aboutsummaryrefslogtreecommitdiff
path: root/source/EditorCorePrivate.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-05-07 23:13:14 -0700
committerrtk0c <[email protected]>2022-05-07 23:13:14 -0700
commitdaca3ada37d885b197d6fa810b6b793f18f8068e (patch)
tree6b7bb160352fc86aa0822bd05e193bff72ebf7c7 /source/EditorCorePrivate.cpp
parent0816a885c85eebe70d8a3b72c5bf12d56d4b9bff (diff)
Changeset: 28 Add more camera controls (3D mode, scroll scaling)
Diffstat (limited to 'source/EditorCorePrivate.cpp')
-rw-r--r--source/EditorCorePrivate.cpp198
1 files changed, 159 insertions, 39 deletions
diff --git a/source/EditorCorePrivate.cpp b/source/EditorCorePrivate.cpp
index e4fdc54..38ba8f6 100644
--- a/source/EditorCorePrivate.cpp
+++ b/source/EditorCorePrivate.cpp
@@ -26,6 +26,9 @@
#include <cstdint>
#include <cstdlib>
#include <functional>
+#include <glm/gtc/quaternion.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/quaternion.hpp>
#include <limits>
#include <memory>
#include <string>
@@ -315,8 +318,8 @@ EditorInstance::EditorInstance(App* app)
: mApp{ app }
, mEdContentBrowser(&mEdInspector) {
mEditorCamera.name = "Editor Camera"s;
- mEditorCamera.Move(glm::vec3(50, 40, 50));
- mEditorCamera.LookAtPos(glm::vec3(0, 0, 0));
+ mEditorCamera.SetEyePos(glm::vec3(0, 0, 200));
+ mEditorCamera.SetTargetPos(glm::vec3(0, 0, 0));
mEditorCamera.SetHasPerspective(true);
app->BindActiveCamera(&mEditorCamera);
}
@@ -371,46 +374,114 @@ void EditorInstance::Show() {
auto& camera = *mApp->GetActiveCamera();
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
- ImGuizmo::SetDrawlist(ImGui::GetForegroundDrawList());
+ ImGuizmo::SetDrawlist(ImGui::GetBackgroundDrawList());
- auto cameraPos = camera.pos;
- {
- if (ImGui::IsMouseClicked(ImGuiMouseButton_Right) && !io.WantCaptureMouse && !mDragCam_Happening) {
- mDragCam_CamInitial = camera.pos;
- mDragCam_CursorInitial = ImGui::GetMousePos();
- mDragCam_Happening = true;
- }
- if (mDragCam_Happening) {
- auto newPos = ImGui::GetMousePos();
- // NOTE: we are emulating as if the mouse is dragging the "canvas", through moving the camera in the opposite direction of the natural position delta
- cameraPos.x = mDragCam_CamInitial.x + mDragCam_CursorInitial.x - newPos.x;
- cameraPos.y = mDragCam_CamInitial.y + -(mDragCam_CursorInitial.y - newPos.y); // Invert Y delta because ImGui uses top-left origin (mouse moving down translates to positive value, but in our coordinate system down is negative)
+ if (IsCurrentCameraEditor() && mEcm == ECM_Side3D) {
+ float viewManipulateRight = io.DisplaySize.x;
+ float viewManipulateTop = 0;
- // Draw movement indicator
- auto drawList = ImGui::GetForegroundDrawList();
- ImGui::DrawArrow(drawList, ImVec2(mDragCam_CursorInitial.x, mDragCam_CursorInitial.y), newPos, IM_COL32(0, 255, 255, 255));
- }
- if (ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
- mDragCam_Happening = false;
+ // TODO get rid of this massive hack: how to manage const better for intuitively read-only, but write doesn't-care data?
+ auto& lastFrameInfo = const_cast<RendererFrameInfo&>(mApp->GetWorldRenderer()->GetLastFrameInfo());
+ auto& view = lastFrameInfo.matrixView;
+ auto& proj = lastFrameInfo.matrixProj;
+ ImGuizmo::ViewManipulate(
+ glm::value_ptr(view),
+ 200.0f, // TODO
+ ImVec2(viewManipulateRight - 128, viewManipulateTop),
+ ImVec2(128, 128),
+ 0x10101010);
+
+ // TODO draw this as a part of the world so it doesn't block objects
+#if 0
+ glm::mat4 identity(1.00f);
+ ImGuizmo::DrawGrid(
+ glm::value_ptr(view),
+ glm::value_ptr(proj),
+ glm::value_ptr(identity),
+ 100.f);
+#endif
+
+ // Extract eye and target position from view matrix
+ // - View matrix transforms world space to view space
+ // - Inverse view matrix should transform view space into world space
+ // - In view space, camera's pos is (0,0,0) and the look/forward vector should be (0,0,-1)
+ auto invView = glm::inverse(view);
+ camera.eye = invView * glm::vec4(0, 0, 0, 1);
+ camera.target = camera.eye + glm::vec3(invView * glm::vec4(0, 0, -1, 1));
+
+ { // Camera controls
+ auto cameraPos = camera.eye;
+ auto cameraForward = glm::normalize(camera.target - camera.eye);
+ // Always move on the horzontal flat plane
+ cameraForward.y = 0.0f;
+
+ if (mMoveCamKeyboard) {
+ constexpr float kCameraMoveSpeed = 5.0f;
+ if (ImGui::IsKeyDown(ImGuiKey_W)) {
+ cameraPos += kCameraMoveSpeed * cameraForward;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_S)) {
+ auto cameraBack = glm::normalize(-cameraForward);
+ cameraPos += kCameraMoveSpeed * cameraBack;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_A)) {
+ auto cameraLeft = glm::normalize(glm::cross(cameraForward, glm::vec3(0, 1, 0)));
+ cameraPos += kCameraMoveSpeed * cameraLeft;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_D)) {
+ auto cameraLeft = glm::normalize(glm::cross(cameraForward, glm::vec3(0, 1, 0)));
+ auto cameraRight = -cameraLeft;
+ cameraPos += kCameraMoveSpeed * cameraRight;
+ }
+ }
+
+ camera.SetEyePos(cameraPos);
}
+ } else {
+ { // Camera controls
+ auto cameraPos = camera.eye;
- if (mMoveCamKeyboard) {
- constexpr float kCameraMoveSpeed = 5.0f;
- if (ImGui::IsKeyDown(ImGuiKey_W)) {
- cameraPos.y += kCameraMoveSpeed;
+ if (ImGui::IsMouseClicked(ImGuiMouseButton_Right) && !io.WantCaptureMouse && !mDragCam_Happening) {
+ mDragCam_CamInitial = camera.eye;
+ mDragCam_CursorInitial = ImGui::GetMousePos();
+ mDragCam_Happening = true;
}
- if (ImGui::IsKeyDown(ImGuiKey_S)) {
- cameraPos.y -= kCameraMoveSpeed;
+ if (mDragCam_Happening) {
+ auto newPos = ImGui::GetMousePos();
+ // NOTE: we are emulating as if the mouse is dragging the "canvas", through moving the camera in the opposite direction of the natural position delta
+ cameraPos.x = mDragCam_CamInitial.x + mDragCam_CursorInitial.x - newPos.x;
+ cameraPos.y = mDragCam_CamInitial.y + -(mDragCam_CursorInitial.y - newPos.y); // Invert Y delta because ImGui uses top-left origin (mouse moving down translates to positive value, but in our coordinate system down is negative)
+
+ // Draw movement indicator
+ auto drawList = ImGui::GetForegroundDrawList();
+ ImGui::DrawArrow(drawList, ImVec2(mDragCam_CursorInitial.x, mDragCam_CursorInitial.y), newPos, IM_COL32(0, 255, 255, 255));
}
- if (ImGui::IsKeyDown(ImGuiKey_A)) {
- cameraPos.x -= kCameraMoveSpeed;
+ if (ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
+ mDragCam_Happening = false;
+ }
+
+ if (mMoveCamKeyboard) {
+ if (ImGui::IsKeyDown(ImGuiKey_W)) {
+ cameraPos.y += mMoveCamSlideSpeed;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_S)) {
+ cameraPos.y -= mMoveCamSlideSpeed;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_A)) {
+ cameraPos.x -= mMoveCamSlideSpeed;
+ }
+ if (ImGui::IsKeyDown(ImGuiKey_D)) {
+ cameraPos.x += mMoveCamSlideSpeed;
+ }
}
- if (ImGui::IsKeyDown(ImGuiKey_D)) {
- cameraPos.x += kCameraMoveSpeed;
+
+ if (mMoveCamScrollWheel) {
+ cameraPos.z = std::clamp(cameraPos.z + io.MouseWheel, 0.1f, 100.0f);
}
+
+ camera.SetEyePos(cameraPos);
}
}
- camera.Move(cameraPos);
if (mWindowVisible_Inspector) {
ImGui::Begin("Inspector");
@@ -503,12 +574,16 @@ void EditorInstance::ShowWorldProperties() {
auto& camera = *mApp->GetActiveCamera();
ImGui::TextUnformatted("Active camera:");
ImGui::Indent();
-#define CAMERA_POS_TEXT "at (%.3f, %.3f, %.3f)\nlooking at (%.3f, %.3f, %.3f)", camera.pos.x, camera.pos.y, camera.pos.z, camera.lookAt.x, camera.lookAt.y, camera.lookAt.z
+#define CAMERA_POS_TEXT "at (%.3f, %.3f, %.3f)\nlooking at (%.3f, %.3f, %.3f)", camera.eye.x, camera.eye.y, camera.eye.z, camera.target.x, camera.target.y, camera.target.z
ImGui::TextUnformatted(camera.name.c_str());
ImGui::Text(CAMERA_POS_TEXT);
if (ImGui::BeginPopupContextItem("##CTXMENU")) {
if (ImGui::MenuItem("Reset to origin")) {
- camera.Move(glm::vec3(1.0f, 1.0f, 1.0f));
+ camera.SetEyePos(glm::vec3(1.0f, 1.0f, 1.0f));
+ }
+ if (ImGui::MenuItem("Reset completely")) {
+ camera.eye = glm::vec3(0, 0, 1);
+ camera.target = glm::vec3(0, 0, 0);
}
if (ImGui::MenuItem("Copy")) {
char buffer[2048];
@@ -519,7 +594,53 @@ void EditorInstance::ShowWorldProperties() {
ImGui::EndPopup();
}
#undef CAMERA_POS_TEXT
+ if (IsCurrentCameraEditor()) {
+ const char* preview;
+ switch (mEcm) {
+ case ECM_2D: preview = "2D view"; break;
+ case ECM_Side3D: preview = "Side 3D view"; break;
+ }
+ if (ImGui::BeginCombo("Mode", preview)) {
+ if (ImGui::Selectable("2D view", mEcm == ECM_2D)) {
+ if (mEcm != ECM_2D) {
+ mEcm = ECM_2D;
+
+ // TODO project eye to world plane
+
+ camera.SetHasPerspective(false);
+ }
+ }
+ if (ImGui::Selectable("Side 3D view", mEcm == ECM_Side3D)) {
+ if (mEcm != ECM_Side3D) {
+ mEcm = ECM_Side3D;
+
+ auto origEye = camera.eye;
+ auto origTarget = camera.target;
+
+ // New setup: focus on the point of world plane that we were originally "hovering above"
+ camera.target = origEye;
+ camera.target.z = 0.0f;
+
+ // New setup: move the eye back at an angle
+ glm::vec3 vec;
+ vec.x = std::cos(60.0f);
+ vec.y = 0.0f;
+ vec.z = std::sin(60.0f);
+ camera.eye = camera.target + 200.0f * vec;
+
+ camera.SetHasPerspective(true);
+ }
+ }
+ ImGui::EndCombo();
+ }
+ }
+
ImGui::Checkbox("Move camera with WASD", &mMoveCamKeyboard);
+ ImGui::SliderFloat("Camera slide speed", &mMoveCamSlideSpeed, 0.1f, 10.0f);
+
+ ImGui::Checkbox("Move camera with scoll wheel", &mMoveCamScrollWheel);
+ ImGui::SliderFloat("Camera scroll speed", &mMoveCamScrollSpeed, 0.01, 10.0f);
+
ImGui::Unindent();
}
@@ -614,12 +735,11 @@ void EditorInstance::ShowInspector(GameObject* object) {
auto ShowGuizmo = [&](/*array[6]*/ float* bounds = nullptr) {
glm::mat4 identityMatrix(1.00f);
- // TODO get rid of this massive hack: how to manage const better for intuitively read-only, but write doesn't-care data?
- auto& lastFrameInfo = const_cast<RendererFrameInfo&>(mApp->GetWorldRenderer()->GetLastFrameInfo());
+ auto& lastFrameInfo = mApp->GetWorldRenderer()->GetLastFrameInfo();
auto& cameraViewMat = lastFrameInfo.matrixView;
- float* cameraView = &cameraViewMat[0][0];
+ const float* cameraView = &cameraViewMat[0][0];
auto& cameraProjMat = lastFrameInfo.matrixProj;
- float* cameraProj = &cameraProjMat[0][0];
+ const float* cameraProj = &cameraProjMat[0][0];
auto objectPos = object->GetPos();
auto objectScale = object->GetScale();
@@ -743,7 +863,7 @@ void EditorInstance::ShowInspector(GameObject* object) {
sg->SetSize(glm::vec3(bounds[3] - bounds[0], bounds[4] - bounds[1], bounds[5] - bounds[2]));
auto size = sg->GetSize();
- if (ImGui::InputFloat2("Size", &size.x)) {
+ if (ImGui::InputFloat3("Size", &size.x)) {
sg->SetSize(size);
}