#pragma once #include #include #include #include #include #include #include #include #include #include #include // 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)k.x<<32)|(unsigned)k.z); } }; struct Chunk { int x,z; // voxels[x][y][z], y ∈ [0,CHUNK_HEIGHT) std::vector>> 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 verts; std::vector 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&, std::vector&); void destroyMesh(ChunkMesh*); std::unordered_map chunks; std::unordered_map,ChunkKeyHash> meshes; std::mutex queueMutex; std::condition_variable queueCV; std::queue toBuild; std::queue readyToUpload; bool stopWorkers=false; std::vector 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); };