From b00143e8f7c2ab6fb06e6492e91b6616e1787848 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 5 May 2026 08:40:43 -0700 Subject: [PATCH] feat(editor): scatter texture patches for natural surface variety - Scatter Patches: randomly places texture circles across the terrain for natural-looking surface variation (dirt patches, rock outcrops) - Configurable count, min/max radius, and seed - Preset buttons for dirt and rock patches - Uses the existing paint() method with random positions - Adds visual variety to otherwise uniform terrain texturing --- tools/editor/editor_ui.cpp | 22 ++++++++++++++++++++++ tools/editor/texture_painter.cpp | 20 ++++++++++++++++++++ tools/editor/texture_painter.hpp | 4 ++++ 3 files changed, 46 insertions(+) diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index 93554fb9..0a7ac3c4 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -904,6 +904,28 @@ void EditorUI::renderTexturePaintPanel(EditorApp& app) { selectedTexture_.c_str()); // Auto-paint by height + if (ImGui::CollapsingHeader("Scatter Patches")) { + static int patchCount = 15; + static float patchMinR = 10.0f, patchMaxR = 30.0f; + static int patchSeed = 55; + ImGui::SliderInt("Count##patches", &patchCount, 5, 50); + ImGui::DragFloatRange2("Radius##patches", &patchMinR, &patchMaxR, 1.0f, 5.0f, 80.0f); + ImGui::InputInt("Seed##patches", &patchSeed); + if (ImGui::Button("Scatter Dirt Patches", ImVec2(-1, 0))) { + app.getTexturePainter().scatterPatches( + "Tileset\\Elwynn\\ElwynnDirtBase.blp", patchCount, patchMinR, patchMaxR, + static_cast(patchSeed)); + app.showToast("Patches scattered"); + } + if (ImGui::Button("Scatter Rock Patches", ImVec2(-1, 0))) { + app.getTexturePainter().scatterPatches( + "Tileset\\Barrens\\BarrensRock01.blp", patchCount, patchMinR, patchMaxR, + static_cast(patchSeed + 1)); + app.showToast("Patches scattered"); + } + ImGui::TextColored(ImVec4(0.6f,0.6f,0.6f,1), "Random texture patches for variety"); + } + if (ImGui::CollapsingHeader("Gradient Blend")) { static int gradDir = 0; ImGui::RadioButton("Horizontal##grad", &gradDir, 0); diff --git a/tools/editor/texture_painter.cpp b/tools/editor/texture_painter.cpp index 4d88c7c1..4f2e22f3 100644 --- a/tools/editor/texture_painter.cpp +++ b/tools/editor/texture_painter.cpp @@ -2,6 +2,7 @@ #include "core/logger.hpp" #include #include +#include namespace wowee { namespace editor { @@ -321,6 +322,25 @@ void TexturePainter::gradientBlend(const std::string& tex1, const std::string& t } } +void TexturePainter::scatterPatches(const std::string& texturePath, int count, + float minRadius, float maxRadius, uint32_t seed) { + if (!terrain_ || texturePath.empty()) return; + uint32_t texId = ensureTextureInList(texturePath); + + float tileNW_X = (32.0f - static_cast(terrain_->coord.y)) * 533.33333f; + float tileNW_Y = (32.0f - static_cast(terrain_->coord.x)) * 533.33333f; + + std::mt19937 rng(seed); + std::uniform_real_distribution distX(tileNW_X - 533.33333f, tileNW_X); + std::uniform_real_distribution distY(tileNW_Y - 533.33333f, tileNW_Y); + std::uniform_real_distribution distR(minRadius, maxRadius); + + for (int p = 0; p < count; p++) { + float px = distX(rng), py = distY(rng), pr = distR(rng); + paint(glm::vec3(px, py, 0), pr, 0.8f, 0.5f); + } +} + std::vector TexturePainter::erase(const glm::vec3& center, float radius, float strength, float falloff) { if (!terrain_ || activeTexture_.empty()) return {}; diff --git a/tools/editor/texture_painter.hpp b/tools/editor/texture_painter.hpp index d5a07f08..236e2457 100644 --- a/tools/editor/texture_painter.hpp +++ b/tools/editor/texture_painter.hpp @@ -31,6 +31,10 @@ public: // Gradient blend: transitions base texture from one to another across tile void gradientBlend(const std::string& tex1, const std::string& tex2, bool horizontal); + // Scatter random texture patches across the terrain + void scatterPatches(const std::string& texturePath, int count, float minRadius, + float maxRadius, uint32_t seed); + // Paint the active texture at the given world position // Returns list of modified chunk indices std::vector paint(const glm::vec3& center, float radius, float strength, float falloff);