From d053f91f0d504d7feaf3cac554e66bb4a065a8cc Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 14:03:07 -0700 Subject: [PATCH] feat(editor): add --gen-texture-star solid polygon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 79th procedural texture: solid N-pointed star polygon centered on the texture. Each pixel computes its polar (r, θ); the star boundary at any θ alternates between outer and inner radii using a 2π/N triangular-wave pattern (0 at sector edges = points, 1 at sector center = valley). Pixels with r < boundary(θ) are filled with the star color. Distinct from --gen-texture-starburst (thin rays with bg between them) and --gen-texture-pinwheel (alternating solid wedges) — star is a single solid polygon shape. innerFrac controls the star's "sharpness": near 0 gives spike-thin star arms; near 1 approximates a circle. Default 0.40 with 5 points gives the classic American-flag star. The first point is rotated to the top (-Y screen direction) for canonical orientation. Useful for medallion centers, shield emblems, religious / order symbols, magic-circle icons, banner emblems, sheriff- badge inserts. --- tools/editor/cli_arg_required.cpp | 1 + tools/editor/cli_gen_texture.cpp | 73 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 + 3 files changed, 76 insertions(+) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index c307031b..568aae5b 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -117,6 +117,7 @@ const char* const kArgRequired[] = { "--gen-texture-embroidery", "--gen-texture-lightbeam", "--gen-texture-dewdrops", "--gen-texture-pinwheel", "--gen-texture-scratched-metal", "--gen-texture-crackle", + "--gen-texture-star", "--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes", "--validate-jsondbc", "--check-glb-bounds", "--validate-stl", "--validate-png", "--validate-blp", diff --git a/tools/editor/cli_gen_texture.cpp b/tools/editor/cli_gen_texture.cpp index 25743306..b7668e88 100644 --- a/tools/editor/cli_gen_texture.cpp +++ b/tools/editor/cli_gen_texture.cpp @@ -3500,6 +3500,78 @@ int handleKnit(int& i, int argc, char** argv) { return 0; } +int handleStar(int& i, int argc, char** argv) { + // N-pointed star polygon centered on the texture. Each pixel + // computes its polar (r, θ); the star boundary at any θ + // alternates between outer and inner radii using a 2π/N + // saw-pattern. Pixels with r < boundary(θ) are filled with + // the star color. Distinct from --gen-texture-starburst + // (rays only) and --gen-texture-pinwheel (alternating wedges) + // — star is a single solid polygon shape. + std::string outPath = argv[++i]; + std::string bgHex = argv[++i]; + std::string starHex = argv[++i]; + int points = 5; + float innerFrac = 0.40f; // inner radius / outer radius + int W = 256, H = 256; + parseOptInt(i, argc, argv, points); + parseOptFloat(i, argc, argv, innerFrac); + parseOptInt(i, argc, argv, W); + parseOptInt(i, argc, argv, H); + if (W < 1 || H < 1 || W > 8192 || H > 8192 || + points < 3 || points > 32 || + innerFrac <= 0.0f || innerFrac >= 1.0f) { + std::fprintf(stderr, + "gen-texture-star: invalid dims (W/H 1..8192, " + "points 3..32, innerFrac (0,1))\n"); + return 1; + } + uint8_t br_, bg_, bb_, sr, sg, sb_; + if (!parseHexOrError(bgHex, br_, bg_, bb_, "gen-texture-star")) return 1; + if (!parseHexOrError(starHex, sr, sg, sb_, + "gen-texture-star")) return 1; + std::vector pixels(static_cast(W) * H * 3, 0); + const float twoPi = 6.28318530717958f; + const float pi = 3.14159265358979f; + const float cx = W * 0.5f; + const float cy = H * 0.5f; + const float outerR = std::min(cx, cy) * 0.95f; + const float anglePer = twoPi / points; + // Rotate so a point is at the top (-Y in screen coords). + const float pointAngleOffset = -pi * 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); + // Map θ into [0, anglePer); position within determines + // whether we're climbing toward a point (0..0.5 of the + // sector) or descending (0.5..1). + float theta = std::atan2(dy, dx) - pointAngleOffset + + 100.0f * twoPi; + float phase = std::fmod(theta, anglePer) / anglePer; + // Triangular wave: 0 at sector start (point), 1 at + // sector center (valley), 0 at sector end (next point). + float tri = (phase < 0.5f) ? phase * 2.0f + : (1.0f - phase) * 2.0f; + float boundary = outerR * (1.0f - tri * (1.0f - innerFrac)); + uint8_t resR, resG, resB; + if (r < boundary) { + resR = sr; resG = sg; resB = sb_; + } else { + resR = br_; resG = bg_; resB = bb_; + } + setPixelRGB(pixels, W, x, y, resR, resG, resB); + } + } + if (!savePngOrError(outPath, W, H, pixels, "gen-texture-star")) return 1; + printPngWrote(outPath, W, H); + std::printf(" bg/star : %s / %s\n", bgHex.c_str(), starHex.c_str()); + std::printf(" star : %d points, innerFrac=%.2f\n", + points, innerFrac); + return 0; +} + int handleCrackle(int& i, int argc, char** argv) { // Fine crack network from Worley cellular noise. For each // pixel, find the two nearest jittered cell centers; the @@ -5758,6 +5830,7 @@ constexpr TextureEntry kTextureTable[] = { {"--gen-texture-pinwheel", 3, handlePinwheel}, {"--gen-texture-scratched-metal",3, handleScratchedMetal}, {"--gen-texture-crackle", 3, handleCrackle}, + {"--gen-texture-star", 3, handleStar}, }; } // namespace diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index 7a54d6a9..c295deb7 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -191,6 +191,8 @@ void printUsage(const char* argv0) { std::printf(" Scratched metal: base color overlaid with N angled hash-derived line segments (worn armor / blades)\n"); std::printf(" --gen-texture-crackle [stride] [crackW] [seed] [W H]\n"); std::printf(" Crackle: fine Voronoi cell-boundary cracks (dried mud / parched earth / aged leather)\n"); + std::printf(" --gen-texture-star [points] [innerFrac] [W H]\n"); + std::printf(" Star: solid N-pointed star polygon centered (medallions / shields / religious symbols)\n"); std::printf(" --add-texture-to-zone [renameTo]\n"); std::printf(" Copy an existing PNG into (optionally renaming it on the way in)\n"); std::printf(" --gen-mesh [size]\n");