feat: extend TileTexture

This commit is contained in:
dualfroz committed 2026-09-09 20:05:30 +02:00
1 parent cdbcb1e701
commit 35cc9ae4b7
1 file changed
+126
+126
View File
@@ -458,3 +458,129 @@ float materialGrain(const TileSpec& spec, int tileSalt, int x, int y, int size,
float amount = spec.noise; float amount = spec.noise;
if (amount <= 0.0f) return 1.0f; if (amount <= 0.0f) return 1.0f;
float shape = 0.0f;
switch (spec.material) {
case TileMaterial::Stone: {
float speck = gridValue(tileSalt, x, y, 101u, seed) * 2.0f - 1.0f;
float mottle =
fractalNoise(tileSalt, x * 4.0f / size, y * 4.0f / size, 103u, seed) * 2.0f - 1.0f;
shape = speck * 0.70f + mottle * 0.55f;
break;
}
case TileMaterial::Soil: {
float clump =
fractalNoise(tileSalt, x * 5.0f / size, y * 5.0f / size, 107u, seed) * 2.0f - 1.0f;
float crumb = gridValue(tileSalt, x, y, 109u, seed) * 2.0f - 1.0f;
shape = clump * 0.90f + crumb * 0.45f;
break;
}
case TileMaterial::Wood: {
float across = spec.vertical ? static_cast<float>(x) : static_cast<float>(y);
float along = spec.vertical ? static_cast<float>(y) : static_cast<float>(x);
float ring = lineNoise(tileSalt, across * 6.0f / size, 113u, seed) * 2.0f - 1.0f;
float fibre =
valueNoise(tileSalt, along * 3.0f / size, across * 9.0f / size, 127u, seed) * 2.0f -
1.0f;
shape = ring * 0.65f + fibre * 0.55f;
break;
}
case TileMaterial::Foliage: {
float cluster = fractalNoise(tileSalt, x * 6.0f / size, y * 6.0f / size, 131u, seed);
float fleck = gridValue(tileSalt, x, y, 137u, seed) * 2.0f - 1.0f;
shape = (cluster < 0.44f ? -0.95f : 0.40f) + fleck * 0.45f;
break;
}
case TileMaterial::Metal: {
float sheen = std::cos((x + y) * 0.5f / size * twoPi) * 0.85f;
float scratch = gridValue(tileSalt, x, y * 3, 139u, seed) > 0.88f ? -0.95f : 0.0f;
shape = sheen + scratch + (gridValue(tileSalt, x, y, 149u, seed) * 2.0f - 1.0f) * 0.25f;
break;
}
case TileMaterial::Crystal: {
float facet =
valueNoise(tileSalt, (x + y) * 2.5f / size, (x - y) * 2.5f / size, 151u, seed);
shape = (facet - 0.5f) * 2.4f;
break;
}
case TileMaterial::Fabric: {
float weave = ((x / 2) + (y / 2)) % 2 == 0 ? 0.75f : -0.75f;
shape = weave + (gridValue(tileSalt, x, y, 157u, seed) * 2.0f - 1.0f) * 0.40f;
break;
}
case TileMaterial::Fluid: {
float swell = std::sin((y * 2.0f / size + x * 0.35f / size) * twoPi);
shape = swell * 0.80f + (gridValue(tileSalt, x, y, 163u, seed) * 2.0f - 1.0f) * 0.35f;
break;
}
case TileMaterial::Light: {
float half = size * 0.5f;
float dx = (x + 0.5f - half) / half;
float dy = (y + 0.5f - half) / half;
float glow = 1.0f - clamp01(std::sqrt(dx * dx + dy * dy));
shape = glow * 1.7f - 0.65f + (gridValue(tileSalt, x, y, 167u, seed) * 2.0f - 1.0f) * 0.3f;
break;
}
case TileMaterial::Organic: {
float soft = fractalNoise(tileSalt, x * 3.0f / size, y * 3.0f / size, 173u, seed);
float pore = gridValue(tileSalt, x, y, 179u, seed);
shape = (soft - 0.5f) * 1.9f + (pore > 0.92f ? -0.85f : 0.0f);
break;
}
case TileMaterial::Count: break;
}
return std::max(0.0f, 1.0f + amount * shape);
}
} // namespace
TileSampler::TileSampler(const TileTextureParams& params) : settings(params) {}
TileSampler::TileSampler(const TileTextureParams& params, const TilePalette& palette)
: settings(params), table(palette) {}
TilePixel TileSampler::pixelOf(const TileSpec& spec, int tileSalt, int x, int y) const {
int size = settings.tileSize;
PatternSample pattern = samplePattern(spec, tileSalt, x, y, size, settings.noiseSeed);
TileRgb blended = mixRgb(spec.base, spec.accent, pattern.accentWeight);
float brightness = pattern.shade * materialGrain(spec, tileSalt, x, y, size, settings.noiseSeed);
// The old atlas darkened the first row and column so block edges stayed
// legible against each other. Cheap, and every tile still needs it.
if (x == 0 || y == 0) brightness *= 0.86f;
float red = blended.r * brightness;
float green = blended.g * brightness;
float blue = blended.b * brightness;
red = spec.base.r + (red - spec.base.r) * settings.contrast;
green = spec.base.g + (green - spec.base.g) * settings.contrast;
blue = spec.base.b + (blue - spec.base.b) * settings.contrast;
TilePixel out;
out.r = toByte(red);
out.g = toByte(green);
out.b = toByte(blue);
out.a = (spec.cutout && pattern.hole) ? 0 : 255;
return out;
}
TilePixel TileSampler::pixelAt(int tile, int x, int y) const {
return pixelOf(table.specFor(tile), tile, x, y);
}
void TileSampler::writeTile(int tile, uint8_t* rgba) const {
const TileSpec& spec = table.specFor(tile);
int size = settings.tileSize;
for (int y = 0; y < size; ++y) {
for (int x = 0; x < size; ++x) {
TilePixel texel = pixelOf(spec, tile, x, y);
std::size_t offset = (static_cast<std::size_t>(y) * size + x) * 4;
rgba[offset + 0] = texel.r;
rgba[offset + 1] = texel.g;
rgba[offset + 2] = texel.b;
rgba[offset + 3] = texel.a;
}
}
}
} // namespace vf