mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
fix(editor): terrain raycast on rough terrain, keyboard shortcuts, context menu
- Raycast AABB now uses actual min/max vertex heights per chunk instead of fixed ±200 padding (fixes misses on sculpted terrain) - Right-click context menu opens correctly (deferred popup via flag since ImGui::OpenPopup must be called within ImGui frame) - Keyboard shortcuts: G=Move, R=Rotate, T=Scale, X/Y=axis lock, Escape=deselect, Delete works in any mode for objects/NPCs - Delete key now removes selected NPC in NPC mode too
This commit is contained in:
parent
f38884856f
commit
ace6173401
4 changed files with 40 additions and 7 deletions
|
|
@ -189,9 +189,27 @@ void EditorApp::processEvents() {
|
||||||
if (event.type == SDL_KEYDOWN) {
|
if (event.type == SDL_KEYDOWN) {
|
||||||
auto sc = event.key.keysym.scancode;
|
auto sc = event.key.keysym.scancode;
|
||||||
if (sc == SDL_SCANCODE_F3) setWireframe(!isWireframe());
|
if (sc == SDL_SCANCODE_F3) setWireframe(!isWireframe());
|
||||||
if (sc == SDL_SCANCODE_DELETE && mode_ == EditorMode::PlaceObject) {
|
// Transform shortcuts (Blender-style)
|
||||||
objectPlacer_.deleteSelected();
|
if (objectPlacer_.getSelected()) {
|
||||||
objectsDirty_ = true;
|
if (sc == SDL_SCANCODE_G) startGizmoMode(TransformMode::Move);
|
||||||
|
if (sc == SDL_SCANCODE_R) startGizmoMode(TransformMode::Rotate);
|
||||||
|
if (sc == SDL_SCANCODE_T) startGizmoMode(TransformMode::Scale);
|
||||||
|
if (sc == SDL_SCANCODE_X) setGizmoAxis(TransformAxis::X);
|
||||||
|
if (sc == SDL_SCANCODE_Y) setGizmoAxis(TransformAxis::Y);
|
||||||
|
if (sc == SDL_SCANCODE_ESCAPE) {
|
||||||
|
viewport_.getGizmo().endDrag();
|
||||||
|
viewport_.getGizmo().setMode(TransformMode::None);
|
||||||
|
objectPlacer_.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sc == SDL_SCANCODE_DELETE) {
|
||||||
|
if (objectPlacer_.getSelected()) {
|
||||||
|
objectPlacer_.deleteSelected();
|
||||||
|
objectsDirty_ = true;
|
||||||
|
} else if (npcSpawner_.getSelected()) {
|
||||||
|
npcSpawner_.removeCreature(npcSpawner_.getSelectedIndex());
|
||||||
|
objectsDirty_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sc == SDL_SCANCODE_Z && (event.key.keysym.mod & KMOD_CTRL)) {
|
if (sc == SDL_SCANCODE_Z && (event.key.keysym.mod & KMOD_CTRL)) {
|
||||||
if (event.key.keysym.mod & KMOD_SHIFT)
|
if (event.key.keysym.mod & KMOD_SHIFT)
|
||||||
|
|
@ -242,7 +260,7 @@ void EditorApp::processEvents() {
|
||||||
giz.endDrag();
|
giz.endDrag();
|
||||||
giz.setMode(TransformMode::None);
|
giz.setMode(TransformMode::None);
|
||||||
} else if (objectPlacer_.getSelected()) {
|
} else if (objectPlacer_.getSelected()) {
|
||||||
ImGui::OpenPopup("ObjectContextMenu");
|
openContextMenu_ = true;
|
||||||
} else {
|
} else {
|
||||||
camera_.processMouseButton(event.button);
|
camera_.processMouseButton(event.button);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ public:
|
||||||
void startGizmoMode(TransformMode mode);
|
void startGizmoMode(TransformMode mode);
|
||||||
void setGizmoAxis(TransformAxis axis);
|
void setGizmoAxis(TransformAxis axis);
|
||||||
TransformGizmo& getGizmo() { return viewport_.getGizmo(); }
|
TransformGizmo& getGizmo() { return viewport_.getGizmo(); }
|
||||||
|
bool shouldOpenContextMenu() const { return openContextMenu_; }
|
||||||
|
void clearContextMenuFlag() { openContextMenu_ = false; }
|
||||||
|
|
||||||
float getWaterHeight() const { return waterHeight_; }
|
float getWaterHeight() const { return waterHeight_; }
|
||||||
void setWaterHeight(float h) { waterHeight_ = h; }
|
void setWaterHeight(float h) { waterHeight_ = h; }
|
||||||
|
|
@ -92,6 +94,7 @@ private:
|
||||||
bool imguiInitialized_ = false;
|
bool imguiInitialized_ = false;
|
||||||
bool painting_ = false;
|
bool painting_ = false;
|
||||||
bool objectsDirty_ = false;
|
bool objectsDirty_ = false;
|
||||||
|
bool openContextMenu_ = false;
|
||||||
size_t lastObjectCount_ = 0;
|
size_t lastObjectCount_ = 0;
|
||||||
EditorMode mode_ = EditorMode::Sculpt;
|
EditorMode mode_ = EditorMode::Sculpt;
|
||||||
float waterHeight_ = 100.0f;
|
float waterHeight_ = 100.0f;
|
||||||
|
|
|
||||||
|
|
@ -592,6 +592,10 @@ void EditorUI::renderWaterPanel(EditorApp& app) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorUI::renderContextMenu(EditorApp& app) {
|
void EditorUI::renderContextMenu(EditorApp& app) {
|
||||||
|
if (app.shouldOpenContextMenu()) {
|
||||||
|
ImGui::OpenPopup("ObjectContextMenu");
|
||||||
|
app.clearContextMenuFlag();
|
||||||
|
}
|
||||||
if (ImGui::BeginPopup("ObjectContextMenu")) {
|
if (ImGui::BeginPopup("ObjectContextMenu")) {
|
||||||
auto* sel = app.getObjectPlacer().getSelected();
|
auto* sel = app.getObjectPlacer().getSelected();
|
||||||
if (!sel) { ImGui::EndPopup(); return; }
|
if (!sel) { ImGui::EndPopup(); return; }
|
||||||
|
|
|
||||||
|
|
@ -133,11 +133,19 @@ bool TerrainEditor::raycastTerrain(const rendering::Ray& ray, glm::vec3& hitPos)
|
||||||
const auto& chunk = terrain_->chunks[chunkIdx];
|
const auto& chunk = terrain_->chunks[chunkIdx];
|
||||||
if (!chunk.hasHeightMap()) continue;
|
if (!chunk.hasHeightMap()) continue;
|
||||||
|
|
||||||
// Quick AABB check: compute chunk bounds in render space
|
// Quick AABB check using actual vertex extent
|
||||||
glm::vec3 corner0 = chunkVertexWorldPos(chunkIdx, 0);
|
glm::vec3 corner0 = chunkVertexWorldPos(chunkIdx, 0);
|
||||||
glm::vec3 corner1 = chunkVertexWorldPos(chunkIdx, 144);
|
glm::vec3 corner1 = chunkVertexWorldPos(chunkIdx, 144);
|
||||||
glm::vec3 minB = glm::min(corner0, corner1) - glm::vec3(0, 0, 200);
|
glm::vec3 minB = glm::min(corner0, corner1);
|
||||||
glm::vec3 maxB = glm::max(corner0, corner1) + glm::vec3(0, 0, 200);
|
glm::vec3 maxB = glm::max(corner0, corner1);
|
||||||
|
// Expand Z by actual height range in chunk
|
||||||
|
float minH = chunk.heightMap.heights[0], maxH = minH;
|
||||||
|
for (int h = 1; h < 145; h++) {
|
||||||
|
minH = std::min(minH, chunk.heightMap.heights[h]);
|
||||||
|
maxH = std::max(maxH, chunk.heightMap.heights[h]);
|
||||||
|
}
|
||||||
|
minB.z = chunk.position[2] + minH - 10.0f;
|
||||||
|
maxB.z = chunk.position[2] + maxH + 10.0f;
|
||||||
|
|
||||||
// Simple AABB-ray test
|
// Simple AABB-ray test
|
||||||
float tmin = -1e30f, tmax = 1e30f;
|
float tmin = -1e30f, tmax = 1e30f;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue