mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-10 19:13:52 +00:00
feat(editor): add --gen-texture-woodgrain end-cut tree-rings
56th procedural texture: concentric annual growth rings centered slightly off-image (at -W*0.2, H/2) so the texture shows sweeping arcs across most of its area rather than the bullseye --gen-texture-rings produces. Per-ring jitter shifts the dark-band center within each ring's annular cell, so adjacent rings don't read as a perfect modulus pattern — mimics real annual-growth variation. Brightness lerps from lightHex (early-wood) to darkHex (late-wood / heartwood) with a smooth triangular falloff at the dark-band peak. First procedural texture to use the new cli_arg_parse helpers for the optional spacing/seed/W/H args. Useful for tabletops, log-end caps (chopped firewood stumps), barrel lids, beam cross-sections, plank ends — distinct from --gen-texture-wood which renders vertical grain streaks for plank surfaces.
This commit is contained in:
parent
56c12bc252
commit
7f7104623d
3 changed files with 87 additions and 1 deletions
|
|
@ -88,7 +88,7 @@ const char* const kArgRequired[] = {
|
|||
"--gen-texture-planks", "--gen-texture-corrugated",
|
||||
"--gen-texture-rope", "--gen-texture-caustics",
|
||||
"--gen-texture-starburst", "--gen-texture-studs",
|
||||
"--gen-texture-moss",
|
||||
"--gen-texture-moss", "--gen-texture-woodgrain",
|
||||
"--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes",
|
||||
"--validate-jsondbc", "--check-glb-bounds", "--validate-stl",
|
||||
"--validate-png", "--validate-blp",
|
||||
|
|
|
|||
|
|
@ -4235,6 +4235,89 @@ int handleKnit(int& i, int argc, char** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int handleWoodgrain(int& i, int argc, char** argv) {
|
||||
// Wood-end grain: concentric annual rings centered slightly
|
||||
// outside the image (so the texture shows arcs sweeping across
|
||||
// it, not a bullseye like --gen-texture-rings). Ring spacing
|
||||
// and per-ring darkness are jittered per ring index so
|
||||
// adjacent rings don't read as a perfect modulus, mimicking
|
||||
// real annual growth variation. Useful for tabletops, log-
|
||||
// end caps, barrel lids, beam cross-sections.
|
||||
std::string outPath = argv[++i];
|
||||
std::string lightHex = argv[++i];
|
||||
std::string darkHex = argv[++i];
|
||||
int spacing = 14;
|
||||
uint32_t seed = 1;
|
||||
int W = 256, H = 256;
|
||||
parseOptInt(i, argc, argv, spacing);
|
||||
parseOptUint(i, argc, argv, seed);
|
||||
parseOptInt(i, argc, argv, W);
|
||||
parseOptInt(i, argc, argv, H);
|
||||
if (W < 1 || H < 1 || W > 8192 || H > 8192 ||
|
||||
spacing < 2 || spacing > 1024) {
|
||||
std::fprintf(stderr,
|
||||
"gen-texture-woodgrain: invalid dims (W/H 1..8192, "
|
||||
"spacing 2..1024)\n");
|
||||
return 1;
|
||||
}
|
||||
uint8_t lr, lg, lb, dr, dg, db;
|
||||
if (!parseHex(lightHex, lr, lg, lb) ||
|
||||
!parseHex(darkHex, dr, dg, db)) {
|
||||
std::fprintf(stderr,
|
||||
"gen-texture-woodgrain: hex color is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
auto hash32 = [](uint32_t x) -> uint32_t {
|
||||
x ^= x >> 16; x *= 0x7feb352d;
|
||||
x ^= x >> 15; x *= 0x846ca68b;
|
||||
x ^= x >> 16; return x;
|
||||
};
|
||||
std::vector<uint8_t> pixels(static_cast<size_t>(W) * H * 3, 0);
|
||||
// Center the rings off the upper-left corner so the texture
|
||||
// shows sweeping arcs across most of its area. Distance from
|
||||
// (cx, cy) determines the ring index.
|
||||
const float cx = -W * 0.2f;
|
||||
const float cy = H * 0.5f;
|
||||
for (int y = 0; y < H; ++y) {
|
||||
for (int x = 0; x < W; ++x) {
|
||||
float dx = x - cx;
|
||||
float dy = y - cy;
|
||||
float r = std::sqrt(dx * dx + dy * dy);
|
||||
// Ring index + position within the ring [0, 1).
|
||||
float ringF = r / spacing;
|
||||
int ringIdx = static_cast<int>(ringF);
|
||||
float frac = ringF - ringIdx;
|
||||
// Per-ring jitter on darkness peak position (so dark
|
||||
// rings don't repeat at exact intervals).
|
||||
float jitter = ((hash32(ringIdx + seed) % 1000) / 1000.0f) - 0.5f;
|
||||
// Dark ring is a thin band centered at frac=0.5+jitter
|
||||
// with width 0.18. Brightness = 1.0 (light) outside,
|
||||
// dropping to 0.0 (full dark color) at the band center.
|
||||
float dist = std::abs(frac - (0.5f + jitter * 0.4f));
|
||||
float t = std::max(0.0f, 1.0f - dist / 0.18f);
|
||||
uint8_t r8 = static_cast<uint8_t>(lr + t * (dr - lr));
|
||||
uint8_t g8 = static_cast<uint8_t>(lg + t * (dg - lg));
|
||||
uint8_t b8 = static_cast<uint8_t>(lb + t * (db - lb));
|
||||
size_t idx = (static_cast<size_t>(y) * W + x) * 3;
|
||||
pixels[idx + 0] = r8;
|
||||
pixels[idx + 1] = g8;
|
||||
pixels[idx + 2] = b8;
|
||||
}
|
||||
}
|
||||
if (!stbi_write_png(outPath.c_str(), W, H, 3,
|
||||
pixels.data(), W * 3)) {
|
||||
std::fprintf(stderr,
|
||||
"gen-texture-woodgrain: stbi_write_png failed for %s\n",
|
||||
outPath.c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("Wrote %s\n", outPath.c_str());
|
||||
std::printf(" size : %dx%d\n", W, H);
|
||||
std::printf(" light/dark : %s / %s\n", lightHex.c_str(), darkHex.c_str());
|
||||
std::printf(" rings : spacing=%d, seed=%u\n", spacing, seed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handleMoss(int& i, int argc, char** argv) {
|
||||
// Moss: irregular spots scattered on a jittered grid. Each
|
||||
// grid cell has a hashed (x, y, presence, radius) so the
|
||||
|
|
@ -4974,6 +5057,7 @@ constexpr TextureEntry kTextureTable[] = {
|
|||
{"--gen-texture-starburst", 3, handleStarburst},
|
||||
{"--gen-texture-studs", 3, handleStuds},
|
||||
{"--gen-texture-moss", 3, handleMoss},
|
||||
{"--gen-texture-woodgrain", 3, handleWoodgrain},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ void printUsage(const char* argv0) {
|
|||
std::printf(" Studs: rivet grid with derived inner highlight (3D rivet/stud appearance for armor + leather)\n");
|
||||
std::printf(" --gen-texture-moss <out.png> <bgHex> <mossHex> [stride] [density 0-100] [seed] [W H]\n");
|
||||
std::printf(" Moss: irregular spots scattered on a hash-jittered grid (forest floor / weathered stone / swamp)\n");
|
||||
std::printf(" --gen-texture-woodgrain <out.png> <lightHex> <darkHex> [spacing] [seed] [W H]\n");
|
||||
std::printf(" Woodgrain: concentric annual rings centered off-image with per-ring jitter (end-cut wood)\n");
|
||||
std::printf(" --add-texture-to-zone <zoneDir> <png-path> [renameTo]\n");
|
||||
std::printf(" Copy an existing PNG into <zoneDir> (optionally renaming it on the way in)\n");
|
||||
std::printf(" --gen-mesh <wom-base> <cube|plane|sphere|cylinder|torus|cone|ramp> [size]\n");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue