diff --git a/Engine/Source/Editor/Camera/EditorCameraController.cpp b/Engine/Source/Editor/Camera/EditorCameraController.cpp deleted file mode 100644 index 7c1651c5..00000000 --- a/Engine/Source/Editor/Camera/EditorCameraController.cpp +++ /dev/null @@ -1,414 +0,0 @@ -#include "EditorCameraController.h" - -#include "ECWorld/CameraComponent.h" -#include "ECWorld/SceneWorld.h" -#include "ImGui/imgui.h" -#include "ImGuizmo/ImGuizmo.h" -#include "Math/Quaternion.hpp" -#include "Window/Input.h" - -#include -#include - -namespace engine -{ - -EditorCameraController::EditorCameraController( - const SceneWorld* pSceneWorld, - float sensitivity, - float movement_speed) - : EditorCameraController(pSceneWorld, sensitivity, sensitivity, movement_speed) -{ -} - -EditorCameraController::EditorCameraController( - const SceneWorld* pSceneWorld, - float horizontal_sensitivity, - float vertical_sensitivity, - float movement_speed) - : m_pSceneWorld(pSceneWorld) - , m_horizontalSensitivity(horizontal_sensitivity) - , m_verticalSensitivity(vertical_sensitivity) - , m_movementSpeed(movement_speed) - , m_initialMovemenSpeed(movement_speed) -{ - assert(pSceneWorld); -} - -void EditorCameraController::CameraToController() -{ - m_eye = GetMainCameraTransform().GetTranslation(); - m_lookAt = CameraComponent::GetLookAt(GetMainCameraTransform()); - m_up = CameraComponent::GetUp(GetMainCameraTransform()); -} - -void EditorCameraController::ControllerToCamera() -{ - cd::Vec3f eye = m_eye; - cd::Vec3f lookAt = m_lookAt; - cd::Vec3f up = m_up; - - if (m_isTracking) - { - float sinPhi = std::sin(m_elevation); - float cosPhi = std::cos(m_elevation); - float sinTheta = std::sin(m_azimuth); - float cosTheta = std::cos(m_azimuth); - - lookAt = cd::Vec3f(-cosPhi * sinTheta, -sinPhi, -cosPhi * cosTheta); - cd::Vec3f cross = cd::Vec3f(cosTheta, 0.0f, -sinTheta); - up = cross.Cross(lookAt); - - float lookAtOffset = 0.0f; - if (m_distanceFromLookAt < m_dollyThreshold) - { - lookAtOffset = m_distanceFromLookAt - m_dollyThreshold; - } - - float eyeOffset = m_distanceFromLookAt; - eye = m_lookAtPoint - (lookAt * eyeOffset); - - // Synchronize view to fps camera - m_eye = eye; - m_lookAt = lookAt; - m_up = up; - } - - GetMainCameraComponent()->BuildViewMatrix(eye, lookAt, up); - TransformComponent* pTransformComponent = GetMainCameraTransformComponent(); - pTransformComponent->GetTransform().SetTranslation(eye); - - // TODO : Add interface to math lib. - lookAt.Normalize(); - cd::Vec3f rotationAxis = cd::Vec3f(0.0f, 0.0f,1.0f).Cross(lookAt).Normalize(); - float rotationAngle = std::acos(cd::Vec3f(0.0f, 0.0f, 1.0f).Dot(lookAt)); - pTransformComponent->GetTransform().SetRotation(cd::Quaternion::FromAxisAngle(rotationAxis, rotationAngle)); - pTransformComponent->Build(); -} - -void EditorCameraController::Update(float deltaTime) -{ - Moving(); - - if (Input::Get().IsKeyPressed(KeyCode::z)) - { - // TODO : Only need to happen once in the first time press z. - SynchronizeTrackingCamera(); - - if (Input::Get().IsMouseLBPressed() && !m_isMoving) - { - m_isTracking = true; - ElevationChanging(m_verticalSensitivity * Input::Get().GetMousePositionOffsetY() * deltaTime); - AzimuthChanging(-m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); - } - - if (Input::Get().IsMouseRBPressed()) - { - float scaleDelta = (Input::Get().GetMousePositionOffsetX() - Input::Get().GetMousePositionOffsetY()) * deltaTime * m_movementSpeed; - m_distanceFromLookAt -= scaleDelta; - m_eye = m_eye + m_lookAt * scaleDelta; - ControllerToCamera(); - } - - if (Input::Get().GetMouseScrollOffsetY()) - { - float scaleDelta = Input::Get().GetMouseScrollOffsetY() * deltaTime * m_movementSpeed * 5.0f; - - m_distanceFromLookAt -= scaleDelta; - m_eye = m_eye + m_lookAt * scaleDelta; - ControllerToCamera(); - } - } - else - { - if (Input::Get().IsMouseMBPressed()) - { - m_isTracking = false; - float dx = Input::Get().GetMousePositionOffsetX() * deltaTime * m_movementSpeed / 4.0f; - float dy = Input::Get().GetMousePositionOffsetY() * deltaTime * m_movementSpeed / 4.0f; - Panning(dx, dy); - } - if (Input::Get().IsMouseLBPressed() || Input::Get().IsMouseRBPressed() || Input::Get().IsMouseMBPressed()) - { - if (Input::Get().GetMouseScrollOffsetY()) - { - float speedRate = std::pow(2.0f, Input::Get().GetMouseScrollOffsetY() / 10.0f); - m_movementSpeed = speedRate * m_movementSpeed; - } - - if (Input::Get().IsKeyPressed(KeyCode::w) && !m_isMoving) - { - m_isTracking = false; - MoveForward(m_movementSpeed * deltaTime); - } - - if (Input::Get().IsKeyPressed(KeyCode::a) && !m_isMoving) - { - m_isTracking = false; - MoveLeft(m_movementSpeed * deltaTime); - } - - if (Input::Get().IsKeyPressed(KeyCode::s) && !m_isMoving) - { - m_isTracking = false; - MoveBackward(m_movementSpeed * deltaTime); - } - - if (Input::Get().IsKeyPressed(KeyCode::d) && !m_isMoving) - { - m_isTracking = false; - MoveRight(m_movementSpeed * deltaTime); - } - - if (Input::Get().IsKeyPressed(KeyCode::e)) - { - m_isTracking = false; - MoveDown(m_movementSpeed * deltaTime); - } - - if (Input::Get().IsKeyPressed(KeyCode::q) && !m_isMoving) - { - m_isTracking = false; - MoveUp(m_movementSpeed * deltaTime); - } - } - - - if (Input::Get().IsMouseRBPressed() && !m_isMoving) - { - m_isTracking = false; - Yaw(m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); - } - - if (Input::Get().IsMouseLBPressed() && !ImGuizmo::IsUsing()) - { - m_isTracking = false; - PitchLocal(m_verticalSensitivity * Input::Get().GetMousePositionOffsetY() * deltaTime); - Yaw(m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); - } - } -} - -void EditorCameraController::SetMovementSpeed(float speed) -{ - m_movementSpeed = speed; -} - -void EditorCameraController::SetSensitivity(float horizontal, float verticle) -{ - m_horizontalSensitivity = horizontal; - m_verticalSensitivity = verticle; -} - -void EditorCameraController::SetHorizontalSensitivity(float sensitivity) -{ - m_horizontalSensitivity = sensitivity; -} - -void EditorCameraController::SetVerticalSensitivity(float sensitivity) -{ - m_verticalSensitivity = sensitivity; -} - -engine::CameraComponent* EditorCameraController::GetMainCameraComponent() const -{ - return m_pSceneWorld->GetCameraComponent(m_pSceneWorld->GetMainCameraEntity()); -} - -engine::TransformComponent* EditorCameraController::GetMainCameraTransformComponent() const -{ - return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity()); -} - -const cd::Transform& EditorCameraController::GetMainCameraTransform() -{ - return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity())->GetTransform(); -} - -void EditorCameraController::MoveForward(float amount) -{ - m_eye = m_eye + m_lookAt * amount; - ControllerToCamera(); -} - -void EditorCameraController::MoveBackward(float amount) -{ - MoveForward(-amount); -} - -void EditorCameraController::MoveLeft(float amount) -{ - m_eye = m_eye + m_lookAt.Cross(m_up) * amount; - ControllerToCamera(); -} - -void EditorCameraController::MoveRight(float amount) -{ - MoveLeft(-amount); -} - -void EditorCameraController::MoveUp(float amount) -{ - m_eye = m_eye + cd::Vec3f(0.0f, 1.0f, 0.0f) * amount; - ControllerToCamera(); -} - -void EditorCameraController::MoveDown(float amount) -{ - MoveUp(-amount); -} - -void EditorCameraController::Rotate(const cd::Vec3f& axis, float angleDegrees) -{ - cd::Quaternion rotation = cd::Quaternion::FromAxisAngle(axis, cd::Math::DegreeToRadian(angleDegrees)); - m_lookAt = rotation * m_lookAt; - m_up = rotation * m_up; - ControllerToCamera(); -} - -void EditorCameraController::Rotate(float x, float y, float z, float angleDegrees) -{ - Rotate(cd::Vec3f(x, y, z), angleDegrees); -} - - -void EditorCameraController::Yaw(float angleDegrees) -{ - Rotate(0.0f, 1.0f, 0.0f, angleDegrees); -} - -void EditorCameraController::Pitch(float angleDegrees) -{ - Rotate(1.0f, 0.0f, 0.0f, angleDegrees); -} - -void EditorCameraController::Roll(float angleDegrees) -{ - Rotate(0.0f, 0.0f, 1.0f, angleDegrees); -} - -void EditorCameraController::YawLocal(float angleDegrees) -{ - Rotate(m_up, angleDegrees); -} - -void EditorCameraController::PitchLocal(float angleDegrees) -{ - Rotate(m_up.Cross(m_lookAt), angleDegrees); -} - -void EditorCameraController::RollLocal(float angleDegrees) -{ - Rotate(m_lookAt, angleDegrees); -} - -void EditorCameraController::ElevationChanging(float angleDegrees) -{ - m_elevation += angleDegrees / 360.0f * cd::Math::PI; - if (m_elevation > cd::Math::PI) - { - m_elevation -= cd::Math::TWO_PI; - } - else if (m_elevation < -cd::Math::PI) - { - m_elevation += cd::Math::TWO_PI; - } - ControllerToCamera(); -} - -void EditorCameraController::AzimuthChanging(float angleDegrees) -{ - m_azimuth -= angleDegrees / 360.0f * cd::Math::PI; - if (m_azimuth > cd::Math::PI) - { - m_azimuth -= cd::Math::TWO_PI; - } - else if (m_azimuth < -cd::Math::PI) - { - m_azimuth += cd::Math::TWO_PI; - } - ControllerToCamera(); -} - -void EditorCameraController::SynchronizeTrackingCamera() -{ - m_lookAtPoint = m_lookAt * m_distanceFromLookAt + m_eye; - m_elevation = std::asin(-m_lookAt.y()); - - if (cd::Math::IsSmallThanZero(m_up.y())) - { - if (cd::Math::IsLargeThanZero(m_lookAt.y())) - { - m_elevation = -cd::Math::PI - m_elevation; - } - else - { - m_elevation = cd::Math::PI - m_elevation; - m_azimuth = std::atan2(m_lookAt.x(), m_lookAt.z()); - } - } - else - { - m_azimuth = std::atan2(-m_lookAt.x(), -m_lookAt.z()); - } -} - -void EditorCameraController::CameraFocus() -{ - Entity selectedEntity = m_pSceneWorld->GetSelectedEntity(); - if (selectedEntity == INVALID_ENTITY) - { - return; - } - - if (TransformComponent* pTransform = m_pSceneWorld->GetTransformComponent(selectedEntity)) - { - m_isMoving = true; - if (CollisionMeshComponent* pCollisionMesh = m_pSceneWorld->GetCollisionMeshComponent(selectedEntity)) - { - cd::AABB meshAABB = pCollisionMesh->GetAABB(); - meshAABB = meshAABB.Transform(pTransform->GetWorldMatrix()); - m_distanceFromLookAt = (meshAABB.Max() - meshAABB.Center()).Length() * 3.0f; - m_eyeDestination = meshAABB.Center() - m_lookAt * m_distanceFromLookAt; - m_movementSpeed = meshAABB.Size().Length() * 1.5f; - } - else - { - m_eyeDestination = pTransform->GetTransform().GetTranslation() - m_lookAt * m_distanceFromLookAt; - } - } -} - -void EditorCameraController::Moving() -{ - if (m_isMoving) - { - if (cd::Math::IsSmallThan((m_eye - m_eyeDestination).Length(), 0.01f)) - { - m_isMoving = false; - return; - } - cd::Direction eyeMove = (m_eye - m_eyeDestination).Normalize(); - float stepDistance = (m_eye - m_eyeDestination).Length() / 5.0f; - m_eye = m_eye - eyeMove * stepDistance; - - SynchronizeTrackingCamera(); - ControllerToCamera(); - } -} - -void EditorCameraController::Panning(float x, float y) -{ - MoveLeft(x); - m_eye = m_eye + m_up * y; -} - -void EditorCameraController::MoveToPosition(cd::Point position, cd::Vec3f rotation) -{ - m_isMoving = true; - m_eyeDestination = position; - cd::Vec3f lookAt = cd::Quaternion::FromPitchYawRoll(rotation.x(), rotation.y(), rotation.z()) * cd::Vec3f(0.0f, 0.0f, 1.0f); - m_lookAtDestination = lookAt.Normalize(); -} - -} \ No newline at end of file diff --git a/Engine/Source/Editor/Camera/ViewportCameraController.cpp b/Engine/Source/Editor/Camera/ViewportCameraController.cpp new file mode 100644 index 00000000..0b44a2f2 --- /dev/null +++ b/Engine/Source/Editor/Camera/ViewportCameraController.cpp @@ -0,0 +1,521 @@ +#include "ViewportCameraController.h" + +#include "ECWorld/CameraComponent.h" +#include "ECWorld/SceneWorld.h" +#include "Math/Quaternion.hpp" +#include "Window/Input.h" + +#include +#include + +#include +#include + +namespace engine +{ + +ViewportCameraController::ViewportCameraController( + const SceneWorld* pSceneWorld, + float sensitivity, + float movement_speed) + : ViewportCameraController(pSceneWorld, sensitivity, sensitivity, movement_speed) +{ +} + +ViewportCameraController::ViewportCameraController( + const SceneWorld* pSceneWorld, + float horizontal_sensitivity, + float vertical_sensitivity, + float movement_speed) + : m_pSceneWorld(pSceneWorld) + , m_horizontalSensitivity(horizontal_sensitivity) + , m_verticalSensitivity(vertical_sensitivity) + , m_movementSpeed(movement_speed) + , m_initialMovemenSpeed(movement_speed) +{ + assert(pSceneWorld); +} + +bool ViewportCameraController::IsInAnimation() const +{ + return m_isFocusing; +} + +bool ViewportCameraController::IsZooming() const +{ + if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) + { + return Input::Get().GetMousePositionOffsetY() != 0.0f; + } + + return Input::Get().GetMouseScrollOffsetY() != 0.0f; +} + +bool ViewportCameraController::IsPanning() const +{ + return ImGui::IsMouseDown(ImGuiMouseButton_Middle); +} + +bool ViewportCameraController::IsTurning() const +{ + if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) + { + // Offset Y is used to zoom in/out when left mouse button down. + return Input::Get().GetMousePositionOffsetX() != 0.0f; + } + + if (ImGui::IsMouseDown(ImGuiMouseButton_Right)) + { + return Input::Get().GetMousePositionOffsetX() != 0.0f || Input::Get().GetMousePositionOffsetY() != 0.0f; + } + + return false; +} + +bool ViewportCameraController::IsTracking() const +{ + return ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsKeyDown(ImGuiKey_Z); +} + +bool ViewportCameraController::IsInWalkMode() const +{ + return m_isInWalkMode; +} + +void ViewportCameraController::OnMouseDown() +{ + if (ImGui::IsAnyMouseDown()) + { + m_isInWalkMode = true; + } + + CameraToController(); +} + +void ViewportCameraController::OnMouseUp() +{ + m_isInWalkMode = false; +} + +void ViewportCameraController::OnMouseMove(float x, float y) +{ + bool dirty = false; + if (IsZooming()) + { + Zoom(y); + dirty = true; + } + + if (dirty) + { + ControllerToCamera(); + } +} + +void ViewportCameraController::OnMouseWheel(float y) +{ + bool dirty = false; + if (IsZooming()) + { + Zoom(y); + dirty = true; + } + + if (dirty) + { + ControllerToCamera(); + } +} + +void ViewportCameraController::Update(float deltaTime) +{ + if (IsInAnimation()) + { + // Camera is focusing an entity automatically. + return; + } + + float offsetX = static_cast(Input::Get().GetMousePositionOffsetX()); + float offsetY = static_cast(Input::Get().GetMousePositionOffsetY()); + if (offsetX != 0.0f || offsetY != 0.0f) + { + OnMouseMove(offsetX, offsetY); + } + + float scrollY = Input::Get().GetMouseScrollOffsetY(); + if (scrollY != 0.0f) + { + OnMouseWheel(scrollY); + } + + //if (ImGui::IsMouseDown(ImGuiMouseButton_Middle)) + //{ + // m_isTracking = false; + // float dx = Input::Get().GetMousePositionOffsetX() * deltaTime * m_movementSpeed / 4.0f; + // float dy = Input::Get().GetMousePositionOffsetY() * deltaTime * m_movementSpeed / 4.0f; + // Panning(dx, dy); + //} + + //if (ImGui::IsKeyPressed(ImGuiKey_Z, false)) + //{ + // // TODO : Only need to happen once in the first time press z. + // SynchronizeTrackingCamera(); + // + // if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !m_isMoving) + // { + // m_isTracking = true; + // ElevationChanging(m_verticalSensitivity * Input::Get().GetMousePositionOffsetY() * deltaTime); + // AzimuthChanging(-m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); + // } + // + // if (ImGui::IsMouseDown(ImGuiMouseButton_Right)) + // { + // float scaleDelta = (Input::Get().GetMousePositionOffsetX() - Input::Get().GetMousePositionOffsetY()) * deltaTime * m_movementSpeed; + // m_distanceFromLookAt -= scaleDelta; + // m_eye = m_eye + m_lookAt * scaleDelta; + // ControllerToCamera(); + // } + // + // return; + //} + //if (ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::IsMouseDown(ImGuiMouseButton_Middle)) + //{ + // if (Input::Get().GetMouseScrollOffsetY()) + // { + // float speedRate = std::pow(2.0f, Input::Get().GetMouseScrollOffsetY() / 10.0f); + // m_movementSpeed = speedRate * m_movementSpeed; + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_W) && !m_isMoving) + // { + // m_isTracking = false; + // MoveForward(m_movementSpeed * deltaTime); + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_A) && !m_isMoving) + // { + // m_isTracking = false; + // MoveLeft(m_movementSpeed * deltaTime); + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_S) && !m_isMoving) + // { + // m_isTracking = false; + // MoveBackward(m_movementSpeed * deltaTime); + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_D) && !m_isMoving) + // { + // m_isTracking = false; + // MoveRight(m_movementSpeed * deltaTime); + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_E)) + // { + // m_isTracking = false; + // MoveDown(m_movementSpeed * deltaTime); + // } + // + // if (ImGui::IsKeyPressed(ImGuiKey_Q) && !m_isMoving) + // { + // m_isTracking = false; + // MoveUp(m_movementSpeed * deltaTime); + // } + //} + // + // + //if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && !m_isMoving) + //{ + // m_isTracking = false; + // Yaw(m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); + //} + // + //if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGuizmo::IsUsing()) + //{ + // m_isTracking = false; + // PitchLocal(m_verticalSensitivity * Input::Get().GetMousePositionOffsetY() * deltaTime); + // Yaw(m_horizontalSensitivity * Input::Get().GetMousePositionOffsetX() * deltaTime); + //} +} + +void ViewportCameraController::CameraToController() +{ + m_eye = GetMainCameraTransform().GetTranslation(); + m_lookAt = CameraComponent::GetLookAt(GetMainCameraTransform()); + m_up = CameraComponent::GetUp(GetMainCameraTransform()); +} + +void ViewportCameraController::ControllerToCamera() +{ + cd::Vec3f eye = m_eye; + cd::Vec3f lookAt = m_lookAt; + cd::Vec3f up = m_up; + + if (m_isTracking) + { + float sinPhi = std::sin(m_elevation); + float cosPhi = std::cos(m_elevation); + float sinTheta = std::sin(m_azimuth); + float cosTheta = std::cos(m_azimuth); + + lookAt = cd::Vec3f(-cosPhi * sinTheta, -sinPhi, -cosPhi * cosTheta); + lookAt.Normalize(); + cd::Vec3f cross = cd::Vec3f(cosTheta, 0.0f, -sinTheta); + up = cross.Cross(lookAt); + + float lookAtOffset = 0.0f; + if (m_distanceFromLookAt < m_dollyThreshold) + { + lookAtOffset = m_distanceFromLookAt - m_dollyThreshold; + } + + float eyeOffset = m_distanceFromLookAt; + eye = m_lookAtPoint - (lookAt * eyeOffset); + + // Synchronize view to fps camera + m_eye = eye; + m_lookAt = lookAt; + m_up = up; + } + + GetMainCameraComponent()->BuildViewMatrix(eye, lookAt, up); + TransformComponent* pTransformComponent = GetMainCameraTransformComponent(); + pTransformComponent->GetTransform().SetTranslation(eye); + + cd::Vec3f rotationAxis = cd::Vec3f(0.0f, 0.0f,1.0f).Cross(lookAt).Normalize(); + float rotationAngle = std::acos(cd::Vec3f(0.0f, 0.0f, 1.0f).Dot(lookAt)); + pTransformComponent->GetTransform().SetRotation(cd::Quaternion::FromAxisAngle(rotationAxis, rotationAngle)); + pTransformComponent->Build(); +} + +void ViewportCameraController::SetMovementSpeed(float speed) +{ + m_movementSpeed = speed; +} + +void ViewportCameraController::SetSensitivity(float horizontal, float verticle) +{ + m_horizontalSensitivity = horizontal; + m_verticalSensitivity = verticle; +} + +void ViewportCameraController::SetHorizontalSensitivity(float sensitivity) +{ + m_horizontalSensitivity = sensitivity; +} + +void ViewportCameraController::SetVerticalSensitivity(float sensitivity) +{ + m_verticalSensitivity = sensitivity; +} + +engine::CameraComponent* ViewportCameraController::GetMainCameraComponent() const +{ + return m_pSceneWorld->GetCameraComponent(m_pSceneWorld->GetMainCameraEntity()); +} + +engine::TransformComponent* ViewportCameraController::GetMainCameraTransformComponent() const +{ + return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity()); +} + +const cd::Transform& ViewportCameraController::GetMainCameraTransform() +{ + return m_pSceneWorld->GetTransformComponent(m_pSceneWorld->GetMainCameraEntity())->GetTransform(); +} + +void ViewportCameraController::MoveForward(float amount) +{ + m_eye = m_eye + m_lookAt * amount; + ControllerToCamera(); +} + +void ViewportCameraController::MoveBackward(float amount) +{ + MoveForward(-amount); +} + +void ViewportCameraController::MoveLeft(float amount) +{ + m_eye = m_eye + m_lookAt.Cross(m_up) * amount; + ControllerToCamera(); +} + +void ViewportCameraController::MoveRight(float amount) +{ + MoveLeft(-amount); +} + +void ViewportCameraController::MoveUp(float amount) +{ + m_eye = m_eye + cd::Vec3f(0.0f, 1.0f, 0.0f) * amount; + ControllerToCamera(); +} + +void ViewportCameraController::MoveDown(float amount) +{ + MoveUp(-amount); +} + +void ViewportCameraController::Rotate(const cd::Vec3f& axis, float angleDegrees) +{ + cd::Quaternion rotation = cd::Quaternion::FromAxisAngle(axis, cd::Math::DegreeToRadian(angleDegrees)); + m_lookAt = rotation * m_lookAt; + m_up = rotation * m_up; + ControllerToCamera(); +} + +void ViewportCameraController::Rotate(float x, float y, float z, float angleDegrees) +{ + Rotate(cd::Vec3f(x, y, z), angleDegrees); +} + +void ViewportCameraController::Yaw(float angleDegrees) +{ + Rotate(0.0f, 1.0f, 0.0f, angleDegrees); +} + +void ViewportCameraController::Pitch(float angleDegrees) +{ + Rotate(1.0f, 0.0f, 0.0f, angleDegrees); +} + +void ViewportCameraController::Roll(float angleDegrees) +{ + Rotate(0.0f, 0.0f, 1.0f, angleDegrees); +} + +void ViewportCameraController::YawLocal(float angleDegrees) +{ + Rotate(m_up, angleDegrees); +} + +void ViewportCameraController::PitchLocal(float angleDegrees) +{ + Rotate(m_up.Cross(m_lookAt), angleDegrees); +} + +void ViewportCameraController::RollLocal(float angleDegrees) +{ + Rotate(m_lookAt, angleDegrees); +} + +void ViewportCameraController::ElevationChanging(float angleDegrees) +{ + m_elevation += angleDegrees / 360.0f * cd::Math::PI; + if (m_elevation > cd::Math::PI) + { + m_elevation -= cd::Math::TWO_PI; + } + else if (m_elevation < -cd::Math::PI) + { + m_elevation += cd::Math::TWO_PI; + } + ControllerToCamera(); +} + +void ViewportCameraController::AzimuthChanging(float angleDegrees) +{ + m_azimuth -= angleDegrees / 360.0f * cd::Math::PI; + if (m_azimuth > cd::Math::PI) + { + m_azimuth -= cd::Math::TWO_PI; + } + else if (m_azimuth < -cd::Math::PI) + { + m_azimuth += cd::Math::TWO_PI; + } + ControllerToCamera(); +} + +void ViewportCameraController::SynchronizeTrackingCamera() +{ + m_lookAtPoint = m_lookAt * m_distanceFromLookAt + m_eye; + m_elevation = std::asin(-m_lookAt.y()); + + if (cd::Math::IsSmallThanZero(m_up.y())) + { + if (cd::Math::IsLargeThanZero(m_lookAt.y())) + { + m_elevation = -cd::Math::PI - m_elevation; + } + else + { + m_elevation = cd::Math::PI - m_elevation; + m_azimuth = std::atan2(m_lookAt.x(), m_lookAt.z()); + } + } + else + { + m_azimuth = std::atan2(-m_lookAt.x(), -m_lookAt.z()); + } +} + +void ViewportCameraController::CameraFocus() +{ + Entity selectedEntity = m_pSceneWorld->GetSelectedEntity(); + if (selectedEntity == INVALID_ENTITY) + { + return; + } + + if (TransformComponent* pTransform = m_pSceneWorld->GetTransformComponent(selectedEntity)) + { + m_isFocusing = true; + if (CollisionMeshComponent* pCollisionMesh = m_pSceneWorld->GetCollisionMeshComponent(selectedEntity)) + { + cd::AABB meshAABB = pCollisionMesh->GetAABB(); + meshAABB = meshAABB.Transform(pTransform->GetWorldMatrix()); + m_distanceFromLookAt = (meshAABB.Max() - meshAABB.Center()).Length() * 3.0f; + m_eyeDestination = meshAABB.Center() - m_lookAt * m_distanceFromLookAt; + m_movementSpeed = meshAABB.Size().Length() * 1.5f; + } + else + { + m_eyeDestination = pTransform->GetTransform().GetTranslation() - m_lookAt * m_distanceFromLookAt; + } + } +} + +void ViewportCameraController::Focusing() +{ + if (m_isFocusing) + { + if (cd::Math::IsSmallThan((m_eye - m_eyeDestination).Length(), 0.01f)) + { + m_isFocusing = false; + } + else + { + cd::Direction eyeMove = (m_eye - m_eyeDestination).Normalize(); + float stepDistance = (m_eye - m_eyeDestination).Length() / 5.0f; + m_eye = m_eye - eyeMove * stepDistance; + + SynchronizeTrackingCamera(); + ControllerToCamera(); + } + } +} + +void ViewportCameraController::Zoom(float delta) +{ + float scaleDelta = delta * m_movementSpeed; + m_distanceFromLookAt -= scaleDelta; + m_eye = m_eye + m_lookAt * scaleDelta; +} + +void ViewportCameraController::Panning(float x, float y) +{ + MoveLeft(x); + m_eye = m_eye + m_up * y; +} + +void ViewportCameraController::MoveToPosition(cd::Point position, cd::Vec3f rotation) +{ + m_isFocusing = true; + m_eyeDestination = position; + cd::Vec3f lookAt = cd::Quaternion::FromPitchYawRoll(rotation.x(), rotation.y(), rotation.z()) * cd::Vec3f(0.0f, 0.0f, 1.0f); + m_lookAtDestination = lookAt.Normalize(); +} + +} \ No newline at end of file diff --git a/Engine/Source/Editor/Camera/EditorCameraController.h b/Engine/Source/Editor/Camera/ViewportCameraController.h similarity index 66% rename from Engine/Source/Editor/Camera/EditorCameraController.h rename to Engine/Source/Editor/Camera/ViewportCameraController.h index 017ca928..64438ef1 100644 --- a/Engine/Source/Editor/Camera/EditorCameraController.h +++ b/Engine/Source/Editor/Camera/ViewportCameraController.h @@ -1,5 +1,6 @@ #pragma once +#include "Camera/ICameraController.h" #include "ECWorld/TransformComponent.h" #include "Math/Box.hpp" #include "Math/Transform.hpp" @@ -10,20 +11,48 @@ namespace engine class CameraComponent; class SceneWorld; -class EditorCameraController final +class ViewportCameraController : public ICameraController { public: - EditorCameraController() = delete; - explicit EditorCameraController(const SceneWorld* pSceneWorld, float sensitivity, float movement_speed); - explicit EditorCameraController(const SceneWorld* pSceneWorld, float horizontal_sensitivity, float vertical_sensitivity, float movement_speed); - ~EditorCameraController() = default; + ViewportCameraController() = delete; + explicit ViewportCameraController(const SceneWorld* pSceneWorld, float sensitivity, float movement_speed); + explicit ViewportCameraController(const SceneWorld* pSceneWorld, float horizontal_sensitivity, float vertical_sensitivity, float movement_speed); + ~ViewportCameraController() = default; + + ViewportCameraController(const ViewportCameraController&) = delete; + ViewportCameraController(ViewportCameraController&&) = delete; + ViewportCameraController& operator=(const ViewportCameraController&) = delete; + ViewportCameraController& operator=(ViewportCameraController&&) = delete; + + // Operations + virtual bool IsInAnimation() const override; + virtual bool IsZooming() const override; + virtual bool IsPanning() const override; + virtual bool IsTurning() const override; + virtual bool IsTracking() const override; + virtual bool IsInWalkMode() const override; + + // Event Handlers + virtual void OnMouseDown() override; + virtual void OnMouseUp() override; + virtual void OnMouseMove(float x, float y) override; + virtual void OnMouseWheel(float y) override; + + // TODO : EventDriven, not update. + void Update(float deltaTime); - EditorCameraController(const EditorCameraController&) = delete; - EditorCameraController(EditorCameraController&&) = delete; - EditorCameraController& operator=(const EditorCameraController&) = delete; - EditorCameraController& operator=(EditorCameraController&&) = delete; + // Synchronizes the controller to the transform of camera current state + void CameraToController(); - void Update(float deltaTime); + // Synchronizes the transform of camera to the controller's current state + void ControllerToCamera(); + + // Implement the effect of a translation animation. + void CameraFocus(); + void Focusing(); + + // + void Zoom(float delta); // Configs void SetMovementSpeed(float speed); @@ -53,16 +82,7 @@ class EditorCameraController final void AzimuthChanging(float amount); void ElevationChanging(float amount); - // Double Click entity,camera will focus - void CameraFocus(); - // Implement the effect of a translation animation. - void Moving(); - - // Synchronizes the controller to the transform of camera current state - void CameraToController(); - // Synchronizes the transform of camera to the controller's current state - void ControllerToCamera(); // Synchronize view when begin using mayastyle camera or fpscamera void SynchronizeTrackingCamera(); @@ -97,8 +117,8 @@ class EditorCameraController final cd::Vec3f m_lookAtDestination; bool m_isTracking = false; - bool m_isMoving = false; - bool m_isMouseMovedInView = false; + bool m_isFocusing = false; + bool m_isInWalkMode = false; }; } \ No newline at end of file diff --git a/Engine/Source/Editor/EditorApp.cpp b/Engine/Source/Editor/EditorApp.cpp index 54a4111a..4f7e48c1 100644 --- a/Engine/Source/Editor/EditorApp.cpp +++ b/Engine/Source/Editor/EditorApp.cpp @@ -1,7 +1,7 @@ #include "EditorApp.h" #include "Application/Engine.h" -#include "Camera/EditorCameraController.h" +#include "Camera/ViewportCameraController.h" #include "ECWorld/SceneWorld.h" #include "ImGui/ImGuiContextInstance.h" #include "ImGui/ImGuiContextManager.h" @@ -58,6 +58,23 @@ //#include #include +namespace +{ + +void OnEnterSceneView() +{ + auto* pWindowManager = static_cast(ImGui::GetIO().BackendPlatformUserData); + pWindowManager->SetCursor(engine::MouseCursorType::Crosshair); +} + +void OnLeaveSceneView() +{ + auto* pWindowManager = static_cast(ImGui::GetIO().BackendPlatformUserData); + pWindowManager->SetCursor(engine::MouseCursorType::Arrow); +} + +} + namespace editor { @@ -164,7 +181,7 @@ void EditorApp::InitEditorImGuiContext(engine::Language language) assert(GetMainWindow() && "Init window before imgui context"); m_pEditorImGuiContext = m_pImGuiContextManager->AddImGuiContext(engine::StringCrc("Editor")); - m_pEditorImGuiContext->InitBackendUserData(GetMainWindow(), m_pRenderContext.get()); + m_pEditorImGuiContext->InitBackendUserData(m_pWindowManager.get(), m_pRenderContext.get()); m_pEditorImGuiContext->SetDisplaySize(GetMainWindow()->GetWidth(), GetMainWindow()->GetHeight()); m_pEditorImGuiContext->LoadFontFiles({ "FanWunMing-SB.ttf" }, language); m_pEditorImGuiContext->SetImGuiThemeColor(engine::ThemeColor::Dark); @@ -174,7 +191,7 @@ void EditorApp::InitEditorImGuiContext(engine::Language language) // Init viewport settings. if (m_pEditorImGuiContext->IsViewportEnable()) { - m_pEditorImGuiContext->InitViewport(m_pWindowManager.get(), m_pRenderContext.get()); + m_pEditorImGuiContext->InitViewport(); ImGuiViewport* pMainViewport = ImGui::GetMainViewport(); assert(pMainViewport); pMainViewport->PlatformHandle = GetMainWindow(); @@ -228,12 +245,15 @@ void EditorApp::InitEngineImGuiContext(engine::Language language) engine::RenderTarget* pSceneRenderTarget = m_pRenderContext->GetRenderTarget(sceneRenderTarget); m_pEngineImGuiContext = m_pImGuiContextManager->AddImGuiContext(engine::StringCrc("Engine")); - m_pEngineImGuiContext->InitBackendUserData(GetMainWindow(), m_pRenderContext.get()); + m_pEngineImGuiContext->InitBackendUserData(m_pWindowManager.get(), m_pRenderContext.get()); m_pEngineImGuiContext->SetDisplaySize(pSceneRenderTarget->GetWidth(), pSceneRenderTarget->GetHeight()); m_pEngineImGuiContext->LoadFontFiles({ "FanWunMing-SB.ttf" }, language); m_pEngineImGuiContext->SetImGuiThemeColor(engine::ThemeColor::Light); pSceneRenderTarget->OnResize.Bind(m_pEngineImGuiContext); + + m_pEngineImGuiContext->OnMouseEnterDisplayRect.Bind(); + m_pEngineImGuiContext->OnMouseLeaveDisplayRect.Bind(); } void EditorApp::InitEngineUILayers() @@ -545,7 +565,7 @@ void EditorApp::InitShaderPrograms(bool compileAllShaders) const void EditorApp::InitEditorController() { // Controller for Input events. - m_pViewportCameraController = std::make_unique( + m_pViewportCameraController = std::make_unique( m_pSceneWorld.get(), 12.0f /* horizontal sensitivity */, 12.0f /* vertical sensitivity */); @@ -623,7 +643,7 @@ bool EditorApp::Update(float deltaTime) } } - auto [sceneRectX, sceneRectY] = m_pSceneView->GetRectPosition(); + auto [sceneRectX, sceneRectY] = m_pSceneView->GetWorkRectPosition(); m_pEditorImGuiContext->EndFrame(); if (m_pEngineImGuiContext) @@ -685,33 +705,6 @@ bool EditorApp::Update(float deltaTime) void EditorApp::InitWindowManager() { m_pWindowManager = std::make_unique(); - m_pWindowManager->OnMouseMove.Bind(this); -} - -void EditorApp::HandleMouseMotionEvent(uint32_t windowID, int x, int y) -{ - engine::Input::Get().SetMousePositionX(x); - engine::Input::Get().SetMousePositionY(y); - - //auto [screenX, screenY] = engine::Input::GetGloalMousePosition(); - ////auto* pWindow = m_pWindowManager->GetWindow(windowID); - //for (auto& [_, pImGuiContext] : m_pImGuiContextManager->GetAllImGuiContexts()) - //{ - // if (pImGuiContext->IsViewportEnable()) - // { - // // In multiple viewport mode, it always use global screen space coordinates. - // engine::Input::Get().SetMousePositionX(screenX); - // engine::Input::Get().SetMousePositionY(screenY); - // } - // else - // { - // if (pImGuiContext->IsInsideDisplayRect()) - // { - // engine::Input::Get().SetMousePositionX(x); - // engine::Input::Get().SetMousePositionY(y); - // } - // } - //} } } diff --git a/Engine/Source/Editor/EditorApp.h b/Engine/Source/Editor/EditorApp.h index dd6bfedc..01839044 100644 --- a/Engine/Source/Editor/EditorApp.h +++ b/Engine/Source/Editor/EditorApp.h @@ -10,7 +10,7 @@ namespace engine { class AABBRenderer; -class EditorCameraController; +class ViewportCameraController; class FlybyCamera; class ImGuiBaseLayer; class ImGuiContextInstance; @@ -51,7 +51,6 @@ class EditorApp final : public engine::IApplication void InitWindowManager(); engine::Window* GetMainWindow() const { return m_pMainWindow; } engine::WindowManager* GetWindowManager() const { return m_pWindowManager.get(); } - void HandleMouseMotionEvent(uint32_t windowID, int x, int y); // Rendering Management void InitRenderContext(engine::GraphicsBackend backend, void* hwnd = nullptr); @@ -119,7 +118,7 @@ class EditorApp final : public engine::IApplication engine::Renderer* m_pAABBRenderer = nullptr; // Controllers for processing input events. - std::unique_ptr m_pViewportCameraController; + std::unique_ptr m_pViewportCameraController; std::unique_ptr m_pFileWatcher; }; diff --git a/Engine/Source/Editor/UILayers/EntityList.cpp b/Engine/Source/Editor/UILayers/EntityList.cpp index 837d5c80..e6e4fa13 100644 --- a/Engine/Source/Editor/UILayers/EntityList.cpp +++ b/Engine/Source/Editor/UILayers/EntityList.cpp @@ -1,6 +1,6 @@ #include "EntityList.h" -#include "Camera/EditorCameraController.h" +#include "Camera/ViewportCameraController.h" #include "ECWorld/SceneWorld.h" #include "ECWorld/World.h" #include "ImGui/IconFont/IconsMaterialDesignIcons.h" diff --git a/Engine/Source/Editor/UILayers/EntityList.h b/Engine/Source/Editor/UILayers/EntityList.h index b62cda50..735857bb 100644 --- a/Engine/Source/Editor/UILayers/EntityList.h +++ b/Engine/Source/Editor/UILayers/EntityList.h @@ -10,7 +10,7 @@ namespace engine { -class EditorCameraController; +class ViewportCameraController; class SceneWorld; } @@ -30,11 +30,11 @@ class EntityList : public engine::ImGuiBaseLayer void AddEntity(engine::SceneWorld* pSceneWorld); void DrawEntity(engine::SceneWorld* pSceneWorld, engine::Entity entity); - void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } + void SetCameraController(engine::ViewportCameraController* pCameraController) { m_pCameraController = pCameraController; } private: ImGuiTextFilter m_entityFilter; - engine::EditorCameraController* m_pCameraController = nullptr; + engine::ViewportCameraController* m_pCameraController = nullptr; }; } diff --git a/Engine/Source/Editor/UILayers/Inspector.cpp b/Engine/Source/Editor/UILayers/Inspector.cpp index 64535630..beea6a57 100644 --- a/Engine/Source/Editor/UILayers/Inspector.cpp +++ b/Engine/Source/Editor/UILayers/Inspector.cpp @@ -360,7 +360,6 @@ void UpdateComponentWidget(engine::SceneWorld* pSceneWo ImGuiUtils::ImGuiFloatProperty("NearPlane", pCameraComponent->GetNearPlane()) || ImGuiUtils::ImGuiFloatProperty("FarPlane", pCameraComponent->GetFarPlane())) { - pCameraComponent->Dirty(); pCameraComponent->BuildProjectMatrix(); } diff --git a/Engine/Source/Editor/UILayers/MainMenu.cpp b/Engine/Source/Editor/UILayers/MainMenu.cpp index d9793c8f..f086137d 100644 --- a/Engine/Source/Editor/UILayers/MainMenu.cpp +++ b/Engine/Source/Editor/UILayers/MainMenu.cpp @@ -1,6 +1,6 @@ #include "MainMenu.h" -#include "Camera/EditorCameraController.h" +#include "Camera/ViewportCameraController.h" #include "ECWorld/SceneWorld.h" #include "EditorApp.h" #include "ImGui/ImGuiContextInstance.h" @@ -53,13 +53,13 @@ void MainMenu::FileMenu() ImGui::Separator(); - if (ImGui::MenuItem("Quit", "Ctrl Q")) - { - if (auto* pMainWindow = reinterpret_cast(ImGui::GetIO().BackendPlatformUserData)) - { - pMainWindow->Close(); - } - } + //if (ImGui::MenuItem("Quit", "Ctrl Q")) + //{ + // if (auto* pMainWindow = reinterpret_cast(ImGui::GetIO().BackendPlatformUserData)) + // { + // pMainWindow->Close(); + // } + //} ImGui::EndMenu(); } @@ -117,7 +117,7 @@ void MainMenu::EditMenu() void MainMenu::ViewMenu() { - auto FrameEntities = [](engine::SceneWorld* pSceneWorld, const std::vector& entities, engine::EditorCameraController* pCameraController) + auto FrameEntities = [](engine::SceneWorld* pSceneWorld, const std::vector& entities, engine::ViewportCameraController* pCameraController) { if (entities.empty()) { @@ -164,7 +164,6 @@ void MainMenu::ViewMenu() pTransformComponent->Dirty(); pTransformComponent->Build(); - pCameraComponent->ViewDirty(); pCameraComponent->BuildViewMatrix(pTransformComponent->GetTransform()); // TODO : add event queue to get mouse down and up events. @@ -263,14 +262,14 @@ void MainMenu::Update() m_pCreateProjectDialog->Display(); - if ((ImGui::IsKeyPressed(ImGuiKey_LeftCtrl) || ImGui::IsKeyPressed(ImGuiKey_RightCtrl)) - && ImGui::IsKeyPressed(ImGuiKey_Q)) - { - if (auto* pMainWindow = reinterpret_cast(ImGui::GetIO().BackendPlatformUserData)) - { - pMainWindow->Close(); - } - } + //if ((ImGui::IsKeyPressed(ImGuiKey_LeftCtrl) || ImGui::IsKeyPressed(ImGuiKey_RightCtrl)) + // && ImGui::IsKeyPressed(ImGuiKey_Q)) + //{ + // if (auto* pMainWindow = reinterpret_cast(ImGui::GetIO().BackendPlatformUserData)) + // { + // pMainWindow->Close(); + // } + //} } } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/MainMenu.h b/Engine/Source/Editor/UILayers/MainMenu.h index ca8817f6..200d9ab7 100644 --- a/Engine/Source/Editor/UILayers/MainMenu.h +++ b/Engine/Source/Editor/UILayers/MainMenu.h @@ -14,7 +14,7 @@ class FileBrowser; namespace engine { -class EditorCameraController; +class ViewportCameraController; } @@ -37,11 +37,11 @@ class MainMenu : public engine::ImGuiBaseLayer void BuildMenu(); void AboutMenu(); - void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } + void SetCameraController(engine::ViewportCameraController* pCameraController) { m_pCameraController = pCameraController; } private: std::unique_ptr m_pCreateProjectDialog; - engine::EditorCameraController* m_pCameraController = nullptr; + engine::ViewportCameraController* m_pCameraController = nullptr; }; } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/SceneView.cpp b/Engine/Source/Editor/UILayers/SceneView.cpp index c8a5b96f..2a19d485 100644 --- a/Engine/Source/Editor/UILayers/SceneView.cpp +++ b/Engine/Source/Editor/UILayers/SceneView.cpp @@ -299,7 +299,13 @@ void SceneView::Update() UpdateToolMenuButtons(); // Check if need to resize scene view. + ImVec2 currentPos = GetRootWindow()->DC.CursorPos; ImVec2 regionSize = ImGui::GetContentRegionAvail(); + m_workRectPosX = currentPos.x; + m_workRectPosY = currentPos.y; + m_workRectWidth = regionSize.x; + m_workRectHeight = regionSize.y; + uint16_t regionWidth = static_cast(regionSize.x); uint16_t regionHeight = static_cast(regionSize.y); if (regionWidth != m_lastContentWidth || regionHeight != m_lastContentHeight) @@ -312,6 +318,7 @@ void SceneView::Update() if (!pCameraComponent->DoConstrainAspectRatio()) { pCameraComponent->SetAspect(static_cast(regionWidth) / static_cast(regionHeight)); + pCameraComponent->BuildProjectMatrix(); } } @@ -322,59 +329,10 @@ void SceneView::Update() ImGui::PopStyleVar(); ImGui::End(); - if (!ImGuizmo::IsUsing()) - { - bool isAnyMouseButtonDraging = ImGui::IsMouseDragging(ImGuiMouseButton_Left) || ImGui::IsMouseDragging(ImGuiMouseButton_Middle) || ImGui::IsMouseDragging(ImGuiMouseButton_Right); - if (isAnyMouseButtonDraging) - { - m_pCameraController; - } - } - - if (m_currentOperation == SelectOperation && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) + if (m_currentOperation == SelectOperation && ImGui::IsMouseDown(ImGuiMouseButton_Left)) { PickSceneMesh(regionWidth, regionHeight); } - - //if (isAnyMouseButtonPressed && !ImGuizmo::IsUsing()) - //{ - // if (!m_isMouseDownFirstTime) - // { - // if (m_pCameraController->GetViewIsMoved()) - // { - // m_isUsingCamera = true; - // } - // if (engine::Input::Get().IsMouseLBPressed()) - // { - // m_isLeftClick = true; - // } - // return; - // } - // - // m_isMouseDownFirstTime = false; - // if (isMouseInsideSeneView && !m_isTerrainEditMode) - // { - // m_pCameraController->SetIsInViewScene(true); - // m_isMouseShow = false; - // } - // else - // { - // m_pCameraController->SetIsInViewScene(false); - // } - //} - //else - //{ - // m_mouseFixedPositionX = engine::Input::Get().GetMousePositionX(); - // m_mouseFixedPositionY = engine::Input::Get().GetMousePositionY(); - // if (!m_isMouseShow && !m_isUsingCamera) - // { - // PickSceneMesh(regionWidth, regionHeight); - // } - // m_isMouseDownFirstTime = true; - // m_isMouseShow = true; - // m_isUsingCamera = false; - // m_isLeftClick = false; - //} if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && engine::INVALID_ENTITY != pSceneWorld->GetSelectedEntity()) @@ -383,4 +341,14 @@ void SceneView::Update() } } +std::pair SceneView::GetWorkRectPosition() const +{ + return std::make_pair(m_workRectPosX, m_workRectPosY); +} + +std::pair SceneView::GetWorkRectSize() const +{ + return std::make_pair(m_workRectWidth, m_workRectHeight); +} + } \ No newline at end of file diff --git a/Engine/Source/Editor/UILayers/SceneView.h b/Engine/Source/Editor/UILayers/SceneView.h index 783f777a..9e4f2e8f 100644 --- a/Engine/Source/Editor/UILayers/SceneView.h +++ b/Engine/Source/Editor/UILayers/SceneView.h @@ -1,6 +1,6 @@ #pragma once -#include "Camera/EditorCameraController.h" +#include "Camera/ViewportCameraController.h" #include "Core/Delegates/MulticastDelegate.hpp" #include "ECWorld/Entity.h" #include "ImGui/ImGuiBaseLayer.h" @@ -52,6 +52,9 @@ class SceneView : public engine::ImGuiBaseLayer virtual void Init() override; virtual void Update() override; + virtual std::pair GetWorkRectPosition() const override; + virtual std::pair GetWorkRectSize() const override; + engine::MulticastDelegate OnResize; void PickSceneMesh(float regionWidth, float regionHeight); @@ -66,7 +69,7 @@ class SceneView : public engine::ImGuiBaseLayer bool IsTerrainEditMode() const { return m_isTerrainEditMode; } - void SetCameraController(engine::EditorCameraController* pCameraController) { m_pCameraController = pCameraController; } + void SetCameraController(engine::ViewportCameraController* pCameraController) { m_pCameraController = pCameraController; } const engine::RenderTarget* GetRenderTarget() const { return m_pRenderTarget; } private: @@ -83,6 +86,11 @@ class SceneView : public engine::ImGuiBaseLayer ImGuizmo::OPERATION m_currentOperation; + float m_workRectPosX = 0.0f; + float m_workRectPosY = 0.0f; + float m_workRectWidth = 1.0f; + float m_workRectHeight = 1.0f; + bool m_is3DMode = true; bool m_isIBLActive = false; bool m_isTerrainEditMode = false; @@ -94,7 +102,7 @@ class SceneView : public engine::ImGuiBaseLayer engine::Renderer* m_pAABBRenderer = nullptr; engine::RenderTarget* m_pRenderTarget = nullptr; - engine::EditorCameraController* m_pCameraController = nullptr; + engine::ViewportCameraController* m_pCameraController = nullptr; }; } \ No newline at end of file diff --git a/Engine/Source/Runtime/Camera/ICameraController.h b/Engine/Source/Runtime/Camera/ICameraController.h new file mode 100644 index 00000000..cf59b13f --- /dev/null +++ b/Engine/Source/Runtime/Camera/ICameraController.h @@ -0,0 +1,33 @@ +#pragma once + +namespace engine +{ + +class ICameraController +{ +public: + ICameraController() = default; + ICameraController(const ICameraController&) = default; + ICameraController(ICameraController&&) = default; + ICameraController& operator=(const ICameraController&) = default; + ICameraController& operator=(ICameraController&&) = default; + virtual ~ICameraController() = default; + + // Operations + virtual bool IsInAnimation() const { return false; } + virtual bool IsZooming() const { return false; } + virtual bool IsFOVZooming() const { return false; } + virtual bool IsPanning() const { return false; } + virtual bool IsTurning() const { return false; } + virtual bool IsTracking() const { return false; } + virtual bool IsInWalkMode() const { return false; } + virtual bool IsControling() const { return IsInAnimation() || IsZooming() || IsFOVZooming() || IsPanning() || IsTurning() || IsTracking() || IsInWalkMode(); } + + // Event Handlers + virtual void OnMouseDown() {} + virtual void OnMouseUp() {} + virtual void OnMouseMove(float x, float y) {} + virtual void OnMouseWheel(float y) {} +}; + +} \ No newline at end of file diff --git a/Engine/Source/Runtime/Core/Delegates/Delegate.hpp b/Engine/Source/Runtime/Core/Delegates/Delegate.hpp index 6708b758..697f67ff 100644 --- a/Engine/Source/Runtime/Core/Delegates/Delegate.hpp +++ b/Engine/Source/Runtime/Core/Delegates/Delegate.hpp @@ -73,7 +73,12 @@ class Delegate RetVal Invoke(Args... args) const { - assert(m_pProxyFunc != nullptr && "Cannot invoke unbound Delegate. Call Bind() first."); + if (!m_pProxyFunc) + { + //assert(m_pProxyFunc != nullptr && "Cannot invoke unbound Delegate. Call Bind() first."); + return; + } + return m_pProxyFunc(m_pInstance, std::forward(args)...); } diff --git a/Engine/Source/Runtime/Core/OS/DllUtils.cpp b/Engine/Source/Runtime/Core/OS/DllUtils.cpp index 871b6480..782e039d 100644 --- a/Engine/Source/Runtime/Core/OS/DllUtils.cpp +++ b/Engine/Source/Runtime/Core/OS/DllUtils.cpp @@ -1,6 +1,6 @@ #include "DllUtils.h" -#include "SDL.h" +#include namespace engine { diff --git a/Engine/Source/Runtime/ECWorld/CameraComponent.cpp b/Engine/Source/Runtime/ECWorld/CameraComponent.cpp index 921f7c6a..9b10a16f 100644 --- a/Engine/Source/Runtime/ECWorld/CameraComponent.cpp +++ b/Engine/Source/Runtime/ECWorld/CameraComponent.cpp @@ -5,11 +5,10 @@ namespace engine void CameraComponent::BuildViewMatrix(const cd::Transform& transform) { + cd::Vec3f eye = transform.GetTranslation(); cd::Vec3f lookAt = GetLookAt(transform).Normalize(); cd::Vec3f up = GetUp(transform).Normalize(); - cd::Vec3f eye = transform.GetTranslation(); - m_viewMatrix = cd::Matrix4x4::LookAt(eye, eye + lookAt, up); - m_projectionMatrix = cd::Matrix4x4::Perspective(m_fov, m_aspect, m_nearPlane, m_farPlane, cd::NDCDepth::MinusOneToOne == m_ndcDepth); + return BuildViewMatrix(eye, lookAt, up); } void CameraComponent::BuildViewMatrix(const cd::Vec3f& eye, const cd::Vec3f& lookAt, const cd::Vec3f& up) diff --git a/Engine/Source/Runtime/ECWorld/CameraComponent.h b/Engine/Source/Runtime/ECWorld/CameraComponent.h index 0d40d51e..3164f7ab 100644 --- a/Engine/Source/Runtime/ECWorld/CameraComponent.h +++ b/Engine/Source/Runtime/ECWorld/CameraComponent.h @@ -55,30 +55,30 @@ class CameraComponent final cd::Ray EmitRay(float screenX, float screenY, float width, float height) const; - void SetAspect(float aspect) { m_aspect = aspect; m_isProjectionDirty = true; } + void SetAspect(float aspect) { m_aspect = aspect; } void SetAspect(uint16_t width, uint16_t height) { SetAspect(static_cast(width) / static_cast(height)); } float& GetAspect() { return m_aspect; } float GetAspect() const { return m_aspect; } - void SetFov(float fov) { m_fov = fov; m_isProjectionDirty = true; } + void SetFov(float fov) { m_fov = fov; } float& GetFov() { return m_fov; } float GetFov() const { return m_fov; } - void SetNearPlane(float nearPlane) { m_nearPlane = nearPlane; m_isProjectionDirty = true; } + void SetNearPlane(float nearPlane) { m_nearPlane = nearPlane; } float& GetNearPlane() { return m_nearPlane; } float GetNearPlane() const { return m_nearPlane; } - void SetFarPlane(float farPlane) { m_farPlane = farPlane; m_isProjectionDirty = true; } + void SetFarPlane(float farPlane) { m_farPlane = farPlane; } float& GetFarPlane() { return m_farPlane; } float GetFarPlane() const { return m_farPlane; } - void SetNDCDepth(cd::NDCDepth ndcDepth) { m_ndcDepth = ndcDepth; m_isProjectionDirty = true; } + void SetNDCDepth(cd::NDCDepth ndcDepth) { m_ndcDepth = ndcDepth; } cd::NDCDepth GetNDCDepth() const { return m_ndcDepth; } // View - static cd::Vec3f GetLookAt(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(0, 0, 1); } - static cd::Vec3f GetUp(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(0, 1, 0); } - static cd::Vec3f GetCross(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(1, 0, 0); } + static cd::Vec3f GetLookAt(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(0.0f, 0.0f, 1.0f); } + static cd::Vec3f GetUp(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(0.0f, 1.0f, 0.0f); } + static cd::Vec3f GetCross(const cd::Transform& transform) { return transform.GetRotation().ToMatrix3x3() * cd::Vec3f(1.0f, 0.0f, 0.0f); } static void SetLookAt(const cd::Vec3f& lookAt, cd::Transform& transform); static void SetUp(const cd::Vec3f& up, cd::Transform& transform); static void SetCross(const cd::Vec3f& cross, cd::Transform& transform); @@ -92,10 +92,6 @@ class CameraComponent final const cd::Matrix4x4& GetProjectionMatrix() const { return m_projectionMatrix; } void BuildProjectMatrix(); - void Dirty() const { m_isViewDirty = true; m_isProjectionDirty = true; } - void ViewDirty() const { m_isViewDirty = true; } - void ProjectDirty() const { m_isProjectionDirty = true; } - #ifdef EDITOR_MODE bool& GetDoConstrainAspectRatio() { return m_doConstainAspectRatio; } bool DoConstrainAspectRatio() const { return m_doConstainAspectRatio; } @@ -161,10 +157,6 @@ class CameraComponent final float m_gammaCorrection; cd::ToneMappingMode m_toneMappingMode; - // Status - mutable bool m_isViewDirty; - mutable bool m_isProjectionDirty; - // Output cd::Matrix4x4 m_viewMatrix; cd::Matrix4x4 m_projectionMatrix; diff --git a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp index 9383e7ab..ff212b1b 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp +++ b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.cpp @@ -34,6 +34,19 @@ std::pair ImGuiBaseLayer::GetRectSize() const return std::make_pair(size.x, size.y); } +std::pair ImGuiBaseLayer::GetWorkRectPosition() const +{ + auto pos = GetRootWindow()->ContentRegionRect.Min; + return std::make_pair(pos.x, pos.y); +} + +std::pair ImGuiBaseLayer::GetWorkRectSize() const +{ + auto maxPos = GetRootWindow()->ContentRegionRect.Max; + auto minPos = GetRootWindow()->ContentRegionRect.Min; + return std::make_pair(maxPos.x - minPos.x, maxPos.y - minPos.y); +} + ImGuiContextInstance* ImGuiBaseLayer::GetImGuiContextInstance() const { return static_cast(ImGui::GetIO().UserData); diff --git a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h index 7a2c7b1c..01b7dc9f 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h +++ b/Engine/Source/Runtime/ImGui/ImGuiBaseLayer.h @@ -32,8 +32,10 @@ class ImGuiBaseLayer uint32_t GetID() const { return m_id; } ImGuiWindow* GetRootWindow() const; - std::pair GetRectPosition() const; - std::pair GetRectSize() const; + virtual std::pair GetRectPosition() const; + virtual std::pair GetRectSize() const; + virtual std::pair GetWorkRectPosition() const; + virtual std::pair GetWorkRectSize() const; void SetEnable(bool enable) { m_isEnable = enable; } bool IsEnable() const { return m_isEnable; } diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp index 5369f250..1daf3697 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.cpp @@ -180,13 +180,23 @@ ImGuiStyle& ImGuiContextInstance::GetStyle() const return m_pImGuiContext->Style; } -void ImGuiContextInstance::InitBackendUserData(void* pWindow, void* pRenderContext) +void ImGuiContextInstance::InitBackendUserData(void* pWindowManager, void* pRenderContext) { ImGuiIO& io = GetIO(); - io.BackendPlatformUserData = pWindow; + io.BackendPlatformUserData = pWindowManager; io.BackendRendererUserData = pRenderContext; } +WindowManager* ImGuiContextInstance::GetWindowManager() const +{ + return static_cast(GetIO().BackendPlatformUserData); +} + +RenderContext* ImGuiContextInstance::GetRenderContext() const +{ + return static_cast(GetIO().BackendRendererUserData); +} + /////////////////////////////////////////////////////////////////////////////////////////// /// Display /////////////////////////////////////////////////////////////////////////////////////////// @@ -345,14 +355,15 @@ bool ImGuiContextInstance::IsViewportEnable() const return GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable; } -void ImGuiContextInstance::InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext) +void ImGuiContextInstance::InitViewport() { // Register window interfaces. - static WindowManager* s_pWindowManager = pWindowManager; + static auto* s_pWindowManager = GetWindowManager(); + ImGuiPlatformIO& platformIO = GetPlatformIO(); platformIO.Platform_CreateWindow = [](ImGuiViewport* pViewport) { - auto pWindow = std::make_unique("ViewportWindow", static_cast(pViewport->Pos.x), static_cast(pViewport->Pos.y), + auto pWindow = std::make_unique("TempName", static_cast(pViewport->Pos.x), static_cast(pViewport->Pos.y), static_cast(pViewport->Size.x), static_cast(pViewport->Size.y)); bool noDecoration = pViewport->Flags & ImGuiViewportFlags_NoDecoration; pWindow->SetBordedLess(noDecoration); @@ -427,7 +438,7 @@ void ImGuiContextInstance::InitViewport(WindowManager* pWindowManager, RenderCon }; // Register rendering interfaces. - static RenderContext* s_pRenderContext = pRenderContext; + static RenderContext* s_pRenderContext = GetRenderContext(); platformIO.Renderer_CreateWindow = [](ImGuiViewport* pViewport) { pViewport->PlatformUserData = reinterpret_cast(s_pRenderContext->CreateView()); @@ -868,6 +879,13 @@ void ImGuiContextInstance::AddMouseInputEvent() { ImGuiIO& io = GetIO(); + // TODO : is this focus event for this context? + if (bool isFocused = Input::Get().IsFocused(); isFocused != m_lastFocused) + { + io.AddFocusEvent(isFocused); + m_lastFocused = isFocused; + } + float mousePosX; float mousePosY; if (IsViewportEnable()) @@ -884,13 +902,25 @@ void ImGuiContextInstance::AddMouseInputEvent() } // Filter mouse events outside of rect. - if (!IsInsideDisplayRect(mousePosX, mousePosY)) + bool isInsideDisplayRect = IsInsideDisplayRect(mousePosX, mousePosY); + if (isInsideDisplayRect != m_lastInsideDisplayRect) { - return; + if (isInsideDisplayRect) + { + OnMouseEnterDisplayRect.Invoke(); + } + else + { + OnMouseLeaveDisplayRect.Invoke(); + } + + m_lastInsideDisplayRect = isInsideDisplayRect; } - // TODO : is this focus event for this context? - io.AddFocusEvent(Input::Get().IsFocused()); + if (!isInsideDisplayRect) + { + return; + } if (mousePosX != m_lastMousePositionX || mousePosY != m_lastMousePositionY) { diff --git a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h index 73c1c077..e44dc504 100644 --- a/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h +++ b/Engine/Source/Runtime/ImGui/ImGuiContextInstance.h @@ -1,5 +1,6 @@ #pragma once +#include "Core/Delegates/Delegate.hpp" #include "Core/StringCrc.h" #include "Localization.h" #include "ThemeColor.h" @@ -42,7 +43,9 @@ class ImGuiContextInstance ImGuiStyle& GetStyle() const; void SetContextManager(ImGuiContextManager* pManager) { m_pImGuiContextManager = pManager; } ImGuiContextManager* GetContextManager() const { return m_pImGuiContextManager; } - void InitBackendUserData(void* pWindow, void* pRenderContext); + void InitBackendUserData(void* pWindowManager, void* pRenderContext); + WindowManager* GetWindowManager() const; + RenderContext* GetRenderContext() const; // Display void SetRectPosition(float x, float y) { m_rectPosX = x; m_rectPosY = y; } @@ -69,7 +72,7 @@ class ImGuiContextInstance // Viewport feature. void EnableViewport(); bool IsViewportEnable() const; - void InitViewport(WindowManager* pWindowManager, RenderContext* pRenderContext); + void InitViewport(); void UpdateViewport(); // Loop. @@ -81,6 +84,10 @@ class ImGuiContextInstance void SetSceneWorld(SceneWorld* pSceneWorld) { m_pSceneWorld = pSceneWorld; } SceneWorld* GetSceneWorld() const { return m_pSceneWorld; } + // Delegates + Delegate OnMouseEnterDisplayRect; + Delegate OnMouseLeaveDisplayRect; + private: void InitLayoutStyles(); @@ -102,6 +109,8 @@ class ImGuiContextInstance float m_rectPosX = 0.0f; float m_rectPosY = 0.0f; + bool m_lastInsideDisplayRect = false; + bool m_lastFocused = false; bool m_lastMouseLBPressed = false; bool m_lastMouseRBPressed = false; bool m_lastMouseMBPressed = false; diff --git a/Engine/Source/Runtime/Window/Input.cpp b/Engine/Source/Runtime/Window/Input.cpp index cacd6347..93078679 100644 --- a/Engine/Source/Runtime/Window/Input.cpp +++ b/Engine/Source/Runtime/Window/Input.cpp @@ -1,7 +1,8 @@ #include "Input.h" #include "Log/Log.h" -#include "SDL.h" + +#include #include #include diff --git a/Engine/Source/Runtime/Window/Window.cpp b/Engine/Source/Runtime/Window/Window.cpp index 12250c67..baa75c41 100644 --- a/Engine/Source/Runtime/Window/Window.cpp +++ b/Engine/Source/Runtime/Window/Window.cpp @@ -13,19 +13,6 @@ namespace engine { -void Window::Init() -{ - // JoyStick : SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER - SDL_Init(SDL_INIT_EVENTS); - SDL_SetHintWithPriority("SDL_BORDERLESS_RESIZABLE_STYLE", "1", SDL_HINT_OVERRIDE); - SDL_SetHintWithPriority("SDL_BORDERLESS_WINDOWED_STYLE", "1", SDL_HINT_OVERRIDE); -} - -void Window::Shutdown() -{ - SDL_Quit(); -} - int Window::GetDisplayMonitorCount() { return SDL_GetNumVideoDisplays(); diff --git a/Engine/Source/Runtime/Window/Window.h b/Engine/Source/Runtime/Window/Window.h index 1720cf6f..1290e427 100644 --- a/Engine/Source/Runtime/Window/Window.h +++ b/Engine/Source/Runtime/Window/Window.h @@ -18,8 +18,6 @@ class Window }; public: - static void Init(); - static void Shutdown(); static int GetDisplayMonitorCount(); static const char* GetDisplayMonitorName(int index); static Rect GetDisplayMonitorMainRect(int index); diff --git a/Engine/Source/Runtime/Window/WindowManager.cpp b/Engine/Source/Runtime/Window/WindowManager.cpp index 6e318230..e1ac9bcf 100644 --- a/Engine/Source/Runtime/Window/WindowManager.cpp +++ b/Engine/Source/Runtime/Window/WindowManager.cpp @@ -1,10 +1,11 @@ #include "WindowManager.h" +#include "Base/NameOf.h" #include "Base/Template.h" #include "Input.h" #include "Window.h" -#include "SDL.h" +#include #include @@ -13,12 +14,28 @@ namespace engine WindowManager::WindowManager() { - Window::Init(); + // JoyStick : SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); + SDL_SetHintWithPriority("SDL_BORDERLESS_RESIZABLE_STYLE", "1", SDL_HINT_OVERRIDE); + SDL_SetHintWithPriority("SDL_BORDERLESS_WINDOWED_STYLE", "1", SDL_HINT_OVERRIDE); + + // Init system cursors. + m_allMouseCursors.resize(nameof::enum_count(), nullptr); + m_allMouseCursors[static_cast(MouseCursorType::Arrow)] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + m_allMouseCursors[static_cast(MouseCursorType::Crosshair)] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); } WindowManager::~WindowManager() { - Window::Shutdown(); + m_allWindows.clear(); + + for (auto* pCursor : m_allMouseCursors) + { + SDL_FreeCursor(pCursor); + } + m_allMouseCursors.clear(); + + SDL_Quit(); } Window* WindowManager::GetWindow(uint32_t id) const @@ -50,6 +67,16 @@ engine::Window* WindowManager::GetActiveWindow() const return nullptr; } +void WindowManager::ShowCursor(bool on) const +{ + SDL_ShowCursor(on); +} + +void WindowManager::SetCursor(MouseCursorType cursorType) const +{ + SDL_SetCursor(m_allMouseCursors[static_cast(cursorType)]); +} + void WindowManager::Update() { SDL_Event sdlEvent; @@ -110,7 +137,10 @@ void WindowManager::Update() case SDL_MOUSEMOTION: { const SDL_MouseMotionEvent& mouseMotionEvent = sdlEvent.motion; - OnMouseMove.Invoke(mouseMotionEvent.windowID, mouseMotionEvent.x, mouseMotionEvent.y); + engine::Input::Get().SetMousePositionX(mouseMotionEvent.x); + engine::Input::Get().SetMousePositionY(mouseMotionEvent.y); + engine::Input::Get().SetMousePositionOffsetX(mouseMotionEvent.xrel); + engine::Input::Get().SetMousePositionOffsetY(mouseMotionEvent.yrel); } break; diff --git a/Engine/Source/Runtime/Window/WindowManager.h b/Engine/Source/Runtime/Window/WindowManager.h index 83d94c9e..d84dc1d7 100644 --- a/Engine/Source/Runtime/Window/WindowManager.h +++ b/Engine/Source/Runtime/Window/WindowManager.h @@ -6,11 +6,19 @@ #include #include +struct SDL_Cursor; + namespace engine { class Window; +enum class MouseCursorType : int +{ + Arrow = 0, + Crosshair +}; + class WindowManager final { public: @@ -30,10 +38,13 @@ class WindowManager final void AddWindow(std::unique_ptr pWindow); void RemoveWindow(uint32_t id); + const SDL_Cursor* GetMouseCursor(MouseCursorType cursorType) const { return m_allMouseCursors[static_cast(cursorType)]; } + void ShowCursor(bool on) const; + void SetCursor(MouseCursorType cursorType) const; + void Update(); // Delegates - Delegate OnMouseMove; Delegate OnDropFile; private: @@ -41,6 +52,7 @@ class WindowManager final private: MapIDToWindow m_allWindows; + std::vector m_allMouseCursors; }; } \ No newline at end of file