#ifndef CHUNK_H #define CHUNK_H #include #include #include #include #include #include #include #include "Mesh.h" enum class VoxelKind : uint8_t { Air, Dirt, Stone }; const int CHUNK_SIZE = 32; // Hash function for glm::ivec3 to use with unordered_set // Still used in World.h namespace std { template <> struct hash { size_t operator()(const glm::ivec3& v) const { // Combine hash values of x, y, z components size_t h1 = hash()(v.x); size_t h2 = hash()(v.y); size_t h3 = hash()(v.z); // Use a simple hash combination algorithm return h1 ^ (h2 << 1) ^ (h3 << 2); } }; } class Chunk { public: Chunk(); Mesh* getMesh(); // Returns pointer, can be null if not generated yet void generateMesh(); void regenerateMesh(); // Accessors inline VoxelKind get(int x, int y, int z) const { return data[index(x, y, z)]; } inline VoxelKind get(glm::ivec3 pos) const { // std::cout << "Getting Pos (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl; return data[index(pos.x, pos.y, pos.z)]; } // Mutators inline void set(int x, int y, int z, VoxelKind v) { data[index(x, y, z)] = v; empty_checked = false; // Invalidate cache } inline void set(glm::ivec3 pos, VoxelKind v) { // std::cout << "Setting Pos (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl; data[index(pos.x, pos.y, pos.z)] = v; empty_checked = false; // Invalidate cache } // Other inline bool isEmpty() const { if (!empty_checked) { is_empty = std::all_of(data.begin(), data.end(), [](VoxelKind k){ return k == VoxelKind::Air; }); empty_checked = true; } return is_empty; } private: static constexpr int SIZE = CHUNK_SIZE; static constexpr int TOTAL = SIZE * SIZE * SIZE; std::array data; std::unique_ptr mesh; // Nullable mesh mutable bool is_empty = true; // Cache empty state mutable bool empty_checked = false; // Track if we've checked static inline constexpr int index(int x, int y, int z) noexcept { return x + (y * SIZE) + (z * SIZE * SIZE); } }; #endif // CHUNK_H