small-projects/cpp-voxel-engine/VoxelGame.h
OusmBlueNinja 58962e52fc Broken
2025-04-05 23:20:54 -05:00

118 lines
2.8 KiB
C++

#pragma once
#include <vector>
#include <unordered_map>
#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <algorithm>
#include <random>
#include <GL/glew.h>
#include <glm/glm.hpp>
// world dimensions
static constexpr int CHUNK_SIZE = 16;
static constexpr int CHUNK_HEIGHT = 64;
struct ChunkKey {
int x,z;
bool operator==(ChunkKey const& o) const { return x==o.x && z==o.z; }
};
struct ChunkKeyHash {
std::size_t operator()(ChunkKey const& k) const noexcept {
return std::hash<long long>()(((long long)k.x<<32)|(unsigned)k.z);
}
};
struct Chunk {
int x,z;
// voxels[x][y][z], y ∈ [0,CHUNK_HEIGHT)
std::vector<std::vector<std::vector<int>>> voxels;
};
struct ChunkMesh {
GLuint vao,vbo,ibo;
GLsizei indexCount;
};
struct Vertex {
glm::vec3 pos;
glm::vec3 normal;
glm::vec2 uv;
};
struct RawMesh {
ChunkKey key;
std::vector<Vertex> verts;
std::vector<uint32_t> indices;
};
class VoxelGame {
public:
VoxelGame();
~VoxelGame();
// initialize with screen size (for cascades)
bool init(int screenW,int screenH);
void update(float dt, glm::vec3 const& camPos);
void render(glm::mat4 const& view, glm::mat4 const& proj);
void debugUI();
private:
// chunk generation
Chunk generateChunk(int cx,int cz);
void updateChunks(glm::vec3 const& camPos);
// CPU meshing
void workerLoop();
void greedyMesh(Chunk const&, std::vector<Vertex>&, std::vector<uint32_t>&);
void destroyMesh(ChunkMesh*);
std::unordered_map<ChunkKey,Chunk,ChunkKeyHash> chunks;
std::unordered_map<ChunkKey,std::unique_ptr<ChunkMesh>,ChunkKeyHash> meshes;
std::mutex queueMutex;
std::condition_variable queueCV;
std::queue<ChunkKey> toBuild;
std::queue<RawMesh> readyToUpload;
bool stopWorkers=false;
std::vector<std::thread> workers;
// stats
int totalChunksLoaded=0, totalChunksEverLoaded=0;
int chunkGenCount=0;
double totalChunkGenTime=0, lastChunkGenTime=0;
float fps=0, lastDeltaTime=0;
double frameTimeSum=0; int frameCount=0;
int lastFaceCount=0, lastGLCalls=0;
// textures
GLuint textureDirt, textureGrass, textureWood;
// cascaded shadow maps
static constexpr int NUM_CASCADES = 3;
static constexpr int SHADOW_MAP_SIZE = 1024;
GLuint depthFBO[NUM_CASCADES];
GLuint depthTex[NUM_CASCADES];
float cascadeSplits[NUM_CASCADES];
glm::mat4 lightSpaceMat[NUM_CASCADES];
// shaders
GLuint depthProg, mainProg;
// light & camera
glm::vec3 lightDir = glm::normalize(glm::vec3(1.0f, -1.0f, 0.5f));
glm::vec3 cameraPos;
int screenW, screenH;
int renderDistance = 2;
bool loadTextures();
bool loadShaders();
void initShadowMaps();
void renderScene(GLuint prog);
};