diff --git a/tools/editor/cli_gen_texture.cpp b/tools/editor/cli_gen_texture.cpp index 4d9a142c..7d5b785f 100644 --- a/tools/editor/cli_gen_texture.cpp +++ b/tools/editor/cli_gen_texture.cpp @@ -2472,6 +2472,114 @@ int handleRust(int& i, int argc, char** argv) { return 0; } +int handleCircuit(int& i, int argc, char** argv) { + // Sci-fi circuit board: solid PCB background plus N traces + // that walk the surface in orthogonal Manhattan style — each + // trace alternates random horizontal + vertical segments, + // mimicking right-angle PCB routing. Each segment endpoint + // gets a "via" dot (3×3 block) so the routing reads as + // intentional rather than random scribbles. + std::string outPath = argv[++i]; + std::string pcbHex = argv[++i]; + std::string traceHex = argv[++i]; + uint32_t seed = 1; + int traceCount = 24; + int W = 256, H = 256; + if (i + 1 < argc && argv[i + 1][0] != '-') { + try { seed = static_cast(std::stoul(argv[++i])); } catch (...) {} + } + if (i + 1 < argc && argv[i + 1][0] != '-') { + try { traceCount = std::stoi(argv[++i]); } catch (...) {} + } + if (i + 1 < argc && argv[i + 1][0] != '-') { + try { W = std::stoi(argv[++i]); } catch (...) {} + } + if (i + 1 < argc && argv[i + 1][0] != '-') { + try { H = std::stoi(argv[++i]); } catch (...) {} + } + if (W < 1 || H < 1 || W > 8192 || H > 8192 || + traceCount < 0 || traceCount > 1024) { + std::fprintf(stderr, + "gen-texture-circuit: invalid dims (W/H 1..8192, traceCount 0..1024)\n"); + return 1; + } + uint8_t pr, pg, pb, tr, tg, tb; + if (!parseHex(pcbHex, pr, pg, pb)) { + std::fprintf(stderr, + "gen-texture-circuit: '%s' is not a valid hex color\n", + pcbHex.c_str()); + return 1; + } + if (!parseHex(traceHex, tr, tg, tb)) { + std::fprintf(stderr, + "gen-texture-circuit: '%s' is not a valid hex color\n", + traceHex.c_str()); + return 1; + } + uint32_t state = seed ? seed : 1u; + auto next01 = [&state]() -> float { + state = state * 1664525u + 1013904223u; + return (state >> 8) * (1.0f / 16777216.0f); + }; + std::vector pixels(static_cast(W) * H * 3, 0); + // Background fill + for (int p = 0; p < W * H; ++p) { + size_t i2 = static_cast(p) * 3; + pixels[i2 + 0] = pr; + pixels[i2 + 1] = pg; + pixels[i2 + 2] = pb; + } + auto setPx = [&](int x, int y) { + if (x < 0 || y < 0 || x >= W || y >= H) return; + size_t i2 = (static_cast(y) * W + x) * 3; + pixels[i2 + 0] = tr; + pixels[i2 + 1] = tg; + pixels[i2 + 2] = tb; + }; + auto setVia = [&](int x, int y) { + // 3×3 dot for vias / segment joints. + for (int dy = -1; dy <= 1; ++dy) + for (int dx = -1; dx <= 1; ++dx) + setPx(x + dx, y + dy); + }; + int viaCount = 0; + for (int t = 0; t < traceCount; ++t) { + int x = static_cast(next01() * W); + int y = static_cast(next01() * H); + // Each trace runs 3-6 segments + int segs = 3 + static_cast(next01() * 4); + bool horiz = next01() < 0.5f; + for (int s = 0; s < segs; ++s) { + int len = 8 + static_cast(next01() * 24); + int dir = (next01() < 0.5f) ? 1 : -1; + int nx = x, ny = y; + for (int k = 0; k < len; ++k) { + if (horiz) nx += dir; + else ny += dir; + setPx(nx, ny); + } + x = nx; y = ny; + setVia(x, y); // joint at the corner + ++viaCount; + horiz = !horiz; // alternate axis + } + } + if (!stbi_write_png(outPath.c_str(), W, H, 3, + pixels.data(), W * 3)) { + std::fprintf(stderr, + "gen-texture-circuit: 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(" pcb/trace : %s / %s\n", + pcbHex.c_str(), traceHex.c_str()); + std::printf(" traces : %d (~%d vias)\n", traceCount, viaCount); + std::printf(" seed : %u\n", seed); + return 0; +} + } // namespace bool handleGenTexture(int& i, int argc, char** argv, int& outRc) { @@ -2555,6 +2663,9 @@ bool handleGenTexture(int& i, int argc, char** argv, int& outRc) { if (std::strcmp(argv[i], "--gen-texture-rust") == 0 && i + 3 < argc) { outRc = handleRust(i, argc, argv); return true; } + if (std::strcmp(argv[i], "--gen-texture-circuit") == 0 && i + 3 < argc) { + outRc = handleCircuit(i, argc, argv); return true; + } return false; } diff --git a/tools/editor/cli_help.cpp b/tools/editor/cli_help.cpp index f2eae150..c976f2ae 100644 --- a/tools/editor/cli_help.cpp +++ b/tools/editor/cli_help.cpp @@ -87,6 +87,8 @@ void printUsage(const char* argv0) { std::printf(" 3-color mosaic: small square tiles with random color picks + grout (default 16px)\n"); std::printf(" --gen-texture-rust [seed] [coverage] [W H]\n"); std::printf(" Metal with rust patches: noise blob threshold + per-pixel grain (default coverage=0.4)\n"); + std::printf(" --gen-texture-circuit [seed] [traceCount] [W H]\n"); + std::printf(" Sci-fi PCB pattern: orthogonal traces with right-angle turns + via dots (default 24 traces)\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"); diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index c073b167..7d365cb7 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -220,7 +220,7 @@ int main(int argc, char* argv[]) { "--gen-texture-leather", "--gen-texture-sand", "--gen-texture-snow", "--gen-texture-lava", "--gen-texture-tile", "--gen-texture-bark", "--gen-texture-clouds", "--gen-texture-stars", "--gen-texture-vines", - "--gen-texture-mosaic", "--gen-texture-rust", + "--gen-texture-mosaic", "--gen-texture-rust", "--gen-texture-circuit", "--validate-glb", "--info-glb", "--info-glb-tree", "--info-glb-bytes", "--validate-jsondbc", "--check-glb-bounds", "--validate-stl", "--validate-png", "--validate-blp",