mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
feat(editor): click-to-place path points for river/road carver
- River/Road tool now uses click-capture mode instead of button-based cursor position — click terrain directly to set start and end points - 3-step flow: Click Start → Click End → Apply Path (with preview text) - Cancel button available at each step - Path state tracked on EditorUI with setPathPoint()/clearPath() - Intercepts terrain clicks before mode-specific handling when active
This commit is contained in:
parent
4e2f704124
commit
6b3cdd325a
3 changed files with 91 additions and 37 deletions
|
|
@ -360,8 +360,25 @@ void EditorApp::processEvents() {
|
|||
giz.endDrag();
|
||||
giz.setMode(TransformMode::None);
|
||||
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
// Path point capture (river/road tool)
|
||||
if (ui_.getPathCapture() != EditorUI::PathCapture::None) {
|
||||
auto ext = window_->getVkContext()->getSwapchainExtent();
|
||||
rendering::Ray ray = camera_.getCamera().screenToWorldRay(
|
||||
static_cast<float>(event.button.x),
|
||||
static_cast<float>(event.button.y),
|
||||
static_cast<float>(ext.width),
|
||||
static_cast<float>(ext.height));
|
||||
glm::vec3 hitPos;
|
||||
if (terrainEditor_.raycastTerrain(ray, hitPos)) {
|
||||
ui_.setPathPoint(hitPos);
|
||||
if (ui_.getPathCapture() == EditorUI::PathCapture::None && ui_.isPathReady())
|
||||
showToast("Both points set — click Apply Path");
|
||||
else if (ui_.getPathCapture() == EditorUI::PathCapture::WaitingEnd)
|
||||
showToast("Start point set — click terrain for end");
|
||||
}
|
||||
}
|
||||
// Ctrl+click = select object (any mode)
|
||||
if ((event.key.keysym.mod & KMOD_CTRL) || (SDL_GetModState() & KMOD_CTRL)) {
|
||||
else if ((event.key.keysym.mod & KMOD_CTRL) || (SDL_GetModState() & KMOD_CTRL)) {
|
||||
auto ext = window_->getVkContext()->getSwapchainExtent();
|
||||
rendering::Ray ray = camera_.getCamera().screenToWorldRay(
|
||||
static_cast<float>(event.button.x),
|
||||
|
|
|
|||
|
|
@ -130,6 +130,18 @@ void EditorUI::processActions(EditorApp& app) {
|
|||
}
|
||||
}
|
||||
|
||||
void EditorUI::setPathPoint(const glm::vec3& pos) {
|
||||
if (pathCapture_ == PathCapture::WaitingStart) {
|
||||
pathStart_ = pos;
|
||||
pathStartSet_ = true;
|
||||
pathCapture_ = PathCapture::WaitingEnd;
|
||||
} else if (pathCapture_ == PathCapture::WaitingEnd) {
|
||||
pathEnd_ = pos;
|
||||
pathEndSet_ = true;
|
||||
pathCapture_ = PathCapture::None;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorUI::renderMenuBar(EditorApp& app) {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
|
|
@ -770,45 +782,53 @@ void EditorUI::renderBrushPanel(EditorApp& app) {
|
|||
|
||||
ImGui::Separator();
|
||||
if (ImGui::CollapsingHeader("River / Road Carver")) {
|
||||
static glm::vec3 pathStart{0}, pathEnd{0};
|
||||
static float pathWidth = 8.0f, pathDepth = 5.0f;
|
||||
static bool pathStartSet = false;
|
||||
static int pathMode = 0; // 0=river, 1=road
|
||||
ImGui::RadioButton("River (carve down)", &pathMode, 0);
|
||||
ImGui::RadioButton("River (carve down)", &pathMode_, 0);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Road (flatten)", &pathMode, 1);
|
||||
ImGui::SliderFloat("Width##path", &pathWidth, 2.0f, 50.0f);
|
||||
if (pathMode == 0) ImGui::SliderFloat("Depth##path", &pathDepth, 1.0f, 30.0f);
|
||||
auto& brush4 = app.getTerrainEditor().brush();
|
||||
auto brushPos = brush4.getPosition();
|
||||
ImGui::Text("Cursor: %.0f, %.0f, %.0f %s",
|
||||
brushPos.x, brushPos.y, brushPos.z,
|
||||
brush4.isActive() ? "" : "(off terrain)");
|
||||
if (ImGui::Button("Set Start##path", ImVec2(120, 0))) {
|
||||
pathStart = brushPos;
|
||||
pathStartSet = true;
|
||||
app.showToast("Path start set");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Set End + Apply##path", ImVec2(140, 0)) && pathStartSet) {
|
||||
pathEnd = brushPos;
|
||||
if (pathMode == 0) {
|
||||
app.getTerrainEditor().carveRiver(pathStart, pathEnd, pathWidth, pathDepth);
|
||||
app.getTexturePainter().paintAlongPath(pathStart, pathEnd, pathWidth * 1.5f,
|
||||
"Tileset\\Ashenvale\\AshenvaleSand.blp");
|
||||
app.showToast("River carved + banks textured");
|
||||
} else {
|
||||
app.getTerrainEditor().flattenRoad(pathStart, pathEnd, pathWidth);
|
||||
app.getTexturePainter().paintAlongPath(pathStart, pathEnd, pathWidth,
|
||||
"Tileset\\Elwynn\\ElwynnCobblestoneBase.blp");
|
||||
app.showToast("Road flattened + textured");
|
||||
ImGui::RadioButton("Road (flatten)", &pathMode_, 1);
|
||||
ImGui::SliderFloat("Width##path", &pathWidth_, 2.0f, 50.0f);
|
||||
if (pathMode_ == 0) ImGui::SliderFloat("Depth##path", &pathDepth_, 1.0f, 30.0f);
|
||||
|
||||
if (pathCapture_ == PathCapture::None && !pathStartSet_) {
|
||||
if (ImGui::Button("Click Start Point", ImVec2(-1, 0))) {
|
||||
pathCapture_ = PathCapture::WaitingStart;
|
||||
pathStartSet_ = false;
|
||||
pathEndSet_ = false;
|
||||
app.showToast("Click terrain to set start point");
|
||||
}
|
||||
pathStartSet = false;
|
||||
} else if (pathCapture_ == PathCapture::WaitingStart) {
|
||||
ImGui::TextColored(ImVec4(1, 1, 0.3f, 1), "Click terrain for START point...");
|
||||
if (ImGui::SmallButton("Cancel##path")) {
|
||||
pathCapture_ = PathCapture::None;
|
||||
}
|
||||
} else if (pathCapture_ == PathCapture::WaitingEnd) {
|
||||
ImGui::TextColored(ImVec4(0.3f, 1, 0.3f, 1), "Start set at (%.0f, %.0f) — click for END",
|
||||
pathStart_.x, pathStart_.y);
|
||||
if (ImGui::SmallButton("Cancel##path")) {
|
||||
clearPath();
|
||||
}
|
||||
} else if (pathStartSet_ && pathEndSet_) {
|
||||
ImGui::TextColored(ImVec4(0.5f, 0.9f, 0.5f, 1),
|
||||
"Start: (%.0f,%.0f) End: (%.0f,%.0f)", pathStart_.x, pathStart_.y, pathEnd_.x, pathEnd_.y);
|
||||
if (ImGui::Button("Apply Path", ImVec2(-1, 0))) {
|
||||
if (pathMode_ == 0) {
|
||||
app.getTerrainEditor().carveRiver(pathStart_, pathEnd_, pathWidth_, pathDepth_);
|
||||
app.getTexturePainter().paintAlongPath(pathStart_, pathEnd_, pathWidth_ * 1.5f,
|
||||
"Tileset\\Ashenvale\\AshenvaleSand.blp");
|
||||
app.showToast("River carved + banks textured");
|
||||
} else {
|
||||
app.getTerrainEditor().flattenRoad(pathStart_, pathEnd_, pathWidth_);
|
||||
app.getTexturePainter().paintAlongPath(pathStart_, pathEnd_, pathWidth_,
|
||||
"Tileset\\Elwynn\\ElwynnCobblestoneBase.blp");
|
||||
app.showToast("Road flattened + textured");
|
||||
}
|
||||
clearPath();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("Reset##path")) clearPath();
|
||||
} else if (pathStartSet_) {
|
||||
if (ImGui::Button("Click End Point", ImVec2(-1, 0)))
|
||||
pathCapture_ = PathCapture::WaitingEnd;
|
||||
}
|
||||
if (pathStartSet)
|
||||
ImGui::TextColored(ImVec4(0.5f, 0.9f, 0.5f, 1), "Start set — click end point");
|
||||
else
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1), "Set start then end to apply");
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Mirror / Rotate")) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "terrain_biomes.hpp"
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -22,6 +23,15 @@ public:
|
|||
|
||||
PaintMode getPaintMode() const { return paintMode_; }
|
||||
|
||||
// Path point capture: when active, next terrain click sets the point
|
||||
enum class PathCapture { None, WaitingStart, WaitingEnd };
|
||||
PathCapture getPathCapture() const { return pathCapture_; }
|
||||
void setPathPoint(const glm::vec3& pos);
|
||||
glm::vec3 getPathStart() const { return pathStart_; }
|
||||
glm::vec3 getPathEnd() const { return pathEnd_; }
|
||||
bool isPathReady() const { return pathStartSet_ && pathEndSet_; }
|
||||
void clearPath() { pathStartSet_ = false; pathEndSet_ = false; pathCapture_ = PathCapture::None; }
|
||||
|
||||
private:
|
||||
void renderMenuBar(EditorApp& app);
|
||||
void renderToolbar(EditorApp& app);
|
||||
|
|
@ -71,6 +81,13 @@ private:
|
|||
int objDirIdx_ = -1;
|
||||
bool showM2s_ = true;
|
||||
bool showWMOs_ = true;
|
||||
|
||||
// Path point capture
|
||||
PathCapture pathCapture_ = PathCapture::None;
|
||||
glm::vec3 pathStart_{0}, pathEnd_{0};
|
||||
bool pathStartSet_ = false, pathEndSet_ = false;
|
||||
int pathMode_ = 0; // 0=river, 1=road
|
||||
float pathWidth_ = 8.0f, pathDepth_ = 5.0f;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue