diff options
Diffstat (limited to 'source/EditorCorePrivate.cpp')
-rw-r--r-- | source/EditorCorePrivate.cpp | 198 |
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); } |