diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index b04aca05..5d989141 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -505,7 +505,22 @@ void EditorUI::renderBrushPanel(EditorApp& app) { ImGui::InputInt("Seed", &noiseSeed); ImGui::SameLine(); if (ImGui::SmallButton("Random##seed")) noiseSeed = static_cast(std::rand()); - if (ImGui::Button("Apply Noise", ImVec2(140, 0))) { + static int noiseType = 0; + ImGui::RadioButton("Value##nt", &noiseType, 0); + ImGui::SameLine(); + ImGui::RadioButton("Voronoi##nt", &noiseType, 1); + + if (noiseType == 1) { + static int voronoiCells = 20; + ImGui::SliderInt("Cells##vor", &voronoiCells, 5, 100); + if (ImGui::Button("Apply Voronoi", ImVec2(-1, 0))) { + app.getTerrainEditor().applyVoronoiNoise(voronoiCells, noiseAmp, + static_cast(noiseSeed)); + app.showToast("Voronoi noise applied"); + } + } + + if (noiseType == 0 && ImGui::Button("Apply Noise", ImVec2(140, 0))) { app.getTerrainEditor().applyNoise(noiseFreq, noiseAmp, noiseOctaves, static_cast(noiseSeed)); app.showToast("Noise applied"); diff --git a/tools/editor/terrain_editor.cpp b/tools/editor/terrain_editor.cpp index bd9f64a7..316c7f5d 100644 --- a/tools/editor/terrain_editor.cpp +++ b/tools/editor/terrain_editor.cpp @@ -860,6 +860,46 @@ void TerrainEditor::createHill(const glm::vec3& center, float radius, float heig dirty_ = true; } +void TerrainEditor::applyVoronoiNoise(int cellCount, float amplitude, uint32_t seed) { + if (!terrain_) return; + + float tileNW_X = (32.0f - static_cast(terrain_->coord.y)) * TILE_SIZE; + float tileNW_Y = (32.0f - static_cast(terrain_->coord.x)) * TILE_SIZE; + + // Generate random cell centers + std::mt19937 rng(seed); + std::uniform_real_distribution distX(tileNW_X - TILE_SIZE, tileNW_X); + std::uniform_real_distribution distY(tileNW_Y - TILE_SIZE, tileNW_Y); + std::uniform_real_distribution distH(0.0f, amplitude); + + struct Cell { float x, y, h; }; + std::vector cells(cellCount); + for (auto& c : cells) { c.x = distX(rng); c.y = distY(rng); c.h = distH(rng); } + + for (int ci = 0; ci < 256; ci++) { + auto& chunk = terrain_->chunks[ci]; + if (!chunk.hasHeightMap()) continue; + for (int v = 0; v < 145; v++) { + glm::vec3 pos = chunkVertexWorldPos(ci, v); + // Find nearest two cells + float d1 = 1e30f, d2 = 1e30f; + float h1 = 0; + for (const auto& c : cells) { + float d = (pos.x - c.x) * (pos.x - c.x) + (pos.y - c.y) * (pos.y - c.y); + if (d < d1) { d2 = d1; d1 = d; h1 = c.h; } + else if (d < d2) { d2 = d; } + } + // F2-F1 creates ridge patterns at cell boundaries + float edge = std::sqrt(d2) - std::sqrt(d1); + float edgeNorm = std::min(edge / 30.0f, 1.0f); + chunk.heightMap.heights[v] += h1 * (1.0f - edgeNorm * 0.5f); + } + dirtyChunks_.push_back(ci); + } + for (int ci = 0; ci < 256; ci++) stitchEdges(ci); + dirty_ = true; +} + void TerrainEditor::offsetHeights(float amount) { if (!terrain_) return; for (int ci = 0; ci < 256; ci++) { diff --git a/tools/editor/terrain_editor.hpp b/tools/editor/terrain_editor.hpp index 16f8f148..50e5cfcf 100644 --- a/tools/editor/terrain_editor.hpp +++ b/tools/editor/terrain_editor.hpp @@ -111,6 +111,9 @@ public: // Offset all heights by a constant void offsetHeights(float amount); + // Voronoi cell noise — creates cell-like terrain patterns + void applyVoronoiNoise(int cellCount, float amplitude, uint32_t seed); + // Fill entire tile with water at a height void fillWater(float height, uint16_t liquidType);