diff --git a/render/Atlas.cpp b/render/Atlas.cpp index 3e14e29..eebb82c 100644 --- a/render/Atlas.cpp +++ b/render/Atlas.cpp @@ -1,113 +1,27 @@ #include "Atlas.h" -#include -#include +#include + +#include "vf/TileTexture.h" namespace vf { -namespace { - -struct Rgb { - uint8_t r, g, b; -}; - -// Deterministic per-tile value noise so tiles read as textured, not flat. -float tileNoise(int tile, int x, int y) { - uint32_t h = static_cast(tile) * 374761393u + static_cast(x) * 668265263u + - static_cast(y) * 2246822519u; - h = (h ^ (h >> 13)) * 1274126177u; - h ^= h >> 16; - return static_cast(h & 0xffff) / 65535.0f; -} - -Rgb baseColor(int tile) { - switch (tile) { - case 0: return {86, 154, 66}; // grass top - case 1: return {112, 92, 58}; // grass side (dirt with green lip handled below) - case 2: return {119, 88, 58}; // dirt - case 3: return {129, 129, 132}; // stone - case 4: return {214, 199, 143}; // sand - case 5: return {104, 78, 46}; // wood bark - case 6: return {160, 128, 78}; // wood rings - case 7: return {58, 122, 52}; // leaves - case 8: return {54, 96, 168}; // water - case 9: return {236, 240, 245}; // snow - case 10: return {129, 129, 132}; // coal ore (stone base) - case 11: return {129, 129, 132}; // iron ore (stone base) - case 12: return {129, 129, 132}; // gold ore (stone base) - case 13: return {122, 120, 120}; // gravel - case 14: return {242, 220, 132}; // glowstone - default: return {160, 160, 160}; - } -} - -// Ore tiles carry coloured speckles over the stone base. Returns true and the -// speckle colour when this pixel belongs to a vein. -bool oreSpeckle(int tile, int x, int y, Rgb& out) { - if (tile < 10 || tile > 12) return false; - uint32_t h = static_cast(tile) * 2654435761u + static_cast(x) * 40503u + - static_cast(y) * 12289u; - h ^= h >> 15; - if ((h & 7u) >= 2u) return false; - switch (tile) { - case 10: out = {38, 38, 42}; break; // coal - case 11: out = {196, 156, 120}; break; // iron - default: out = {238, 214, 96}; break; // gold - } - return true; -} - -uint8_t clampByte(float v) { - if (v < 0.0f) return 0; - if (v > 255.0f) return 255; - return static_cast(v + 0.5f); -} - -} // namespace - +// The generator itself lives in core/ so it can be tested without a GL context. +// What is left here is the one thing that genuinely belongs to the renderer: +// laying the tiles out the way glTexImage3D wants to read them. Atlas buildAtlas(int tileSize) { Atlas atlas; atlas.tileSize = tileSize; atlas.layers = tileCount; atlas.pixels.resize(static_cast(tileCount) * tileSize * tileSize * 4); + TileTextureParams params; + params.tileSize = tileSize; + TileSampler sampler(params); + + const std::size_t tileBytes = static_cast(tileSize) * tileSize * 4; for (int tile = 0; tile < tileCount; ++tile) { - Rgb base = baseColor(tile); - for (int y = 0; y < tileSize; ++y) { - for (int x = 0; x < tileSize; ++x) { - float n = tileNoise(tile, x, y) * 0.22f - 0.11f; - float r = base.r * (1.0f + n); - float g = base.g * (1.0f + n); - float b = base.b * (1.0f + n); - - // Grass side: green band across the top few rows. - if (tile == 1 && y < tileSize / 4) { - r = 86 * (1.0f + n); - g = 154 * (1.0f + n); - b = 66 * (1.0f + n); - } - Rgb speck; - if (oreSpeckle(tile, x, y, speck)) { - r = speck.r * (1.0f + n); - g = speck.g * (1.0f + n); - b = speck.b * (1.0f + n); - } - - // Subtle grid so block edges stay legible. - if (x == 0 || y == 0) { - r *= 0.86f; - g *= 0.86f; - b *= 0.86f; - } - - std::size_t idx = - (static_cast(tile) * tileSize * tileSize + y * tileSize + x) * 4; - atlas.pixels[idx + 0] = clampByte(r); - atlas.pixels[idx + 1] = clampByte(g); - atlas.pixels[idx + 2] = clampByte(b); - atlas.pixels[idx + 3] = 255; - } - } + sampler.writeTile(tile, atlas.pixels.data() + tileBytes * static_cast(tile)); } return atlas; } diff --git a/render/Atlas.h b/render/Atlas.h index b26313c..f1e2182 100644 --- a/render/Atlas.h +++ b/render/Atlas.h @@ -8,7 +8,9 @@ namespace vf { // A procedurally generated texture-array atlas: one RGBA tile per layer, // indexed by the tile ids that Block.h assigns to each face. Built in code so -// the demo has no binary asset dependency. +// the demo has no binary asset dependency. The colours and the patterns come +// from vf::TilePalette and are drawn by vf::TileSampler, both in core/ and both +// under test; this header only describes the buffer they are written into. struct Atlas { int tileSize = 16; int layers = tileCount; diff --git a/render/Shaders.h b/render/Shaders.h index de46f28..32c742e 100644 --- a/render/Shaders.h +++ b/render/Shaders.h @@ -47,6 +47,10 @@ uniform vec3 uFogColor; out vec4 fragColor; void main() { vec4 texel = texture(uAtlas, vec3(vUv, float(vTile))); + // Cutout tiles (ladders, rails, grates, plants, cobweb) carry their shape + // in alpha. The opaque pass runs with blending off, so without this the + // holes would draw as solid squares of whatever sits behind them. + if (texel.a < 0.5) discard; float ndl = max(dot(normalize(vNormal), normalize(uLightDir)), 0.0); float directional = 0.55 + 0.45 * ndl; float baked = 0.18 + 0.82 * vLight;