From c9892f29d062bc5131586d3f32ae68220b37dfaf Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 13:41:40 -0700 Subject: [PATCH] feat(editor): add --gen-texture-pinwheel sector mandala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 76th procedural texture: N alternating colored triangular wedges radiating from the texture center, each subtending 2π/N radians. Each pixel computes its angle via atan2 and maps to a sector index; even sectors get color A, odd get color B. Distinct from --gen-texture-starburst (thin rays with bg between them) and --gen-texture-swirl (curved spiral arms) — pinwheel uses solid-fill alternating wedges with no bg. Useful for ceiling-decoration medallions, sun-mandala designs, magical-wheel symbols, wind-rose floor inlays, heraldic radial backgrounds, druid-circle ground markings. Default 8 sectors gives the classic pinwheel look; bump to 12-16 for finer subdivisions, or drop to 2-4 for bold quadrant patterns. --- tools/editor/cli_arg_required.cpp | 2 +- tools/editor/cli_gen_texture.cpp | 57 +++++++++++++++++++++++++++++++ tools/editor/cli_help.cpp | 2 ++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/tools/editor/cli_arg_required.cpp b/tools/editor/cli_arg_required.cpp index c9cc697f..f30cb4f2 100644 --- a/tools/editor/cli_arg_required.cpp +++ b/tools/editor/cli_arg_required.cpp @@ -112,7 +112,7 @@ const char* const kArgRequired[] = { "--gen-texture-dunes", "--gen-texture-swirl", "--gen-texture-ironbark", "--gen-texture-mold", "--gen-texture-embroidery", "--gen-texture-lightbeam", - "--gen-texture-dewdrops", + "--gen-texture-dewdrops", "--gen-texture-pinwheel", "--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 f0e52208..e266f2ab 100644 --- a/tools/editor/cli_gen_texture.cpp +++ b/tools/editor/cli_gen_texture.cpp @@ -3500,6 +3500,62 @@ int handleKnit(int& i, int argc, char** argv) { return 0; } +int handlePinwheel(int& i, int argc, char** argv) { + // N-sector pinwheel: alternating colored triangular wedges + // radiating from the texture center, each subtending 2π/N + // radians. Distinct from --gen-texture-starburst (thin rays + // with bg between) and --gen-texture-swirl (spiral arms) — + // pinwheel uses solid wedges with no bg. Useful for ceiling + // decorations, sun-mandala medallions, magical wheels, + // wind-rose floor inlays. + std::string outPath = argv[++i]; + std::string aHex = argv[++i]; + std::string bHex = argv[++i]; + int sectors = 8; + int W = 256, H = 256; + parseOptInt(i, argc, argv, sectors); + parseOptInt(i, argc, argv, W); + parseOptInt(i, argc, argv, H); + if (W < 1 || H < 1 || W > 8192 || H > 8192 || + sectors < 2 || sectors > 256) { + std::fprintf(stderr, + "gen-texture-pinwheel: invalid dims (W/H 1..8192, " + "sectors 2..256)\n"); + return 1; + } + uint8_t ar, ag, ab, br_, bg_, bb_; + if (!parseHexOrError(aHex, ar, ag, ab, + "gen-texture-pinwheel")) return 1; + if (!parseHexOrError(bHex, br_, bg_, bb_, + "gen-texture-pinwheel")) return 1; + std::vector pixels(static_cast(W) * H * 3, 0); + const float twoPi = 6.28318530717958f; + const float cx = W * 0.5f; + const float cy = H * 0.5f; + const float anglePer = twoPi / sectors; + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float dx = x - cx; + float dy = y - cy; + float theta = std::atan2(dy, dx) + 100.0f * twoPi; + int sector = static_cast(std::fmod(theta, twoPi) / anglePer); + uint8_t r, g, b; + if (sector & 1) { + r = br_; g = bg_; b = bb_; + } else { + r = ar; g = ag; b = ab; + } + setPixelRGB(pixels, W, x, y, r, g, b); + } + } + if (!savePngOrError(outPath, W, H, pixels, + "gen-texture-pinwheel")) return 1; + printPngWrote(outPath, W, H); + std::printf(" a / b : %s / %s\n", aHex.c_str(), bHex.c_str()); + std::printf(" sectors : %d\n", sectors); + return 0; +} + int handleDewdrops(int& i, int argc, char** argv) { // Scattered dewdrops / water droplets: N small circles of // hash-derived (position, radius) blended onto bg via radial @@ -5539,6 +5595,7 @@ constexpr TextureEntry kTextureTable[] = { {"--gen-texture-embroidery", 3, handleEmbroidery}, {"--gen-texture-lightbeam", 3, handleLightbeam}, {"--gen-texture-dewdrops", 3, handleDewdrops}, + {"--gen-texture-pinwheel", 3, handlePinwheel}, }; } // namespace diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index 4ee979bb..2955a447 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -185,6 +185,8 @@ void printUsage(const char* argv0) { std::printf(" Lightbeam: vertical sun-ray gradient fading horizontally + vertically (sunbeam / holy radiance)\n"); std::printf(" --gen-texture-dewdrops [dropCount] [maxR] [seed] [W H]\n"); std::printf(" Dewdrops: scattered translucent water drops with radial brightness (grass / glass / leaf surfaces)\n"); + std::printf(" --gen-texture-pinwheel [sectors] [W H]\n"); + std::printf(" Pinwheel: alternating colored triangular wedges radiating from center (mandala / wind-rose / wheel inlay)\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");