feat: add liquidPattern and crossPattern to TileTexture
This commit is contained in:
1 parent
1063442547
commit
cdbcb1e701
1 file changed
+146
@@ -312,3 +312,149 @@ PatternSample splatterPattern(const TileSpec& spec, int tileSalt, int x, int y,
|
||||
return out;
|
||||
}
|
||||
|
||||
// Travelling crests with ripple on top. When the spec is a cutout the troughs
|
||||
// open right through, which is how a portal reads as a hole in the world.
|
||||
PatternSample liquidPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||
uint32_t seed) {
|
||||
float drift = lineNoise(tileSalt, x * 2.0f / size, 71u, seed);
|
||||
float crest = std::sin((y * (1.5f + spec.scale * 2.5f) / size + drift * 0.7f) * twoPi);
|
||||
float ripple = fractalNoise(tileSalt, x * 3.0f / size, y * 3.0f / size, 73u, seed);
|
||||
|
||||
PatternSample out;
|
||||
out.accentWeight = clamp01((0.5f + 0.5f * crest) * spec.density * (0.55f + 0.7f * ripple));
|
||||
out.shade = 0.95f + 0.12f * ripple;
|
||||
out.hole = out.accentWeight < 0.16f && ripple < 0.50f;
|
||||
return out;
|
||||
}
|
||||
|
||||
// A plant sprite: a wandering stalk with leaves hung off it, everything else
|
||||
// cut away. Without the vertical flag it becomes the flat cross a dust line or
|
||||
// a tripwire draws on the ground.
|
||||
PatternSample crossPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||
uint32_t seed) {
|
||||
float centre = (size - 1) * 0.5f;
|
||||
PatternSample out;
|
||||
|
||||
if (!spec.vertical) {
|
||||
float armHalf = std::max(0.6f, size * (0.05f + spec.scale * 0.09f));
|
||||
float dx = std::fabs(x - centre);
|
||||
float dy = std::fabs(y - centre);
|
||||
if (dx <= armHalf || dy <= armHalf) {
|
||||
float edge = std::min(dx, dy) / std::max(1.0f, armHalf);
|
||||
out.accentWeight = clamp01(1.0f - edge) * spec.density;
|
||||
out.shade = 0.92f + 0.16f * gridValue(tileSalt, x, y, 79u, seed);
|
||||
return out;
|
||||
}
|
||||
out.hole = true;
|
||||
out.shade = 0.34f;
|
||||
return out;
|
||||
}
|
||||
|
||||
float sway = (lineNoise(tileSalt, y * 3.0f / size, 79u, seed) - 0.5f) * size * 0.16f;
|
||||
float stalkHalf = std::max(0.6f, size * (0.05f + spec.scale * 0.07f));
|
||||
float dx = std::fabs(x - centre - sway);
|
||||
if (dx <= stalkHalf) {
|
||||
// The top of a stalk is its head: the flame on a torch, the ear on
|
||||
// wheat, the bud on a sapling. It carries the accent, the stem does not.
|
||||
float headDepth = size * 0.30f;
|
||||
out.accentWeight = clamp01((headDepth - y) / headDepth);
|
||||
out.shade = 1.02f - 0.22f * (dx / std::max(1.0f, stalkHalf));
|
||||
return out;
|
||||
}
|
||||
|
||||
float leafField = fractalNoise(tileSalt, x * 4.0f / size, y * 4.0f / size, 83u, seed);
|
||||
float reach = stalkHalf + size * (0.10f + spec.density * 0.24f) * leafField;
|
||||
if (dx <= reach && leafField > 0.42f) {
|
||||
out.accentWeight = 1.0f;
|
||||
out.shade = 0.90f + 0.20f * leafField;
|
||||
return out;
|
||||
}
|
||||
out.hole = true;
|
||||
out.shade = 0.34f;
|
||||
return out;
|
||||
}
|
||||
|
||||
PatternSample webPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||
uint32_t seed) {
|
||||
float centre = (size - 1) * 0.5f;
|
||||
float dx = x - centre;
|
||||
float dy = y - centre;
|
||||
float pixels = std::sqrt(dx * dx + dy * dy);
|
||||
float radius = pixels / (size * 0.5f);
|
||||
float spokes = 8.0f;
|
||||
float angle = std::atan2(dy, dx) / twoPi + 0.5f;
|
||||
float spokePhase = angle * spokes;
|
||||
float spokeOffset = std::fabs(spokePhase - std::floor(spokePhase + 0.5f));
|
||||
float spokeDistance = spokeOffset * (twoPi / spokes) * pixels;
|
||||
|
||||
PatternSample out;
|
||||
float rings = 2.0f + spec.scale * 4.0f;
|
||||
float ringPhase = radius * rings;
|
||||
float ringOffset = std::fabs(ringPhase - std::floor(ringPhase + 0.5f));
|
||||
float ringDistance = ringOffset * (size * 0.5f) / rings;
|
||||
|
||||
bool onSpoke = spokeDistance < 0.60f && radius <= 1.02f;
|
||||
bool onRing = ringDistance < 0.45f && radius <= 0.98f;
|
||||
if (onSpoke || onRing) {
|
||||
out.accentWeight = onRing && !onSpoke ? 1.0f : 0.0f;
|
||||
out.shade = 0.92f + 0.16f * gridValue(tileSalt, x, y, 89u, seed);
|
||||
return out;
|
||||
}
|
||||
out.hole = true;
|
||||
out.shade = 0.30f;
|
||||
return out;
|
||||
}
|
||||
|
||||
PatternSample panePattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||
uint32_t seed) {
|
||||
int border = std::max(1, static_cast<int>(std::lround(size * (0.04f + spec.scale * 0.06f))));
|
||||
bool onFrame = x < border || y < border || x >= size - border || y >= size - border;
|
||||
bool onCorner = (x < border * 3 && y < border * 3) ||
|
||||
(x >= size - border * 3 && y >= size - border * 3);
|
||||
|
||||
PatternSample out;
|
||||
if (onFrame || onCorner) {
|
||||
out.accentWeight = onCorner && !onFrame ? 1.0f : 0.0f;
|
||||
out.shade = 0.94f + 0.12f * gridValue(tileSalt, x, y, 97u, seed);
|
||||
return out;
|
||||
}
|
||||
int quarter = std::max(2, size / 4);
|
||||
if (x - y == quarter || y - x == quarter) {
|
||||
out.accentWeight = spec.density;
|
||||
out.shade = 1.10f;
|
||||
return out;
|
||||
}
|
||||
out.hole = true;
|
||||
out.shade = 0.55f;
|
||||
return out;
|
||||
}
|
||||
|
||||
PatternSample samplePattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||
uint32_t seed) {
|
||||
switch (spec.pattern) {
|
||||
case TilePattern::Solid: return solidPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::OreSpeckle: return orePattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Brick: return brickPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Plank: return plankPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Lattice: return latticePattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::EdgeBand: return edgeBandPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::GrowthRings: return growthRingsPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Dots: return dotsPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Strata: return strataPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Splatter: return splatterPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Liquid: return liquidPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Cross: return crossPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Web: return webPattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Pane: return panePattern(spec, tileSalt, x, y, size, seed);
|
||||
case TilePattern::Count: break;
|
||||
}
|
||||
return PatternSample{};
|
||||
}
|
||||
|
||||
// The grain the material lays over the pattern, as a brightness multiplier.
|
||||
// Its amplitude is the spec's noise, so a tile with no noise has no grain at
|
||||
// all and shows exactly what its pattern drew.
|
||||
float materialGrain(const TileSpec& spec, int tileSalt, int x, int y, int size, uint32_t seed) {
|
||||
float amount = spec.noise;
|
||||
if (amount <= 0.0f) return 1.0f;
|
||||
|
||||
Reference in new issue
Block a user