Tighten editor scene backend write boundary
This commit is contained in:
@@ -3,12 +3,9 @@
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/Components/Component.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Components/TransformComponent.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
@@ -16,13 +13,10 @@ namespace {
|
||||
|
||||
using ::XCEngine::Components::GameObject;
|
||||
using ::XCEngine::Components::Scene;
|
||||
using ::XCEngine::Components::TransformComponent;
|
||||
using ::XCEngine::Components::Component;
|
||||
using ::XCEngine::Math::Quaternion;
|
||||
using ::XCEngine::Math::Vector3;
|
||||
|
||||
constexpr char kComponentIdSeparator = '#';
|
||||
|
||||
std::string ResolveGameObjectDisplayName(const GameObject& gameObject) {
|
||||
return gameObject.GetName().empty()
|
||||
? std::string("GameObject")
|
||||
@@ -54,57 +48,6 @@ bool TransformSnapshotsMatch(
|
||||
NearlyEqual(lhs.scale, rhs.scale);
|
||||
}
|
||||
|
||||
std::string BuildEditorComponentId(
|
||||
std::string_view typeName,
|
||||
std::size_t ordinal) {
|
||||
std::string componentId(typeName);
|
||||
componentId.push_back(kComponentIdSeparator);
|
||||
componentId += std::to_string(ordinal);
|
||||
return componentId;
|
||||
}
|
||||
|
||||
bool ParseEditorComponentId(
|
||||
std::string_view componentId,
|
||||
std::string& outTypeName,
|
||||
std::size_t& outOrdinal) {
|
||||
const std::size_t separatorIndex = componentId.find(kComponentIdSeparator);
|
||||
if (separatorIndex == std::string_view::npos ||
|
||||
separatorIndex == 0u ||
|
||||
separatorIndex + 1u >= componentId.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outTypeName = std::string(componentId.substr(0u, separatorIndex));
|
||||
std::size_t ordinal = 0u;
|
||||
const std::string_view ordinalText =
|
||||
componentId.substr(separatorIndex + 1u);
|
||||
const char* first = ordinalText.data();
|
||||
const char* last = ordinalText.data() + ordinalText.size();
|
||||
const std::from_chars_result result =
|
||||
std::from_chars(first, last, ordinal);
|
||||
if (result.ec != std::errc() || result.ptr != last) {
|
||||
outTypeName.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
outOrdinal = ordinal;
|
||||
return true;
|
||||
}
|
||||
|
||||
EditorSceneComponentDescriptor BuildComponentDescriptor(
|
||||
const Component& component,
|
||||
std::size_t ordinal) {
|
||||
EditorSceneComponentDescriptor descriptor = {};
|
||||
descriptor.typeName = component.GetName();
|
||||
descriptor.componentId =
|
||||
BuildEditorComponentId(descriptor.typeName, ordinal);
|
||||
descriptor.component = &component;
|
||||
descriptor.removable =
|
||||
component.GetGameObject() != nullptr &&
|
||||
component.GetGameObject()->GetTransform() != &component;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string_view GetSceneToolModeName(SceneToolMode mode) {
|
||||
@@ -276,17 +219,12 @@ void EditorSceneRuntime::ApplySceneViewportCameraInput(
|
||||
}
|
||||
|
||||
bool EditorSceneRuntime::FocusSceneSelection() {
|
||||
const GameObject* selectedGameObject = GetSelectedGameObject();
|
||||
if (selectedGameObject == nullptr || !EnsureSceneViewCamera()) {
|
||||
SceneTransformSnapshot snapshot = {};
|
||||
if (!CaptureSelectedTransformSnapshot(snapshot) || !EnsureSceneViewCamera()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* transform = selectedGameObject->GetTransform();
|
||||
if (transform == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sceneViewCamera.controller.Focus(transform->GetPosition());
|
||||
m_sceneViewCamera.controller.Focus(snapshot.position);
|
||||
ApplySceneViewCameraController();
|
||||
return true;
|
||||
}
|
||||
@@ -328,28 +266,10 @@ const GameObject* EditorSceneRuntime::GetSelectedGameObject() const {
|
||||
}
|
||||
|
||||
std::vector<EditorSceneComponentDescriptor> EditorSceneRuntime::GetSelectedComponents() const {
|
||||
std::vector<EditorSceneComponentDescriptor> descriptors = {};
|
||||
const GameObject* gameObject = GetSelectedGameObject();
|
||||
if (gameObject == nullptr) {
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
const std::vector<const Component*> components =
|
||||
gameObject->GetComponents<Component>();
|
||||
descriptors.reserve(components.size());
|
||||
std::unordered_map<std::string, std::size_t> ordinalsByType = {};
|
||||
for (const Component* component : components) {
|
||||
if (component == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string typeName = component->GetName();
|
||||
const std::size_t ordinal = ordinalsByType[typeName];
|
||||
descriptors.push_back(BuildComponentDescriptor(*component, ordinal));
|
||||
ordinalsByType[typeName] = ordinal + 1u;
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
const std::string selectedItemId = GetSelectedItemId();
|
||||
return m_backend != nullptr && !selectedItemId.empty()
|
||||
? m_backend->GetComponents(selectedItemId)
|
||||
: std::vector<EditorSceneComponentDescriptor>{};
|
||||
}
|
||||
|
||||
std::uint64_t EditorSceneRuntime::GetSelectionStamp() const {
|
||||
@@ -556,21 +476,10 @@ bool EditorSceneRuntime::RemoveSelectedComponent(std::string_view componentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::optional<GameObject::ID> selectedId = GetSelectedGameObjectId();
|
||||
Scene* scene = GetActiveScene();
|
||||
if (!selectedId.has_value() || scene == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject* gameObject = scene->FindByID(selectedId.value());
|
||||
Component* component =
|
||||
const_cast<Component*>(descriptor.component);
|
||||
if (gameObject == nullptr || component == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ResetTransformEditHistory();
|
||||
const bool removed = gameObject->RemoveComponent(component);
|
||||
const bool removed =
|
||||
m_backend != nullptr &&
|
||||
m_backend->RemoveComponent(GetSelectedItemId(), componentId);
|
||||
if (removed) {
|
||||
IncrementInspectorRevision();
|
||||
}
|
||||
@@ -583,10 +492,7 @@ bool EditorSceneRuntime::SetSelectedTransformLocalPosition(
|
||||
const Vector3& position) {
|
||||
const EditorSceneComponentDescriptor descriptor =
|
||||
ResolveSelectedComponentDescriptor(componentId);
|
||||
auto* transform =
|
||||
const_cast<TransformComponent*>(
|
||||
dynamic_cast<const TransformComponent*>(descriptor.component));
|
||||
if (transform == nullptr) {
|
||||
if (m_backend == nullptr || descriptor.typeName != "Transform") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -595,7 +501,12 @@ bool EditorSceneRuntime::SetSelectedTransformLocalPosition(
|
||||
return false;
|
||||
}
|
||||
|
||||
transform->SetLocalPosition(position);
|
||||
if (!m_backend->SetTransformLocalPosition(
|
||||
GetSelectedItemId(),
|
||||
componentId,
|
||||
position)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneTransformSnapshot afterSnapshot = {};
|
||||
CaptureSelectedTransformSnapshot(afterSnapshot);
|
||||
@@ -611,10 +522,7 @@ bool EditorSceneRuntime::SetSelectedTransformLocalEulerAngles(
|
||||
const Vector3& eulerAngles) {
|
||||
const EditorSceneComponentDescriptor descriptor =
|
||||
ResolveSelectedComponentDescriptor(componentId);
|
||||
auto* transform =
|
||||
const_cast<TransformComponent*>(
|
||||
dynamic_cast<const TransformComponent*>(descriptor.component));
|
||||
if (transform == nullptr) {
|
||||
if (m_backend == nullptr || descriptor.typeName != "Transform") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -623,7 +531,12 @@ bool EditorSceneRuntime::SetSelectedTransformLocalEulerAngles(
|
||||
return false;
|
||||
}
|
||||
|
||||
transform->SetLocalEulerAngles(eulerAngles);
|
||||
if (!m_backend->SetTransformLocalEulerAngles(
|
||||
GetSelectedItemId(),
|
||||
componentId,
|
||||
eulerAngles)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneTransformSnapshot afterSnapshot = {};
|
||||
CaptureSelectedTransformSnapshot(afterSnapshot);
|
||||
@@ -639,10 +552,7 @@ bool EditorSceneRuntime::SetSelectedTransformLocalScale(
|
||||
const Vector3& scale) {
|
||||
const EditorSceneComponentDescriptor descriptor =
|
||||
ResolveSelectedComponentDescriptor(componentId);
|
||||
auto* transform =
|
||||
const_cast<TransformComponent*>(
|
||||
dynamic_cast<const TransformComponent*>(descriptor.component));
|
||||
if (transform == nullptr) {
|
||||
if (m_backend == nullptr || descriptor.typeName != "Transform") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -651,7 +561,12 @@ bool EditorSceneRuntime::SetSelectedTransformLocalScale(
|
||||
return false;
|
||||
}
|
||||
|
||||
transform->SetLocalScale(scale);
|
||||
if (!m_backend->SetTransformLocalScale(
|
||||
GetSelectedItemId(),
|
||||
componentId,
|
||||
scale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneTransformSnapshot afterSnapshot = {};
|
||||
CaptureSelectedTransformSnapshot(afterSnapshot);
|
||||
@@ -669,14 +584,15 @@ bool EditorSceneRuntime::ApplySelectedComponentMutation(
|
||||
return false;
|
||||
}
|
||||
|
||||
const EditorSceneComponentDescriptor descriptor =
|
||||
ResolveSelectedComponentDescriptor(componentId);
|
||||
Component* component = const_cast<Component*>(descriptor.component);
|
||||
if (!descriptor.IsValid() || component == nullptr) {
|
||||
if (m_backend == nullptr ||
|
||||
!ResolveSelectedComponentDescriptor(componentId).IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mutation(*component)) {
|
||||
if (!m_backend->MutateComponent(
|
||||
GetSelectedItemId(),
|
||||
componentId,
|
||||
mutation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -750,23 +666,22 @@ void EditorSceneRuntime::ResetToolInteractionState() {
|
||||
|
||||
bool EditorSceneRuntime::CaptureSelectedTransformSnapshot(
|
||||
SceneTransformSnapshot& outSnapshot) const {
|
||||
const GameObject* selectedGameObject = GetSelectedGameObject();
|
||||
if (selectedGameObject == nullptr) {
|
||||
outSnapshot = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
const TransformComponent* transform = selectedGameObject->GetTransform();
|
||||
if (transform == nullptr) {
|
||||
const std::optional<GameObject::ID> selectedId = GetSelectedGameObjectId();
|
||||
if (!selectedId.has_value() || m_backend == nullptr) {
|
||||
outSnapshot = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
outSnapshot = {};
|
||||
outSnapshot.targetId = selectedGameObject->GetID();
|
||||
outSnapshot.position = transform->GetPosition();
|
||||
outSnapshot.rotation = transform->GetRotation();
|
||||
outSnapshot.scale = transform->GetScale();
|
||||
outSnapshot.targetId = selectedId.value();
|
||||
if (!m_backend->QueryWorldTransform(
|
||||
selectedId.value(),
|
||||
outSnapshot.position,
|
||||
outSnapshot.rotation,
|
||||
outSnapshot.scale)) {
|
||||
outSnapshot = {};
|
||||
return false;
|
||||
}
|
||||
outSnapshot.valid = true;
|
||||
return true;
|
||||
}
|
||||
@@ -777,24 +692,15 @@ bool EditorSceneRuntime::ApplyTransformSnapshot(
|
||||
return false;
|
||||
}
|
||||
|
||||
Scene* scene = GetActiveScene();
|
||||
if (scene == nullptr) {
|
||||
if (m_backend == nullptr ||
|
||||
!m_backend->SetWorldTransform(
|
||||
snapshot.targetId,
|
||||
snapshot.position,
|
||||
snapshot.rotation,
|
||||
snapshot.scale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject* gameObject = scene->FindByID(snapshot.targetId);
|
||||
if (gameObject == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TransformComponent* transform = gameObject->GetTransform();
|
||||
if (transform == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
transform->SetPosition(snapshot.position);
|
||||
transform->SetRotation(snapshot.rotation);
|
||||
transform->SetScale(snapshot.scale);
|
||||
IncrementInspectorRevision();
|
||||
return true;
|
||||
}
|
||||
@@ -869,12 +775,13 @@ bool EditorSceneRuntime::ApplyTransformToolWorldPreview(
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneTransformSnapshot snapshot = m_toolState.dragState.initialTransform;
|
||||
snapshot.targetId = targetId;
|
||||
snapshot.position = position;
|
||||
snapshot.rotation = rotation;
|
||||
snapshot.valid = true;
|
||||
return ApplyTransformSnapshot(snapshot);
|
||||
if (m_backend == nullptr ||
|
||||
!m_backend->SetWorldPositionRotation(targetId, position, rotation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IncrementInspectorRevision();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EditorSceneRuntime::ApplyTransformToolLocalScalePreview(
|
||||
@@ -886,17 +793,11 @@ bool EditorSceneRuntime::ApplyTransformToolLocalScalePreview(
|
||||
return false;
|
||||
}
|
||||
|
||||
Scene* scene = GetActiveScene();
|
||||
if (scene == nullptr) {
|
||||
if (m_backend == nullptr ||
|
||||
!m_backend->SetObjectLocalScale(targetId, localScale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject* gameObject = scene->FindByID(targetId);
|
||||
if (gameObject == nullptr || gameObject->GetTransform() == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gameObject->GetTransform()->SetLocalScale(localScale);
|
||||
IncrementInspectorRevision();
|
||||
return true;
|
||||
}
|
||||
@@ -1040,28 +941,11 @@ bool EditorSceneRuntime::HasValidSelection() const {
|
||||
|
||||
EditorSceneComponentDescriptor EditorSceneRuntime::ResolveSelectedComponentDescriptor(
|
||||
std::string_view componentId) const {
|
||||
std::string typeName = {};
|
||||
std::size_t ordinal = 0u;
|
||||
if (!ParseEditorComponentId(componentId, typeName, ordinal)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const GameObject* gameObject = GetSelectedGameObject();
|
||||
if (gameObject == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t currentOrdinal = 0u;
|
||||
for (const Component* component : gameObject->GetComponents<Component>()) {
|
||||
if (component == nullptr || component->GetName() != typeName) {
|
||||
continue;
|
||||
for (const EditorSceneComponentDescriptor& descriptor :
|
||||
GetSelectedComponents()) {
|
||||
if (descriptor.componentId == componentId) {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
if (currentOrdinal == ordinal) {
|
||||
return BuildComponentDescriptor(*component, currentOrdinal);
|
||||
}
|
||||
|
||||
++currentOrdinal;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
Reference in New Issue
Block a user