From 496f97f9db898d09156605d34363a4ac90221c5c Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 5 May 2026 06:48:05 -0700 Subject: [PATCH] feat(editor): middle mouse orbit camera around terrain point - Middle mouse drag orbits camera around the terrain point under cursor (or 100 units ahead if no terrain hit) - Maintains distance from pivot while rotating yaw/pitch - Much more intuitive for inspecting terrain features, placed objects, and NPC positions from different angles - Works alongside right-drag (free look) and WASD (fly) --- tools/editor/editor_app.cpp | 7 ++++++- tools/editor/editor_camera.cpp | 18 ++++++++++++++++++ tools/editor/editor_camera.hpp | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/editor/editor_app.cpp b/tools/editor/editor_app.cpp index 6edf7fed..938125b2 100644 --- a/tools/editor/editor_app.cpp +++ b/tools/editor/editor_app.cpp @@ -263,7 +263,12 @@ void EditorApp::processEvents() { if (event.type == SDL_MOUSEMOTION && !io.WantCaptureMouse) { // Gizmo drag takes priority over camera auto& giz = viewport_.getGizmo(); - if (giz.isDragging()) { + if (event.motion.state & SDL_BUTTON_MMASK) { + // Middle mouse = orbit around brush/terrain point + auto& brush = terrainEditor_.brush(); + glm::vec3 pivot = brush.isActive() ? brush.getPosition() : camera_.getCamera().getPosition() + camera_.getCamera().getForward() * 100.0f; + camera_.processMiddleMouseMotion(event.motion.xrel, event.motion.yrel, pivot); + } else if (giz.isDragging()) { auto ext = window_->getVkContext()->getSwapchainExtent(); giz.updateDrag(glm::vec2(static_cast(event.motion.x), static_cast(event.motion.y)), diff --git a/tools/editor/editor_camera.cpp b/tools/editor/editor_camera.cpp index 5a8badbe..3a17c108 100644 --- a/tools/editor/editor_camera.cpp +++ b/tools/editor/editor_camera.cpp @@ -71,6 +71,24 @@ void EditorCamera::processKeyEvent(const SDL_KeyboardEvent& event) { void EditorCamera::processMouseButton(const SDL_MouseButtonEvent& event) { if (event.button == SDL_BUTTON_RIGHT) rightMouseDown_ = (event.type == SDL_MOUSEBUTTONDOWN); + if (event.button == SDL_BUTTON_MIDDLE) + middleMouseDown_ = (event.type == SDL_MOUSEBUTTONDOWN); +} + +void EditorCamera::processMiddleMouseMotion(int dx, int dy, const glm::vec3& pivotPoint) { + if (!middleMouseDown_) return; + + constexpr float sensitivity = 0.3f; + yaw_ += static_cast(dx) * sensitivity; + pitch_ -= static_cast(dy) * sensitivity; + pitch_ = std::clamp(pitch_, -89.0f, 89.0f); + camera_.setRotation(yaw_, pitch_); + + // Orbit: maintain distance from pivot + glm::vec3 toPivot = pivotPoint - camera_.getPosition(); + float dist = glm::length(toPivot); + glm::vec3 newPos = pivotPoint - camera_.getForward() * dist; + camera_.setPosition(newPos); } void EditorCamera::setPosition(const glm::vec3& pos) { diff --git a/tools/editor/editor_camera.hpp b/tools/editor/editor_camera.hpp index 926c1fb3..11c8b066 100644 --- a/tools/editor/editor_camera.hpp +++ b/tools/editor/editor_camera.hpp @@ -16,6 +16,7 @@ public: void processMouseWheel(float delta, bool shiftHeld); void processKeyEvent(const SDL_KeyboardEvent& event); void processMouseButton(const SDL_MouseButtonEvent& event); + void processMiddleMouseMotion(int dx, int dy, const glm::vec3& pivotPoint); rendering::Camera& getCamera() { return camera_; } const rendering::Camera& getCamera() const { return camera_; } @@ -33,6 +34,7 @@ private: bool keyW_ = false, keyA_ = false, keyS_ = false, keyD_ = false; bool keyQ_ = false, keyE_ = false, keyShift_ = false; bool rightMouseDown_ = false; + bool middleMouseDown_ = false; }; } // namespace editor