Checkpoint workspace changes

This commit is contained in:
2026-04-29 01:24:21 +08:00
parent 9b6adf1806
commit ef11651ec2
67 changed files with 3161 additions and 1904 deletions

View File

@@ -4,23 +4,13 @@
#include "Scene/EditorSceneRuntime.h"
#include "Scene/SceneToolState.h"
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Components/GameObject.h>
#include <XCEngine/Components/MeshFilterComponent.h>
#include <XCEngine/Components/TransformComponent.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <XCEngine/Scene/Scene.h>
#include <utility>
#include <optional>
namespace XCEngine::UI::Editor::App {
namespace {
using ::XCEngine::Components::CameraComponent;
using ::XCEngine::Components::GameObject;
using ::XCEngine::Components::MeshFilterComponent;
using ::XCEngine::Components::TransformComponent;
using ::XCEngine::Math::Color;
using ::XCEngine::Math::Quaternion;
using ::XCEngine::Math::Vector2;
@@ -49,8 +39,8 @@ enum class ActiveTransformGizmoKind : std::uint8_t {
};
struct TransformGizmoSelectionState {
GameObject* primaryObject = nullptr;
std::vector<GameObject*> selectedObjects = {};
EditorSceneViewportSelectionSnapshot primaryObject = {};
std::vector<EditorSceneViewportSelectionSnapshot> selectedObjects = {};
Vector3 pivotWorldPosition = Vector3::Zero();
Quaternion primaryWorldRotation = Quaternion::Identity();
};
@@ -67,86 +57,49 @@ Vector2 ToLocalPoint(const UIRect& viewportRect, const UIPoint& point) {
return Vector2(point.x - viewportRect.x, point.y - viewportRect.y);
}
Quaternion ComputeStableWorldRotation(const GameObject* gameObject) {
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
return Quaternion::Identity();
}
return gameObject->GetTransform()->GetRotation().Normalized();
}
Vector3 ResolvePivotWorldPosition(const GameObject* gameObject) {
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
return Vector3::Zero();
}
return gameObject->GetTransform()->GetPosition();
}
Vector3 ResolveCenterWorldPosition(const GameObject* gameObject) {
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
return Vector3::Zero();
}
if (const MeshFilterComponent* meshFilter =
gameObject->GetComponent<MeshFilterComponent>();
meshFilter != nullptr) {
if (::XCEngine::Resources::Mesh* mesh = meshFilter->GetMesh();
mesh != nullptr && mesh->IsValid()) {
return gameObject->GetTransform()->TransformPoint(mesh->GetBounds().center);
}
}
return gameObject->GetTransform()->GetPosition();
Quaternion ComputeStableWorldRotation(
const EditorSceneViewportSelectionSnapshot& selection) {
return selection.IsValid()
? selection.worldRotation.Normalized()
: Quaternion::Identity();
}
TransformGizmoSelectionState BuildSelectionState(
EditorSceneRuntime& sceneRuntime,
bool useCenterPivot) {
TransformGizmoSelectionState state = {};
const auto selectedId = sceneRuntime.GetSelectedGameObjectId();
if (!selectedId.has_value()) {
const std::optional<EditorSceneViewportSelectionSnapshot> selectedObject =
sceneRuntime.BuildSceneViewportSelectionSnapshot();
if (!selectedObject.has_value() || !selectedObject->IsValid()) {
return state;
}
GameObject* selectedObject =
sceneRuntime.GetActiveScene() != nullptr
? sceneRuntime.GetActiveScene()->FindByID(selectedId.value())
: nullptr;
if (selectedObject == nullptr || selectedObject->GetTransform() == nullptr) {
return state;
}
state.primaryObject = selectedObject;
state.selectedObjects.push_back(selectedObject);
state.primaryWorldRotation = ComputeStableWorldRotation(selectedObject);
state.primaryObject = selectedObject.value();
state.selectedObjects.push_back(selectedObject.value());
state.primaryWorldRotation = ComputeStableWorldRotation(state.primaryObject);
state.pivotWorldPosition = useCenterPivot
? ResolveCenterWorldPosition(selectedObject)
: ResolvePivotWorldPosition(selectedObject);
? state.primaryObject.centerWorldPosition
: state.primaryObject.worldPosition;
return state;
}
SceneViewportOverlayData BuildOverlayData(const EditorSceneRuntime& sceneRuntime) {
SceneViewportOverlayData overlay = {};
const CameraComponent* camera = sceneRuntime.GetSceneViewCamera();
if (camera == nullptr || camera->GetGameObject() == nullptr) {
return overlay;
}
const TransformComponent* transform = camera->GetGameObject()->GetTransform();
if (transform == nullptr) {
const EditorSceneCameraSnapshot snapshot =
sceneRuntime.BuildSceneViewCameraSnapshot();
if (!snapshot.valid) {
return overlay;
}
overlay.valid = true;
overlay.cameraPosition = transform->GetPosition();
overlay.cameraForward = transform->GetForward();
overlay.cameraRight = transform->GetRight();
overlay.cameraUp = transform->GetUp();
overlay.verticalFovDegrees = camera->GetFieldOfView();
overlay.nearClipPlane = camera->GetNearClipPlane();
overlay.farClipPlane = camera->GetFarClipPlane();
overlay.orbitDistance = sceneRuntime.GetSceneViewOrbitDistance();
overlay.cameraPosition = snapshot.position;
overlay.cameraForward = snapshot.forward;
overlay.cameraRight = snapshot.right;
overlay.cameraUp = snapshot.up;
overlay.verticalFovDegrees = snapshot.verticalFovDegrees;
overlay.nearClipPlane = snapshot.nearClipPlane;
overlay.farClipPlane = snapshot.farClipPlane;
overlay.orbitDistance = snapshot.orbitDistance;
return overlay;
}
@@ -381,7 +334,7 @@ void SceneViewportTransformGizmo::Refresh(
sceneRuntime.GetToolSpaceMode() == SceneToolSpaceMode::Local;
const TransformGizmoSelectionState selection =
BuildSelectionState(sceneRuntime, useCenterPivot);
if (selection.primaryObject == nullptr) {
if (!selection.primaryObject.IsValid()) {
CancelDrag(sceneRuntime);
return;
}
@@ -406,8 +359,8 @@ void SceneViewportTransformGizmo::Refresh(
localPointer,
localSpace);
if (state.moveGizmo.IsActive() &&
state.moveContext.selectedObject != nullptr &&
state.moveContext.selectedObject->GetID() !=
state.moveContext.selectedObject.IsValid() &&
state.moveContext.selectedObject.objectId !=
state.moveGizmo.GetActiveEntityId()) {
state.moveGizmo.CancelDrag(&state.undoBridge);
}
@@ -424,8 +377,8 @@ void SceneViewportTransformGizmo::Refresh(
localSpace,
useCenterPivot);
if (state.rotateGizmo.IsActive() &&
state.rotateContext.selectedObject != nullptr &&
state.rotateContext.selectedObject->GetID() !=
state.rotateContext.selectedObject.IsValid() &&
state.rotateContext.selectedObject.objectId !=
state.rotateGizmo.GetActiveEntityId()) {
state.rotateGizmo.CancelDrag(&state.undoBridge);
}
@@ -442,8 +395,8 @@ void SceneViewportTransformGizmo::Refresh(
localSpace);
state.scaleContext.uniformOnly = usingTransformTool;
if (state.scaleGizmo.IsActive() &&
state.scaleContext.selectedObject != nullptr &&
state.scaleContext.selectedObject->GetID() !=
state.scaleContext.selectedObject.IsValid() &&
state.scaleContext.selectedObject.objectId !=
state.scaleGizmo.GetActiveEntityId()) {
state.scaleGizmo.CancelDrag(&state.undoBridge);
}
@@ -465,7 +418,7 @@ void SceneViewportTransformGizmo::Refresh(
ActiveTransformGizmoKind::Move);
state.moveGizmo.Update(updateContext);
inputs.moveGizmo = &state.moveGizmo.GetDrawData();
inputs.moveEntityId = selection.primaryObject->GetID();
inputs.moveEntityId = selection.primaryObject.objectId;
}
if (showingRotateGizmo) {
@@ -477,7 +430,7 @@ void SceneViewportTransformGizmo::Refresh(
ActiveTransformGizmoKind::Rotate);
state.rotateGizmo.Update(updateContext);
inputs.rotateGizmo = &state.rotateGizmo.GetDrawData();
inputs.rotateEntityId = selection.primaryObject->GetID();
inputs.rotateEntityId = selection.primaryObject.objectId;
}
if (showingScaleGizmo) {
@@ -489,7 +442,7 @@ void SceneViewportTransformGizmo::Refresh(
ActiveTransformGizmoKind::Scale);
state.scaleGizmo.Update(updateContext);
inputs.scaleGizmo = &state.scaleGizmo.GetDrawData();
inputs.scaleEntityId = selection.primaryObject->GetID();
inputs.scaleEntityId = selection.primaryObject.objectId;
}
const SceneViewportOverlayFrameData overlayFrame =