feat: add clamp01 and toByte
This commit is contained in:
1 parent
5af69b7354
commit
4cbd72c75b
1 file changed
+152
@@ -0,0 +1,152 @@
|
|||||||
|
#include "vf/TileTexture.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr float twoPi = 6.28318530718f;
|
||||||
|
|
||||||
|
float clamp01(float v) {
|
||||||
|
if (v < 0.0f) return 0.0f;
|
||||||
|
if (v > 1.0f) return 1.0f;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t toByte(float v) {
|
||||||
|
if (v < 0.0f) return 0;
|
||||||
|
if (v > 255.0f) return 255;
|
||||||
|
return static_cast<uint8_t>(v + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t scramble(uint32_t v) {
|
||||||
|
v ^= v >> 16;
|
||||||
|
v *= 0x7feb352du;
|
||||||
|
v ^= v >> 15;
|
||||||
|
v *= 0x846ca68bu;
|
||||||
|
v ^= v >> 16;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tile id takes part in the hash so two tiles that share a pattern still
|
||||||
|
// get different grain, and the seed is folded in so params.noiseSeed actually
|
||||||
|
// reaches every sample.
|
||||||
|
uint32_t gridHash(int tileSalt, int x, int y, uint32_t salt, uint32_t seed) {
|
||||||
|
uint32_t h = static_cast<uint32_t>(tileSalt) * 374761393u +
|
||||||
|
static_cast<uint32_t>(x) * 668265263u +
|
||||||
|
static_cast<uint32_t>(y) * 2246822519u + salt * 2654435761u + seed;
|
||||||
|
return scramble(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
float gridValue(int tileSalt, int x, int y, uint32_t salt, uint32_t seed) {
|
||||||
|
return static_cast<float>(gridHash(tileSalt, x, y, salt, seed) & 0xffffu) / 65535.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float easeCurve(float t) { return t * t * (3.0f - 2.0f * t); }
|
||||||
|
|
||||||
|
float valueNoise(int tileSalt, float fx, float fy, uint32_t salt, uint32_t seed) {
|
||||||
|
float baseX = std::floor(fx);
|
||||||
|
float baseY = std::floor(fy);
|
||||||
|
int x0 = static_cast<int>(baseX);
|
||||||
|
int y0 = static_cast<int>(baseY);
|
||||||
|
float tx = easeCurve(fx - baseX);
|
||||||
|
float ty = easeCurve(fy - baseY);
|
||||||
|
float corner00 = gridValue(tileSalt, x0, y0, salt, seed);
|
||||||
|
float corner10 = gridValue(tileSalt, x0 + 1, y0, salt, seed);
|
||||||
|
float corner01 = gridValue(tileSalt, x0, y0 + 1, salt, seed);
|
||||||
|
float corner11 = gridValue(tileSalt, x0 + 1, y0 + 1, salt, seed);
|
||||||
|
float top = corner00 + (corner10 - corner00) * tx;
|
||||||
|
float bottom = corner01 + (corner11 - corner01) * tx;
|
||||||
|
return top + (bottom - top) * ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fractalNoise(int tileSalt, float fx, float fy, uint32_t salt, uint32_t seed) {
|
||||||
|
float coarse = valueNoise(tileSalt, fx, fy, salt, seed);
|
||||||
|
float fine = valueNoise(tileSalt, fx * 2.17f + 3.1f, fy * 2.17f - 1.7f, salt + 101u, seed);
|
||||||
|
return coarse * 0.66f + fine * 0.34f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise that varies along one axis only, for grain and for warping band edges.
|
||||||
|
float lineNoise(int tileSalt, float along, uint32_t salt, uint32_t seed) {
|
||||||
|
return valueNoise(tileSalt, along, 0.5f, salt, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TileRgb mixRgb(TileRgb from, TileRgb to, float t) {
|
||||||
|
float k = clamp01(t);
|
||||||
|
TileRgb out;
|
||||||
|
out.r = static_cast<uint8_t>(from.r + (to.r - from.r) * k + 0.5f);
|
||||||
|
out.g = static_cast<uint8_t>(from.g + (to.g - from.g) * k + 0.5f);
|
||||||
|
out.b = static_cast<uint8_t>(from.b + (to.b - from.b) * k + 0.5f);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// What a pattern says about one pixel: how far it moved from base towards
|
||||||
|
// accent, how it is lit, and whether the pattern left a gap there.
|
||||||
|
struct PatternSample {
|
||||||
|
float accentWeight = 0.0f;
|
||||||
|
float shade = 1.0f;
|
||||||
|
bool hole = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
PatternSample solidPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||||
|
uint32_t seed) {
|
||||||
|
float cells = 2.0f + spec.scale * 4.0f;
|
||||||
|
float blob = fractalNoise(tileSalt, x * cells / size, y * cells / size, 11u, seed);
|
||||||
|
PatternSample out;
|
||||||
|
out.accentWeight = clamp01((blob - 0.34f) * 2.0f) * spec.density;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
PatternSample orePattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||||
|
uint32_t seed) {
|
||||||
|
float cells = 6.5f - spec.scale * 3.5f;
|
||||||
|
float blob = fractalNoise(tileSalt, x * cells / size, y * cells / size, 23u, seed);
|
||||||
|
float threshold = 1.0f - spec.density * 1.15f;
|
||||||
|
PatternSample out;
|
||||||
|
if (blob > threshold) {
|
||||||
|
out.accentWeight = clamp01((blob - threshold) * 9.0f);
|
||||||
|
out.shade = 1.0f + 0.10f * out.accentWeight;
|
||||||
|
} else if (blob > threshold - 0.05f) {
|
||||||
|
out.shade = 0.78f;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Courses of brick with mortar between them. Odd rows shift by half a brick;
|
||||||
|
// without that shift the tile reads as a grid and every brick wall in the world
|
||||||
|
// lines its joints up vertically.
|
||||||
|
PatternSample brickPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||||
|
uint32_t seed) {
|
||||||
|
int courseHeight = std::max(2, static_cast<int>(std::lround(size * (0.16f + spec.scale * 0.2f))));
|
||||||
|
int brickWidth = std::max(3, courseHeight * 2);
|
||||||
|
int course = y / courseHeight;
|
||||||
|
int shift = (course % 2 == 0) ? 0 : brickWidth / 2;
|
||||||
|
int localY = y - course * courseHeight;
|
||||||
|
int localX = (x + shift) % brickWidth;
|
||||||
|
|
||||||
|
PatternSample out;
|
||||||
|
if (localY == 0 || localX == 0) {
|
||||||
|
out.accentWeight = 1.0f;
|
||||||
|
out.shade = 0.95f;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
int brickIndex = (x + shift) / brickWidth;
|
||||||
|
out.shade = 0.93f + 0.14f * gridValue(tileSalt, brickIndex, course, 29u, seed);
|
||||||
|
if (localY == 1) out.shade *= 1.05f;
|
||||||
|
if (localY == courseHeight - 1) out.shade *= 0.93f;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boards laid side by side with a seam between them, and grain that runs the
|
||||||
|
// length of the board rather than across it.
|
||||||
|
PatternSample plankPattern(const TileSpec& spec, int tileSalt, int x, int y, int size,
|
||||||
|
uint32_t seed) {
|
||||||
|
int across = spec.vertical ? x : y;
|
||||||
|
int along = spec.vertical ? y : x;
|
||||||
|
int boardWidth =
|
||||||
|
std::max(3, static_cast<int>(std::lround(size * (0.16f + spec.scale * 0.30f))));
|
||||||
|
int board = across / boardWidth;
|
||||||
|
int localAcross = across - board * boardWidth;
|
||||||
|
|
||||||
Reference in new issue
Block a user