From 426863f19a2ac3a7961595cbbeff0d6d3d7f23a7 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 5 May 2026 08:06:20 -0700 Subject: [PATCH] feat(editor): smooth beaches tool for natural water-land transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Smooth Beaches button in Water panel: creates gentle beach slopes near water level by blending terrain toward waterline height - Configurable beach width (15 units default) - Quadratic falloff creates natural concave beach profile - Use after filling water to soften harsh land-water edges - Workflow: sculpt → fill water → smooth beaches → paint sand --- tools/editor/editor_ui.cpp | 4 ++++ tools/editor/terrain_editor.cpp | 23 +++++++++++++++++++++++ tools/editor/terrain_editor.hpp | 3 +++ 3 files changed, 30 insertions(+) diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index 7b1428f9..f7a48a1d 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -1513,6 +1513,10 @@ void EditorUI::renderWaterPanel(EditorApp& app) { app.getTerrainEditor().removeWater(brush.getPosition(), s.radius); } } + if (ImGui::Button("Smooth Beaches", ImVec2(-1, 0))) { + app.getTerrainEditor().smoothBeaches(app.getWaterHeight(), 15.0f); + app.showToast("Beaches smoothed"); + } if (ImGui::Button("Remove ALL Water", ImVec2(-1, 0))) { for (int ci = 0; ci < 256; ci++) app.getTerrainEditor().getTerrain()->waterData[ci].layers.clear(); diff --git a/tools/editor/terrain_editor.cpp b/tools/editor/terrain_editor.cpp index 316c7f5d..f581bb25 100644 --- a/tools/editor/terrain_editor.cpp +++ b/tools/editor/terrain_editor.cpp @@ -962,6 +962,29 @@ void TerrainEditor::fillWater(float height, uint16_t liquidType) { dirty_ = true; } +void TerrainEditor::smoothBeaches(float waterHeight, float beachWidth) { + if (!terrain_) return; + for (int ci = 0; ci < 256; ci++) { + auto& chunk = terrain_->chunks[ci]; + if (!chunk.hasHeightMap()) continue; + bool modified = false; + for (int v = 0; v < 145; v++) { + float absH = chunk.position[2] + chunk.heightMap.heights[v]; + float distToWater = std::abs(absH - waterHeight); + if (distToWater < beachWidth) { + // Smooth toward water level with gentle slope + float t = distToWater / beachWidth; + float target = waterHeight + (absH > waterHeight ? 1.0f : -1.0f) * beachWidth * t * t; + float relTarget = target - chunk.position[2]; + chunk.heightMap.heights[v] = chunk.heightMap.heights[v] * 0.3f + relTarget * 0.7f; + modified = true; + } + } + if (modified) { stitchEdges(ci); dirtyChunks_.push_back(ci); } + } + dirty_ = true; +} + void TerrainEditor::thermalErosion(int iterations, float talusAngle) { if (!terrain_) return; float unitSize = CHUNK_SIZE / 8.0f; diff --git a/tools/editor/terrain_editor.hpp b/tools/editor/terrain_editor.hpp index 50e5cfcf..1b81ad73 100644 --- a/tools/editor/terrain_editor.hpp +++ b/tools/editor/terrain_editor.hpp @@ -117,6 +117,9 @@ public: // Fill entire tile with water at a height void fillWater(float height, uint16_t liquidType); + // Smooth terrain near water level to create natural beaches + void smoothBeaches(float waterHeight, float beachWidth); + // Import/export heightmap (raw 16-bit grayscale, 129x129) bool importHeightmap(const std::string& path, float heightScale); bool exportHeightmap(const std::string& path, float heightScale);