Chunk
10×10×10 block sub-volume with palette-compressed bit-packing.
Overview
Chunk stores 1 000 block values in a compact palette + bit-packed index format.
It is the storage unit inside World — each world holds 10³ = 1 000 chunks.
Engine-agnostic; no Urho3D headers.
Header: include/GalaxyEggbert/Worlds/Chunk.hpp. Implementation: src/GalaxyEggbert/Worlds/Chunk.cpp.
Constants
static constexpr int Size = 10; // blocks per axis
static constexpr int Volume = 1000; // Size³
Internal Storage Layout
private:
std::vector<Block> palette_; // unique block values (≤256)
std::vector<uint8_t> packedIndices_; // bit-packed palette indices
std::vector<uint8_t> extraMetadata_; // reserved for future use
uint8_t bitsPerBlock_; // ceil(log2(palette_.size()))
bool dirty_; // set by setBlock, cleared on serialise
When the palette has 1 entry (uniform chunk), packedIndices_ may be empty.
bitsPerBlock_ is recomputed whenever the palette grows.
API
namespace GalaxyEggbert::Worlds {
class Chunk {
public:
// Factory helpers
static Chunk createUniform(Block fillBlock);
static Chunk fromBlocks(const std::array<Block, Volume>& blocks);
Block getBlock(uint8_t lx, uint8_t ly, uint8_t lz) const;
void setBlock(uint8_t lx, uint8_t ly, uint8_t lz, Block block);
// Unpack all 1 000 blocks into a flat array (for terrain meshing)
std::array<Block, Volume> unpackBlocks() const;
bool isEmpty() const; // all blocks == Air
bool isUniform() const; // palette_.size() == 1
bool isDirty() const; // modified since last write()
// Serialisation (called by World::saveToFile / loadFromFile)
void write(std::ostream& os) const;
void read (std::istream& is);
};
Bit-packing Details
Block indices into the palette are stored consecutively in packedIndices_.
Each index occupies exactly bitsPerBlock_ bits.
Indices are packed little-endian within each byte.
| Palette size | Bits per block | Bytes for 1000 blocks |
|---|---|---|
| 1 (uniform) | 0 | 0 (packedIndices_ empty) |
| 2 | 1 | 125 |
| 3–4 | 2 | 250 |
| 5–8 | 3 | 375 |
| 9–16 | 4 | 500 |
| 17–32 | 5 | 625 |
| 33–64 | 6 | 750 |
| 65–128 | 7 | 875 |
| 129–256 | 8 | 1000 |
Coordinate Mapping
Local indices lx, ly, lz ∈ [0, 9]. Flat index: lx + ly*10 + lz*100.
World-to-local: lx = worldX % 10. Chunk coordinate: cx = worldX / 10.
Serialisation
write() emits the VCH1 chunk payload as described in
VWR Format:
palette count, palette entries, packed index data, and optional BMD1 metadata section.
Tests
Covered by tests/GalaxyEggbert/Worlds/ChunkTests.cpp:
uniform create, palette growth, bit-pack round-trip, isEmpty/isUniform, dirty flag,
write/read round-trip.