#pragma once #include #include namespace voxel { // ── Voxel Data (16 bits per voxel, as per spec) ───────────────── // Layout: 8 bits material ID | 4 bits flags | 4 bits metadata struct VoxelData { uint16_t packed = 0; VoxelData() = default; explicit VoxelData(uint8_t materialID, uint8_t flags = 0, uint8_t meta = 0) { packed = (uint16_t(materialID) << 8) | (uint16_t(flags & 0xF) << 4) | (meta & 0xF); } uint8_t getMaterialID() const { return uint8_t(packed >> 8); } uint8_t getFlags() const { return uint8_t((packed >> 4) & 0xF); } uint8_t getMetadata() const { return uint8_t(packed & 0xF); } bool isEmpty() const { return packed == 0; } bool isSmooth() const { return (getFlags() & FLAG_SMOOTH) != 0; } bool isTransparent() const { return (getFlags() & FLAG_TRANSPARENT) != 0; } bool isEmissive() const { return (getFlags() & FLAG_EMISSIVE) != 0; } static constexpr uint8_t FLAG_SMOOTH = 0x1; static constexpr uint8_t FLAG_TRANSPARENT = 0x2; static constexpr uint8_t FLAG_EMISSIVE = 0x4; static constexpr uint8_t FLAG_CUSTOM = 0x8; }; // ── Chunk Constants ───────────────────────────────────────────── static constexpr int CHUNK_SIZE = 32; static constexpr int CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; // ── Packed Vertex for Greedy Mesh Quads (8 bytes per quad) ────── // Layout per spec: // 6 bits posX | 6 bits posY | 6 bits posZ | // 6 bits width | 6 bits height | 3 bits face | // 8 bits materialID | 8 bits AO | 15 bits flags struct PackedQuad { uint64_t data; static PackedQuad create( uint8_t x, uint8_t y, uint8_t z, uint8_t w, uint8_t h, uint8_t face, uint8_t materialID, uint8_t ao = 0, uint16_t flags = 0 ) { PackedQuad q; q.data = (uint64_t(x & 0x3F)) | (uint64_t(y & 0x3F) << 6) | (uint64_t(z & 0x3F) << 12) | (uint64_t(w & 0x3F) << 18) | (uint64_t(h & 0x3F) << 24) | (uint64_t(face & 0x7) << 30) | (uint64_t(materialID) << 33) | (uint64_t(ao) << 41) | (uint64_t(flags & 0x7FFF) << 49); return q; } uint8_t getX() const { return uint8_t(data & 0x3F); } uint8_t getY() const { return uint8_t((data >> 6) & 0x3F); } uint8_t getZ() const { return uint8_t((data >> 12) & 0x3F); } uint8_t getWidth() const { return uint8_t((data >> 18) & 0x3F); } uint8_t getHeight() const { return uint8_t((data >> 24) & 0x3F); } uint8_t getFace() const { return uint8_t((data >> 30) & 0x7); } uint8_t getMaterialID() const { return uint8_t((data >> 33) & 0xFF); } uint8_t getAO() const { return uint8_t((data >> 41) & 0xFF); } uint16_t getFlags() const { return uint16_t((data >> 49) & 0x7FFF); } }; // Face directions: +X, -X, +Y, -Y, +Z, -Z enum Face : uint8_t { FACE_POS_X = 0, FACE_NEG_X = 1, FACE_POS_Y = 2, FACE_NEG_Y = 3, FACE_POS_Z = 4, FACE_NEG_Z = 5, FACE_COUNT = 6 }; // ── Material Descriptor ───────────────────────────────────────── struct MaterialDesc { uint16_t albedoTextureIndex = 0; uint16_t normalTextureIndex = 0; uint16_t heightmapTextureIndex = 0; uint8_t roughness = 128; // 0-255 mapped to 0.0-1.0 uint8_t metallic = 0; uint8_t flags = 0; // triplanar, blend mode, etc. uint8_t _pad = 0; static constexpr uint8_t FLAG_TRIPLANAR = 0x1; }; // ── Chunk Position Hash ───────────────────────────────────────── struct ChunkPos { int32_t x, y, z; bool operator==(const ChunkPos& other) const { return x == other.x && y == other.y && z == other.z; } }; struct ChunkPosHash { size_t operator()(const ChunkPos& p) const { // FNV-1a inspired hash size_t h = 0x811c9dc5; h ^= size_t(p.x); h *= 0x01000193; h ^= size_t(p.y); h *= 0x01000193; h ^= size_t(p.z); h *= 0x01000193; return h; } }; } // namespace voxel