Integrating latest 47acbe8
This commit is contained in:
@@ -15,6 +15,11 @@
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct CameraState;
|
||||
}
|
||||
|
||||
namespace Camera
|
||||
{
|
||||
/**
|
||||
@@ -56,6 +61,16 @@ namespace Camera
|
||||
* @return True if the camera position was successfully retrieved, false if not.
|
||||
*/
|
||||
virtual bool GetActiveCameraPosition(AZ::Vector3& /*cameraPos*/) { return false; }
|
||||
|
||||
/**
|
||||
* Gets the position of the currently active Editor camera.
|
||||
* The Editor can have multiple viewports displayed, though at most only one is active at any point in time.
|
||||
* (Active is not the same as "has focus" - a different editor pane can have focus, but there's still one
|
||||
* active viewport that's updating every frame, and the others are not).
|
||||
* @param cameraView The current camera view in the one active Editor viewport.
|
||||
* @return True if the camera view was successfully retrieved, false if not.
|
||||
*/
|
||||
virtual bool GetActiveCameraState([[maybe_unused]] AzFramework::CameraState& cameraState) { return false; }
|
||||
};
|
||||
|
||||
using EditorCameraRequestBus = AZ::EBus<EditorCameraRequests>;
|
||||
|
||||
@@ -42,6 +42,7 @@ class QMenu;
|
||||
class QWidget;
|
||||
class QApplication;
|
||||
class QDockWidget;
|
||||
class QMainWindow;
|
||||
struct IEditor;
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -587,6 +588,13 @@ namespace AzToolsFramework
|
||||
*/
|
||||
virtual const char* GetEngineVersion() const = 0;
|
||||
|
||||
/**
|
||||
* Retrieves if Legacy Slice System is enabled
|
||||
*/
|
||||
virtual bool IsLegacySliceSystemEnabled() const = 0;
|
||||
|
||||
virtual bool ShouldAssertForLegacySlicesUsage() const = 0;
|
||||
|
||||
/**
|
||||
* Creates and adds a new entity to the tools application from components which match at least one of the requiredTags
|
||||
* The tag matching occurs on AZ::Edit::SystemComponentTags attribute from the reflected class data in the serialization context
|
||||
@@ -948,6 +956,9 @@ namespace AzToolsFramework
|
||||
/// Notify that the IEditor is ready
|
||||
virtual void NotifyIEditorAvailable(IEditor* /*editor*/) {}
|
||||
|
||||
/// Notify that the MainWindow has been fully initialized
|
||||
virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {}
|
||||
|
||||
/// Signal that an asset should be highlighted / selected
|
||||
virtual void SelectAsset(const QString& /* assetPath */) {}
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h>
|
||||
#include <AzToolsFramework/Component/EditorComponentAPIComponent.h>
|
||||
#include <AzToolsFramework/Component/EditorLevelComponentAPIComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityActionComponent.h>
|
||||
@@ -66,6 +67,7 @@
|
||||
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
|
||||
#include <AzToolsFramework/AssetEditor/AssetEditorBus.h>
|
||||
#include <AzToolsFramework/Render/EditorIntersectorComponent.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer<QFileInfoPrivate>' needs to have dll-interface to be used by clients of class 'QFileInfo'
|
||||
@@ -93,6 +95,9 @@ namespace AzToolsFramework
|
||||
|
||||
static const char* s_startupLogWindow = "Startup";
|
||||
|
||||
static const char* s_prefabSystemKey = "/Amazon/Editor/Preferences/EnablePrefabSystem";
|
||||
static const char* s_legacySlicesAssertKey = "/Amazon/Editor/Preferences/ShouldAssertForLegacySlicesUsage";
|
||||
|
||||
template<typename IdContainerType>
|
||||
void DeleteEntities(const IdContainerType& entityIds)
|
||||
{
|
||||
@@ -206,6 +211,19 @@ namespace AzToolsFramework
|
||||
}
|
||||
};
|
||||
|
||||
struct EditorEventsBusHandler final
|
||||
: public EditorEventsBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator,
|
||||
NotifyRegisterViews);
|
||||
|
||||
void NotifyRegisterViews() override
|
||||
{
|
||||
Call(FN_NotifyRegisterViews);
|
||||
}
|
||||
};
|
||||
|
||||
} // Internal
|
||||
|
||||
#define AZ_MAX_ENGINE_VERSION_LEN 64
|
||||
@@ -346,6 +364,7 @@ namespace AzToolsFramework
|
||||
|
||||
components.insert(components.end(), {
|
||||
azrtti_typeid<EditorEntityContextComponent>(),
|
||||
azrtti_typeid<Components::EditorEntityUiSystemComponent>(),
|
||||
azrtti_typeid<SliceMetadataEntityContextComponent>(),
|
||||
azrtti_typeid<Prefab::PrefabSystemComponent>(),
|
||||
azrtti_typeid<EditorEntityFixupComponent>(),
|
||||
@@ -440,6 +459,7 @@ namespace AzToolsFramework
|
||||
QTreeViewWithStateSaving::Reflect(context);
|
||||
QWidgetSavedState::Reflect(context);
|
||||
SliceUtilities::Reflect(context);
|
||||
Prefab::PrefabIntegrationManager::Reflect(context);
|
||||
|
||||
ComponentModeFramework::ComponentModeDelegate::Reflect(context);
|
||||
|
||||
@@ -499,6 +519,14 @@ namespace AzToolsFramework
|
||||
->Event("UnregisterViewPane", &EditorRequests::UnregisterViewPane)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<EditorEventsBus>("EditorEventBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, "editor")
|
||||
->Handler<Internal::EditorEventsBusHandler>()
|
||||
->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<ViewPaneCallbackBus>("ViewPaneCallbackBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
@@ -1741,6 +1769,26 @@ namespace AzToolsFramework
|
||||
return m_engineConfigImpl->GetEngineVersion();
|
||||
}
|
||||
|
||||
bool ToolsApplication::IsLegacySliceSystemEnabled() const
|
||||
{
|
||||
bool value = false;
|
||||
if (auto* registry = AZ::SettingsRegistry::Get())
|
||||
{
|
||||
registry->Get(value, Internal::s_prefabSystemKey);
|
||||
}
|
||||
return !value;
|
||||
}
|
||||
|
||||
bool ToolsApplication::ShouldAssertForLegacySlicesUsage() const
|
||||
{
|
||||
bool value = false;
|
||||
if (auto* registry = AZ::SettingsRegistry::Get())
|
||||
{
|
||||
registry->Get(value, Internal::s_legacySlicesAssertKey);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void ToolsApplication::CreateAndAddEntityFromComponentTags(const AZStd::vector<AZ::Crc32>& requiredTags, const char* entityName)
|
||||
{
|
||||
if (!entityName || !entityName[0])
|
||||
|
||||
@@ -145,6 +145,8 @@ namespace AzToolsFramework
|
||||
bool IsEditorInIsolationMode() override;
|
||||
const char* GetEngineRootPath() const override;
|
||||
const char* GetEngineVersion() const override;
|
||||
bool IsLegacySliceSystemEnabled() const override;
|
||||
bool ShouldAssertForLegacySlicesUsage() const override;
|
||||
|
||||
void CreateAndAddEntityFromComponentTags(const AZStd::vector<AZ::Crc32>& requiredTags, const char* entityName) override;
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace AssetBrowser
|
||||
{
|
||||
class AssetBrowserSourceDropEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~AssetBrowserSourceDropEvents() = default;
|
||||
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
|
||||
// File extension, includes dot.
|
||||
using BusIdType = AZStd::string;
|
||||
|
||||
//! Handles source files dropped from the AssetBrowser into the scene.
|
||||
virtual void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const = 0;
|
||||
};
|
||||
|
||||
using AssetBrowserSourceDropBus = AZ::EBus<AssetBrowserSourceDropEvents>;
|
||||
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
+2
-1
@@ -194,7 +194,8 @@ namespace AzToolsFramework
|
||||
->Field("m_name", &AssetBrowserEntry::m_name)
|
||||
->Field("m_children", &AssetBrowserEntry::m_children)
|
||||
->Field("m_row", &AssetBrowserEntry::m_row)
|
||||
->Version(1);
|
||||
->Field("m_fullPath", &AssetBrowserEntry::m_fullPath)
|
||||
->Version(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_dirty = false;
|
||||
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
|
||||
|
||||
// Clone the asset
|
||||
AZ::Data::AssetId newAssetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom());
|
||||
@@ -333,9 +333,9 @@ namespace AzToolsFramework
|
||||
m_saveAssetAction->setEnabled(false);
|
||||
m_propertyEditor->ClearInstances();
|
||||
|
||||
if (AZ::Data::AssetBus::Handler::BusIsConnectedId(asset.GetId()))
|
||||
if (AZ::Data::AssetBus::MultiHandler::BusIsConnectedId(asset.GetId()))
|
||||
{
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId());
|
||||
}
|
||||
QString errString = tr("Failed to load %1!").arg(asset.GetHint().c_str());
|
||||
AZ_Error("Asset Editor", false, errString.toUtf8());
|
||||
@@ -591,6 +591,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
auto asset = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, AZ::Data::AssetLoadBehavior::Default);
|
||||
|
||||
asset.BlockUntilLoadComplete();
|
||||
|
||||
if (asset.IsReady())
|
||||
{
|
||||
OnAssetReady(asset);
|
||||
@@ -599,10 +601,10 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (m_inMemoryAsset)
|
||||
{
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(m_inMemoryAsset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(m_inMemoryAsset.GetId());
|
||||
}
|
||||
|
||||
AZ::Data::AssetBus::Handler::BusConnect(asset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(asset.GetId());
|
||||
|
||||
// Need to disable editing until OnAssetReady.
|
||||
m_propertyEditor->setEnabled(false);
|
||||
@@ -619,7 +621,9 @@ namespace AzToolsFramework
|
||||
|
||||
AssetEditorValidationRequestBus::Event(m_sourceAssetId, &AssetEditorValidationRequests::PreAssetSave, m_inMemoryAsset);
|
||||
|
||||
if (AZ::Utils::SaveObjectToStream(dstByteStream, AZ::DataStream::ST_XML, m_inMemoryAsset.Get(), m_inMemoryAsset.Get()->RTTI_GetType(), m_serializeContext))
|
||||
if (AZ::Utils::SaveObjectToStream(
|
||||
dstByteStream, AZ::DataStream::ST_XML, m_inMemoryAsset.Get(), m_inMemoryAsset.Get()->RTTI_GetType(),
|
||||
m_serializeContext))
|
||||
{
|
||||
AZStd::swap(newSaveData, m_saveData);
|
||||
}
|
||||
@@ -800,7 +804,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_inMemoryAsset)
|
||||
{
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(m_inMemoryAsset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect(m_inMemoryAsset.GetId());
|
||||
m_inMemoryAsset.Release();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace AzToolsFramework
|
||||
*/
|
||||
class AssetEditorWidget
|
||||
: public QWidget
|
||||
, private AZ::Data::AssetBus::Handler
|
||||
, private AZ::Data::AssetBus::MultiHandler
|
||||
, private AzFramework::AssetCatalogEventBus::Handler
|
||||
, private AzToolsFramework::IPropertyEditorNotify
|
||||
, private AZ::SystemTickBus::Handler
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiSystemComponent.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerComponent.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/MaterialBrowser/MaterialBrowserComponent.h>
|
||||
@@ -98,6 +99,7 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Components::EditorEntitySearchComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Components::EditorIntersectorComponent::CreateDescriptor(),
|
||||
AzToolsFramework::AzToolsFrameworkConfigurationSystemComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Components::EditorEntityUiSystemComponent::CreateDescriptor(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
class QMenu;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
enum class EditorContextMenuOrdering
|
||||
{
|
||||
TOP = 0,
|
||||
MIDDLE = 500,
|
||||
BOTTOM = 1000
|
||||
};
|
||||
|
||||
//! Editor Settings API Bus
|
||||
class EditorContextMenuEvents
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
virtual ~EditorContextMenuEvents() = default;
|
||||
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::MultipleAndOrdered;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
|
||||
/**
|
||||
* Determines the order in which handlers populate the context menus.
|
||||
*/
|
||||
struct BusHandlerOrderCompare
|
||||
{
|
||||
AZ_FORCE_INLINE bool operator()(EditorContextMenuEvents* left, EditorContextMenuEvents* right) const
|
||||
{
|
||||
if (left->GetMenuPosition() == right->GetMenuPosition())
|
||||
{
|
||||
return left->GetMenuIdentifier() < right->GetMenuIdentifier();
|
||||
}
|
||||
|
||||
return left->GetMenuPosition() < right->GetMenuPosition();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies the order in which a handler receives context menu events relative to other handlers.
|
||||
* This value should not be changed while the handler is connected.
|
||||
* Use the EditorContextMenuOrdering enum values as a baseline.
|
||||
* @return A value specifying this handler's relative order.
|
||||
*/
|
||||
virtual int GetMenuPosition() const
|
||||
{
|
||||
return aznumeric_cast<int>(EditorContextMenuOrdering::BOTTOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier for this handler.
|
||||
* Used to break ties in the order comparison.
|
||||
* @return A string containing the identifier for this handler.
|
||||
*/
|
||||
virtual AZStd::string GetMenuIdentifier() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends menu items to the global editor context menu.
|
||||
* This is the menu that appears when right clicking the main editor window,
|
||||
* including the Entity Outliner and the Viewport.
|
||||
*/
|
||||
virtual void PopulateEditorGlobalContextMenu(QMenu* menu) const = 0;
|
||||
};
|
||||
|
||||
using EditorContextMenuBus = AZ::EBus<EditorContextMenuEvents>;
|
||||
}
|
||||
+83
-26
@@ -12,6 +12,8 @@
|
||||
|
||||
#include "AzToolsFramework_precompiled.h"
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/EntityUtils.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
@@ -51,8 +53,9 @@
|
||||
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntitySortComponent.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
|
||||
#include "EditorEntityContextComponent.h"
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -160,7 +163,19 @@ namespace AzToolsFramework
|
||||
//=========================================================================
|
||||
void EditorEntityContextComponent::Activate()
|
||||
{
|
||||
m_entityOwnershipService = AZStd::make_unique<SliceEditorEntityOwnershipService>(GetContextId(), GetSerializeContext());
|
||||
m_isLegacySliceService = true;
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(m_isLegacySliceService,
|
||||
&AzToolsFramework::ToolsApplicationRequests::IsLegacySliceSystemEnabled);
|
||||
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
m_entityOwnershipService = AZStd::make_unique<SliceEditorEntityOwnershipService>(GetContextId(), GetSerializeContext());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entityOwnershipService = AZStd::make_unique<PrefabEditorEntityOwnershipService>(GetContextId(), GetSerializeContext());
|
||||
}
|
||||
|
||||
InitContext();
|
||||
|
||||
@@ -359,9 +374,18 @@ namespace AzToolsFramework
|
||||
AZ::SliceComponent::SliceReferenceToInstancePtrs& instancesInLayers)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
return editorEntityOwnershipService->SaveToStreamForEditor(stream, entitiesInLayers, instancesInLayers);
|
||||
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
return editorEntityOwnershipService->SaveToStreamForEditor(stream, entitiesInLayers, instancesInLayers);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorEntityContextComponent::GetLooseEditorEntities(EntityList& entityList)
|
||||
@@ -375,9 +399,17 @@ namespace AzToolsFramework
|
||||
bool EditorEntityContextComponent::SaveToStreamForGame(AZ::IO::GenericStream& stream, AZ::DataStream::StreamType streamType)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
return editorEntityOwnershipService->SaveToStreamForGame(stream, streamType);
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
return editorEntityOwnershipService->SaveToStreamForGame(stream, streamType);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -410,11 +442,16 @@ namespace AzToolsFramework
|
||||
|
||||
EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnEntityStreamLoadBegin);
|
||||
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
|
||||
const bool loadedSuccessfully = editorEntityOwnershipService->LoadFromStreamWithLayers(stream, levelPakFile);
|
||||
|
||||
bool loadedSuccessfully = true;
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
loadedSuccessfully = static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get())->LoadFromStreamWithLayers(stream, levelPakFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
}
|
||||
|
||||
LoadFromStreamComplete(loadedSuccessfully);
|
||||
|
||||
return loadedSuccessfully;
|
||||
@@ -450,10 +487,16 @@ namespace AzToolsFramework
|
||||
|
||||
EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnStartPlayInEditorBegin);
|
||||
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
|
||||
editorEntityOwnershipService->StartPlayInEditor(m_editorToRuntimeIdMap, m_runtimeToEditorIdMap);
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
editorEntityOwnershipService->StartPlayInEditor(m_editorToRuntimeIdMap, m_runtimeToEditorIdMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
}
|
||||
|
||||
m_isRunningGame = true;
|
||||
|
||||
@@ -471,10 +514,17 @@ namespace AzToolsFramework
|
||||
|
||||
m_isRunningGame = false;
|
||||
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
|
||||
editorEntityOwnershipService->StopPlayInEditor(m_editorToRuntimeIdMap, m_runtimeToEditorIdMap);
|
||||
editorEntityOwnershipService->StopPlayInEditor(m_editorToRuntimeIdMap, m_runtimeToEditorIdMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
}
|
||||
|
||||
ToolsApplicationRequests::Bus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, m_selectedBeforeStartingGame);
|
||||
m_selectedBeforeStartingGame.clear();
|
||||
@@ -603,13 +653,20 @@ namespace AzToolsFramework
|
||||
void EditorEntityContextComponent::OnContextEntitiesAdded(const EntityList& entities)
|
||||
{
|
||||
EntityContext::OnContextEntitiesAdded(entities);
|
||||
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
|
||||
// Any entities being added to the context that don't belong to another slice
|
||||
// need to be associated with the root metadata info component.
|
||||
editorEntityOwnershipService->AssociateToRootMetadataEntity(entities);
|
||||
if (m_isLegacySliceService)
|
||||
{
|
||||
SliceEditorEntityOwnershipService* editorEntityOwnershipService =
|
||||
static_cast<SliceEditorEntityOwnershipService*>(m_entityOwnershipService.get());
|
||||
|
||||
// Any entities being added to the context that don't belong to another slice
|
||||
// need to be associated with the root metadata info component.
|
||||
editorEntityOwnershipService->AssociateToRootMetadataEntity(entities);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(!m_entityOwnershipService->m_shouldAssertForLegacySlicesUsage, "Not implemented");
|
||||
}
|
||||
|
||||
SetupEditorEntities(entities);
|
||||
}
|
||||
|
||||
+7
-5
@@ -124,18 +124,19 @@ namespace AzToolsFramework
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("EditorEntityContextService", 0x28d93a43));
|
||||
provided.push_back(AZ_CRC_CE("EditorEntityContextService"));
|
||||
}
|
||||
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC("EditorEntityContextService", 0x28d93a43));
|
||||
incompatible.push_back(AZ_CRC_CE("EditorEntityContextService"));
|
||||
}
|
||||
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
|
||||
dependent.push_back(AZ_CRC("SliceSystemService", 0x1a5b7aad));
|
||||
dependent.push_back(AZ_CRC_CE("AssetDatabaseService"));
|
||||
dependent.push_back(AZ_CRC_CE("SliceSystemService"));
|
||||
dependent.push_back(AZ_CRC_CE("PrefabSystem"));
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -183,7 +184,8 @@ namespace AzToolsFramework
|
||||
AZ::ComponentTypeList m_requiredEditorComponentTypes;
|
||||
|
||||
//! Edit time visibility management integrating entities with the IVisibilitySystem.
|
||||
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
|
||||
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
|
||||
bool m_isLegacySliceService;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class PrefabEditorEntityOwnershipInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabEditorEntityOwnershipInterface,"{38E764BA-A089-49F3-848F-46018822CE2E}");
|
||||
|
||||
//! Creates a prefab instance with the provided entities and nestedPrefabInstances.
|
||||
//! /param entities The entities to put under the new prefab.
|
||||
//! /param nestedPrefabInstances The nested prefab instances to put under the new prefab.
|
||||
//! /param filePath The filepath corresponding to the prefab file to be created.
|
||||
//! /param instanceToParentUnder The instance under which the newly created prefab instance is parented under.
|
||||
//! /return The optional reference to the prefab created.
|
||||
virtual Prefab::InstanceOptionalReference CreatePrefab(
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
|
||||
const AZStd::string& filePath, Prefab::Instance& instanceToParentUnder) = 0;
|
||||
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
|
||||
};
|
||||
}
|
||||
+211
-7
@@ -10,21 +10,48 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoader.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
PrefabEditorEntityOwnershipService::PrefabEditorEntityOwnershipService(const AzFramework::EntityContextId& entityContextId,
|
||||
AZ::SerializeContext* serializeContext)
|
||||
: m_entityContextId(entityContextId)
|
||||
, m_serializeContext(serializeContext)
|
||||
{
|
||||
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
||||
m_shouldAssertForLegacySlicesUsage, &AzToolsFramework::ToolsApplicationRequests::ShouldAssertForLegacySlicesUsage);
|
||||
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Register(this);
|
||||
}
|
||||
|
||||
PrefabEditorEntityOwnershipService::~PrefabEditorEntityOwnershipService()
|
||||
{
|
||||
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::Initialize()
|
||||
{
|
||||
m_prefabSystemComponent = AZ::Interface<Prefab::PrefabSystemComponentInterface>::Get();
|
||||
AZ_Assert(m_prefabSystemComponent != nullptr, "Couldn't get prefab system component, it's a requirement for PrefabEntityOwnership system to work");
|
||||
AZ_Assert(m_prefabSystemComponent != nullptr,
|
||||
"Couldn't get prefab system component, it's a requirement for PrefabEntityOwnership system to work");
|
||||
|
||||
m_loaderInterface = AZ::Interface<Prefab::PrefabLoaderInterface>::Get();
|
||||
AZ_Assert(m_loaderInterface != nullptr,
|
||||
"Couldn't get prefab loader interface, it's a requirement for PrefabEntityOwnership system to work");
|
||||
|
||||
// This path has to be updated with a proper path based where the level lives
|
||||
// Potentially, a level should be a prefab itself
|
||||
m_rootInstance = AZStd::unique_ptr<Prefab::Instance>(m_prefabSystemComponent->CreatePrefab({}, {}, "/"));
|
||||
|
||||
m_sliceOwnershipService.BusConnect(m_entityContextId);
|
||||
m_sliceOwnershipService.m_shouldAssertForLegacySlicesUsage = m_shouldAssertForLegacySlicesUsage;
|
||||
m_editorSliceOwnershipService.BusConnect();
|
||||
m_editorSliceOwnershipService.m_shouldAssertForLegacySlicesUsage = m_shouldAssertForLegacySlicesUsage;
|
||||
}
|
||||
|
||||
bool PrefabEditorEntityOwnershipService::IsInitialized()
|
||||
@@ -34,6 +61,8 @@ namespace AzToolsFramework
|
||||
|
||||
void PrefabEditorEntityOwnershipService::Destroy()
|
||||
{
|
||||
m_editorSliceOwnershipService.BusDisconnect();
|
||||
m_sliceOwnershipService.BusDisconnect();
|
||||
m_rootInstance.reset();
|
||||
}
|
||||
|
||||
@@ -46,7 +75,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_Assert(IsInitialized(), "Tried to add an entity without initializing the Entity Ownership Service");
|
||||
m_rootInstance->AddEntity(*entity);
|
||||
m_entitiesAddedCallback({ entity });
|
||||
HandleEntitiesAdded({ entity });
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::AddEntities(const EntityList& entities)
|
||||
@@ -56,7 +85,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_rootInstance->AddEntity(*entity);
|
||||
}
|
||||
m_entitiesAddedCallback(entities);
|
||||
HandleEntitiesAdded(entities);
|
||||
}
|
||||
|
||||
bool PrefabEditorEntityOwnershipService::DestroyEntity(AZ::Entity* entity)
|
||||
@@ -67,9 +96,11 @@ namespace AzToolsFramework
|
||||
bool PrefabEditorEntityOwnershipService::DestroyEntityById(AZ::EntityId entityId)
|
||||
{
|
||||
AZ_Assert(IsInitialized(), "Tried to destroy an entity without initializing the Entity Ownership Service");
|
||||
AZ_Assert(m_entitiesRemovedCallback, "Callback function for DestroyEntityById has not been set.");
|
||||
AZStd::unique_ptr<AZ::Entity> detachedEntity = m_rootInstance->DetachEntity(entityId);
|
||||
if (detachedEntity)
|
||||
{
|
||||
AzFramework::SliceEntityRequestBus::MultiHandler::BusDisconnect(detachedEntity->GetId());
|
||||
m_entitiesRemovedCallback({ entityId });
|
||||
return true;
|
||||
}
|
||||
@@ -92,8 +123,14 @@ namespace AzToolsFramework
|
||||
{
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::HandleEntitiesAdded(const EntityList& /*entities*/)
|
||||
void PrefabEditorEntityOwnershipService::HandleEntitiesAdded(const EntityList& entities)
|
||||
{
|
||||
AZ_Assert(m_entitiesAddedCallback, "Callback function for AddEntity has not been set.");
|
||||
for (const AZ::Entity* entity : entities)
|
||||
{
|
||||
AzFramework::SliceEntityRequestBus::MultiHandler::BusConnect(entity->GetId());
|
||||
}
|
||||
m_entitiesAddedCallback(entities);
|
||||
}
|
||||
|
||||
bool PrefabEditorEntityOwnershipService::LoadFromStream(AZ::IO::GenericStream& /*stream*/, bool /*remapIds*/,
|
||||
@@ -102,6 +139,28 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::CreatePrefab(
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
|
||||
const AZStd::string& filePath, Prefab::Instance& instanceToParentUnder)
|
||||
{
|
||||
AZStd::unique_ptr<Prefab::Instance> createdPrefabInstance =
|
||||
m_prefabSystemComponent->CreatePrefab(entities, AZStd::move(nestedPrefabInstances), filePath);
|
||||
|
||||
if (createdPrefabInstance)
|
||||
{
|
||||
Prefab::Instance& addedInstance = instanceToParentUnder.AddInstance(AZStd::move(createdPrefabInstance));
|
||||
HandleEntitiesAdded({addedInstance.m_containerEntity.get()});
|
||||
return addedInstance;
|
||||
}
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetRootPrefabInstance()
|
||||
{
|
||||
AZ_Assert(m_rootInstance, "A valid root prefab instance couldn't be found in PrefabEditorEntityOwnershipService.");
|
||||
return *m_rootInstance;
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::SetEntitiesAddedCallback(OnEntitiesAddedCallback onEntitiesAddedCallback)
|
||||
{
|
||||
m_entitiesAddedCallback = AZStd::move(onEntitiesAddedCallback);
|
||||
@@ -116,4 +175,149 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Slice Buses implementation with Assert(false), this will exist only during Slice->Prefab
|
||||
// development to pinpoint and replace specific calls to Slice system
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress PrefabEditorEntityOwnershipService::GetOwningSlice()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return AZ::SliceComponent::SliceInstanceAddress();
|
||||
}
|
||||
|
||||
|
||||
AZ::Data::AssetId UnimplementedSliceEntityOwnershipService::CurrentlyInstantiatingSlice()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return {};
|
||||
}
|
||||
|
||||
bool UnimplementedSliceEntityOwnershipService::HandleRootEntityReloadedFromStream(
|
||||
AZ::Entity*, bool, AZ::SliceComponent::EntityIdToEntityIdMap*)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::SliceComponent* UnimplementedSliceEntityOwnershipService::GetRootSlice()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AZ::SliceComponent::EntityIdToEntityIdMap& UnimplementedSliceEntityOwnershipService::GetLoadedEntityIdMap()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
static AZ::SliceComponent::EntityIdToEntityIdMap dummy;
|
||||
return dummy;
|
||||
}
|
||||
|
||||
AZ::EntityId UnimplementedSliceEntityOwnershipService::FindLoadedEntityIdMapping(const AZ::EntityId&) const
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
AzFramework::SliceInstantiationTicket UnimplementedSliceEntityOwnershipService::InstantiateSlice(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>&,
|
||||
const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&,
|
||||
const AZ::Data::AssetFilterCB&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return AzFramework::SliceInstantiationTicket();
|
||||
}
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress UnimplementedSliceEntityOwnershipService::CloneSliceInstance(
|
||||
AZ::SliceComponent::SliceInstanceAddress, AZ::SliceComponent::EntityIdToEntityIdMap&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return {};
|
||||
}
|
||||
|
||||
void UnimplementedSliceEntityOwnershipService::CancelSliceInstantiation(const AzFramework::SliceInstantiationTicket&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
AzFramework::SliceInstantiationTicket UnimplementedSliceEntityOwnershipService::GenerateSliceInstantiationTicket()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return AzFramework::SliceInstantiationTicket();
|
||||
}
|
||||
|
||||
void UnimplementedSliceEntityOwnershipService::SetIsDynamic(bool)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
const AzFramework::RootSliceAsset& UnimplementedSliceEntityOwnershipService::GetRootAsset() const
|
||||
{
|
||||
static AzFramework::RootSliceAsset dummy;
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return dummy;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AzFramework::SliceInstantiationTicket UnimplementedSliceEditorEntityOwnershipService::InstantiateEditorSlice(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>&, const AZ::Transform&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return AzFramework::SliceInstantiationTicket();
|
||||
}
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress UnimplementedSliceEditorEntityOwnershipService::CloneEditorSliceInstance(
|
||||
AZ::SliceComponent::SliceInstanceAddress, AZ::SliceComponent::EntityIdToEntityIdMap&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress UnimplementedSliceEditorEntityOwnershipService::CloneSubSliceInstance(
|
||||
const AZ::SliceComponent::SliceInstanceAddress&, const AZStd::vector<AZ::SliceComponent::SliceInstanceAddress>&,
|
||||
const AZ::SliceComponent::SliceInstanceAddress&, AZ::SliceComponent::EntityIdToEntityIdMap*)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress UnimplementedSliceEditorEntityOwnershipService::PromoteEditorEntitiesIntoSlice(
|
||||
const AZ::Data::Asset<AZ::SliceAsset>&, const AZ::SliceComponent::EntityIdToEntityIdMap&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return {};
|
||||
}
|
||||
|
||||
void UnimplementedSliceEditorEntityOwnershipService::DetachSliceEntities(const EntityIdList&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
void UnimplementedSliceEditorEntityOwnershipService::DetachSliceInstances(const AZ::SliceComponent::SliceInstanceAddressSet&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
void UnimplementedSliceEditorEntityOwnershipService::DetachSubsliceInstances(const AZ::SliceComponent::SliceInstanceEntityIdRemapList&)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
void UnimplementedSliceEditorEntityOwnershipService::RestoreSliceEntity(
|
||||
AZ::Entity*, const AZ::SliceComponent::EntityRestoreInfo&, SliceEntityRestoreType)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
void UnimplementedSliceEditorEntityOwnershipService::ResetEntitiesToSliceDefaults(EntityIdList)
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
}
|
||||
|
||||
AZ::SliceComponent* UnimplementedSliceEditorEntityOwnershipService::GetEditorRootSlice()
|
||||
{
|
||||
AZ_Assert(!m_shouldAssertForLegacySlicesUsage, "Slice usage with Prefab code enabled");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
+100
@@ -13,6 +13,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Entity/PrefabEntityOwnershipService.h>
|
||||
#include <AzFramework/Entity/SliceEntityOwnershipServiceBus.h>
|
||||
#include <AzFramework/Slice/SliceEntityBus.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -20,10 +24,79 @@ namespace AzToolsFramework
|
||||
{
|
||||
class Instance;
|
||||
class PrefabSystemComponentInterface;
|
||||
class PrefabLoaderInterface;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Implementation with Assert(false), this will exist only during Slice->Prefab
|
||||
// development to pinpoint and replace specific calls to Slice system
|
||||
|
||||
class UnimplementedSliceEntityOwnershipService
|
||||
: public AzFramework::SliceEntityOwnershipServiceRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
bool m_shouldAssertForLegacySlicesUsage = false;
|
||||
private:
|
||||
AZ::Data::AssetId CurrentlyInstantiatingSlice() override;
|
||||
|
||||
bool HandleRootEntityReloadedFromStream(AZ::Entity* rootEntity, bool remapIds,
|
||||
AZ::SliceComponent::EntityIdToEntityIdMap* idRemapTable = nullptr) override;
|
||||
|
||||
AZ::SliceComponent* GetRootSlice() override;
|
||||
|
||||
const AZ::SliceComponent::EntityIdToEntityIdMap& GetLoadedEntityIdMap() override;
|
||||
|
||||
AZ::EntityId FindLoadedEntityIdMapping(const AZ::EntityId& staticId) const override;
|
||||
|
||||
AzFramework::SliceInstantiationTicket InstantiateSlice(const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper& customIdMapper = nullptr,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilter = nullptr) override;
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress CloneSliceInstance(AZ::SliceComponent::SliceInstanceAddress sourceInstance,
|
||||
AZ::SliceComponent::EntityIdToEntityIdMap& sourceToCloneEntityIdMap) override;
|
||||
|
||||
void CancelSliceInstantiation(const AzFramework::SliceInstantiationTicket& ticket) override;
|
||||
AzFramework::SliceInstantiationTicket GenerateSliceInstantiationTicket() override;
|
||||
void SetIsDynamic(bool isDynamic) override;
|
||||
const AzFramework::RootSliceAsset& GetRootAsset() const override;
|
||||
};
|
||||
|
||||
class UnimplementedSliceEditorEntityOwnershipService
|
||||
: public AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
bool m_shouldAssertForLegacySlicesUsage = false;
|
||||
private:
|
||||
AzFramework::SliceInstantiationTicket InstantiateEditorSlice(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& sliceAsset, const AZ::Transform& worldTransform) override;
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress CloneEditorSliceInstance(
|
||||
AZ::SliceComponent::SliceInstanceAddress sourceInstance,
|
||||
AZ::SliceComponent::EntityIdToEntityIdMap& sourceToCloneEntityIdMap) override;
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress CloneSubSliceInstance(
|
||||
const AZ::SliceComponent::SliceInstanceAddress& sourceSliceInstanceAddress,
|
||||
const AZStd::vector<AZ::SliceComponent::SliceInstanceAddress>& sourceSubSliceInstanceAncestry,
|
||||
const AZ::SliceComponent::SliceInstanceAddress& sourceSubSliceInstanceAddress,
|
||||
AZ::SliceComponent::EntityIdToEntityIdMap* out_sourceToCloneEntityIdMap) override;
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress PromoteEditorEntitiesIntoSlice(
|
||||
const AZ::Data::Asset<AZ::SliceAsset>& sliceAsset, const AZ::SliceComponent::EntityIdToEntityIdMap& liveToAssetMap) override;
|
||||
|
||||
void DetachSliceEntities(const EntityIdList& entities) override;
|
||||
void DetachSliceInstances(const AZ::SliceComponent::SliceInstanceAddressSet& instances) override;
|
||||
void DetachSubsliceInstances(const AZ::SliceComponent::SliceInstanceEntityIdRemapList& subsliceRootList) override;
|
||||
void RestoreSliceEntity(
|
||||
AZ::Entity* entity, const AZ::SliceComponent::EntityRestoreInfo& info, SliceEntityRestoreType restoreType) override;
|
||||
void ResetEntitiesToSliceDefaults(EntityIdList entities) override;
|
||||
AZ::SliceComponent* GetEditorRootSlice() override;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PrefabEditorEntityOwnershipService
|
||||
: public AzFramework::PrefabEntityOwnershipService
|
||||
, private PrefabEditorEntityOwnershipInterface
|
||||
, private AzFramework::SliceEntityRequestBus::MultiHandler
|
||||
{
|
||||
public:
|
||||
using EntityList = AzFramework::EntityList;
|
||||
@@ -31,6 +104,11 @@ namespace AzToolsFramework
|
||||
using OnEntitiesRemovedCallback = AzFramework::OnEntitiesRemovedCallback;
|
||||
using ValidateEntitiesCallback = AzFramework::ValidateEntitiesCallback;
|
||||
|
||||
explicit PrefabEditorEntityOwnershipService(
|
||||
const AzFramework::EntityContextId& entityContextId, AZ::SerializeContext* serializeContext);
|
||||
|
||||
~PrefabEditorEntityOwnershipService();
|
||||
|
||||
//! Initializes all assets/entities/components required for managing entities.
|
||||
void Initialize() override;
|
||||
|
||||
@@ -83,11 +161,33 @@ namespace AzToolsFramework
|
||||
void SetValidateEntitiesCallback(ValidateEntitiesCallback validateEntitiesCallback) override;
|
||||
|
||||
protected:
|
||||
|
||||
AZ::SliceComponent::SliceInstanceAddress GetOwningSlice() override;
|
||||
|
||||
private:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// PrefabSystemComponentInterface interface implementation
|
||||
Prefab::InstanceOptionalReference CreatePrefab(
|
||||
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
|
||||
const AZStd::string& filePath, Prefab::Instance& instanceToParentUnder) override;
|
||||
|
||||
Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OnEntitiesAddedCallback m_entitiesAddedCallback;
|
||||
OnEntitiesRemovedCallback m_entitiesRemovedCallback;
|
||||
ValidateEntitiesCallback m_validateEntitiesCallback;
|
||||
|
||||
UnimplementedSliceEntityOwnershipService m_sliceOwnershipService;
|
||||
UnimplementedSliceEditorEntityOwnershipService m_editorSliceOwnershipService;
|
||||
|
||||
AZStd::string m_rootPath;
|
||||
AZStd::unique_ptr<Prefab::Instance> m_rootInstance;
|
||||
Prefab::PrefabSystemComponentInterface* m_prefabSystemComponent;
|
||||
|
||||
Prefab::PrefabLoaderInterface* m_loaderInterface;
|
||||
AzFramework::EntityContextId m_entityContextId;
|
||||
AZ::SerializeContext m_serializeContext;
|
||||
};
|
||||
}
|
||||
|
||||
+3
-24
@@ -119,8 +119,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
AngularManipulator::AngularManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
AttachLeftMouseDownImpl();
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace AzToolsFramework
|
||||
|
||||
// calculate initial state when mouse press first happens
|
||||
m_actionInternal = CalculateManipulationDataStart(
|
||||
m_fixed, TransformNormalizedScale(m_worldFromLocal), TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, TransformNormalizedScale(GetSpace()), TransformNormalizedScale(GetLocalTransform()),
|
||||
interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
|
||||
rayIntersectionDistance);
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace AzToolsFramework
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
m_worldFromLocal * m_localTransform,
|
||||
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
|
||||
AZ::Vector3::CreateZero(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
@@ -210,27 +210,6 @@ namespace AzToolsFramework
|
||||
m_fixed.m_axis = axis;
|
||||
}
|
||||
|
||||
void AngularManipulator::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
m_worldFromLocal = worldFromLocal;
|
||||
}
|
||||
|
||||
void AngularManipulator::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void AngularManipulator::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void AngularManipulator::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void AngularManipulator::SetView(AZStd::unique_ptr<ManipulatorView>&& view)
|
||||
{
|
||||
m_manipulatorView = AZStd::move(view);
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace AzToolsFramework
|
||||
/// in the opposite direction the rotation axis points to.
|
||||
class AngularManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalTransform
|
||||
{
|
||||
/// Private constructor.
|
||||
explicit AngularManipulator(const AZ::Transform& worldFromLocal);
|
||||
@@ -81,12 +82,6 @@ namespace AzToolsFramework
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetAxis(const AZ::Vector3& axis);
|
||||
void SetSpace(const AZ::Transform& worldFromLocal);
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
|
||||
AZ::Vector3 GetPosition() const { return m_localTransform.GetTranslation(); }
|
||||
const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; }
|
||||
|
||||
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
|
||||
@@ -133,9 +128,6 @@ namespace AzToolsFramework
|
||||
CurrentInternal m_current;
|
||||
};
|
||||
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform of the manipulator.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
|
||||
Fixed m_fixed;
|
||||
ActionInternal m_actionInternal;
|
||||
|
||||
@@ -155,4 +147,4 @@ namespace AzToolsFramework
|
||||
const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
|
||||
ViewportInteraction::KeyboardModifiers keyboardModifiers);
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -26,8 +26,8 @@ namespace AzToolsFramework
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(BaseManipulator, AZ::SystemAllocator, 0)
|
||||
|
||||
static bool EntityIdAndEntityComponentIdComparison(
|
||||
const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId)
|
||||
static bool EntityIdAndEntityComponentIdComparison(
|
||||
const AZ::EntityId entityId, const AZ::EntityComponentIdPair& entityComponentId)
|
||||
{
|
||||
return entityId == entityComponentId.GetEntityId();
|
||||
}
|
||||
@@ -347,64 +347,64 @@ namespace AzToolsFramework
|
||||
void Manipulators::Register(const ManipulatorManagerId manipulatorManagerId)
|
||||
{
|
||||
ProcessManipulators([manipulatorManagerId](BaseManipulator* manipulator)
|
||||
{
|
||||
manipulator->Register(manipulatorManagerId);
|
||||
});
|
||||
{
|
||||
manipulator->Register(manipulatorManagerId);
|
||||
});
|
||||
}
|
||||
|
||||
void Manipulators::Unregister()
|
||||
{
|
||||
ProcessManipulators([](BaseManipulator* manipulator)
|
||||
{
|
||||
if (manipulator->Registered())
|
||||
{
|
||||
manipulator->Unregister();
|
||||
}
|
||||
});
|
||||
if (manipulator->Registered())
|
||||
{
|
||||
manipulator->Unregister();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Manipulators::SetBoundsDirty()
|
||||
{
|
||||
ProcessManipulators([](BaseManipulator* manipulator)
|
||||
{
|
||||
manipulator->SetBoundsDirty();
|
||||
});
|
||||
{
|
||||
manipulator->SetBoundsDirty();
|
||||
});
|
||||
}
|
||||
|
||||
void Manipulators::AddEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair)
|
||||
{
|
||||
ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator)
|
||||
{
|
||||
manipulator->AddEntityComponentIdPair(entityComponentIdPair);
|
||||
});
|
||||
{
|
||||
manipulator->AddEntityComponentIdPair(entityComponentIdPair);
|
||||
});
|
||||
}
|
||||
|
||||
void Manipulators::RemoveEntityComponentIdPair(const AZ::EntityComponentIdPair& entityComponentIdPair)
|
||||
{
|
||||
ProcessManipulators([&entityComponentIdPair](BaseManipulator* manipulator)
|
||||
{
|
||||
manipulator->RemoveEntityComponentIdPair(entityComponentIdPair);
|
||||
});
|
||||
{
|
||||
manipulator->RemoveEntityComponentIdPair(entityComponentIdPair);
|
||||
});
|
||||
}
|
||||
|
||||
void Manipulators::RemoveEntityId(const AZ::EntityId entityId)
|
||||
{
|
||||
ProcessManipulators([entityId](BaseManipulator* manipulator)
|
||||
{
|
||||
manipulator->RemoveEntityId(entityId);
|
||||
});
|
||||
{
|
||||
manipulator->RemoveEntityId(entityId);
|
||||
});
|
||||
}
|
||||
|
||||
bool Manipulators::PerformingAction()
|
||||
{
|
||||
bool performingAction = false;
|
||||
ProcessManipulators([&performingAction](BaseManipulator* manipulator)
|
||||
{
|
||||
if (manipulator->PerformingAction())
|
||||
{
|
||||
performingAction = true;
|
||||
}
|
||||
});
|
||||
if (manipulator->PerformingAction())
|
||||
{
|
||||
performingAction = true;
|
||||
}
|
||||
});
|
||||
|
||||
return performingAction;
|
||||
}
|
||||
@@ -413,16 +413,56 @@ namespace AzToolsFramework
|
||||
{
|
||||
bool registered = false;
|
||||
ProcessManipulators([®istered](BaseManipulator* manipulator)
|
||||
{
|
||||
if (manipulator->Registered())
|
||||
{
|
||||
registered = true;
|
||||
}
|
||||
});
|
||||
if (manipulator->Registered())
|
||||
{
|
||||
registered = true;
|
||||
}
|
||||
});
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
const AZ::Transform& Manipulators::GetLocalTransform() const
|
||||
{
|
||||
return m_manipulatorSpaceWithLocalTransform.GetLocalTransform();
|
||||
}
|
||||
|
||||
const AZ::Transform& Manipulators::GetSpace() const
|
||||
{
|
||||
return m_manipulatorSpaceWithLocalTransform.GetSpace();
|
||||
}
|
||||
|
||||
void Manipulators::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
|
||||
SetSpaceImpl(worldFromLocal);
|
||||
}
|
||||
|
||||
void Manipulators::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_manipulatorSpaceWithLocalTransform.SetLocalTransform(localTransform);
|
||||
SetLocalTransformImpl(localTransform);
|
||||
}
|
||||
|
||||
void Manipulators::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_manipulatorSpaceWithLocalTransform.SetLocalPosition(localPosition);
|
||||
SetLocalPositionImpl(localPosition);
|
||||
}
|
||||
|
||||
void Manipulators::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_manipulatorSpaceWithLocalTransform.SetLocalOrientation(localOrientation);
|
||||
SetLocalOrientationImpl(localOrientation);
|
||||
}
|
||||
|
||||
void Manipulators::SetNonUniformScale(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
m_manipulatorSpaceWithLocalTransform.SetNonUniformScale(nonUniformScale);
|
||||
SetNonUniformScaleImpl(nonUniformScale);
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
bool CalculateRayPlaneIntersectingPoint(const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/smart_ptr/enable_shared_from_this.h>
|
||||
#include <AzToolsFramework/Manipulators/ManipulatorBus.h>
|
||||
#include "ManipulatorSpace.h"
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
@@ -248,24 +249,33 @@ namespace AzToolsFramework
|
||||
bool PerformingAction();
|
||||
bool Registered();
|
||||
|
||||
const AZ::Transform& GetLocalTransform() const { return m_localTransform; }
|
||||
const AZ::Transform& GetSpace() const { return m_space; }
|
||||
|
||||
virtual void SetSpace(const AZ::Transform& worldFromLocal) = 0;
|
||||
virtual void SetLocalTransform(const AZ::Transform& localTransform) = 0;
|
||||
virtual void SetLocalPosition(const AZ::Vector3& localPosition) = 0;
|
||||
virtual void SetLocalOrientation(const AZ::Quaternion& localOrientation) = 0;
|
||||
|
||||
/// Refresh the Manipulator and/or View based on the current view position.
|
||||
virtual void RefreshView(const AZ::Vector3& /*worldViewPosition*/) {}
|
||||
|
||||
const AZ::Transform& GetLocalTransform() const;
|
||||
const AZ::Transform& GetSpace() const;
|
||||
const AZ::Vector3& GetNonUniformScale() const;
|
||||
void SetSpace(const AZ::Transform& worldFromLocal);
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
void SetNonUniformScale(const AZ::Vector3& nonUniformScale);
|
||||
|
||||
protected:
|
||||
/// Common processing for base manipulator type - Implement for all
|
||||
/// individual manipulators used in an aggregate manipulator.
|
||||
virtual void ProcessManipulators(const AZStd::function<void(BaseManipulator*)>&) = 0;
|
||||
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local space transform of Manipulators.
|
||||
AZ::Transform m_space = AZ::Transform::CreateIdentity(); ///< Space the Manipulators are in.
|
||||
///@{
|
||||
/// Allows implementers to perform additional logic when updating the location of the manipulator group.
|
||||
virtual void SetSpaceImpl([[maybe_unused]] const AZ::Transform& worldFromLocal) {}
|
||||
virtual void SetLocalTransformImpl([[maybe_unused]] const AZ::Transform& localTransform) {}
|
||||
virtual void SetLocalPositionImpl([[maybe_unused]] const AZ::Vector3& localPosition) {}
|
||||
virtual void SetLocalOrientationImpl([[maybe_unused]] const AZ::Quaternion& localOrientation) {}
|
||||
virtual void SetNonUniformScaleImpl([[maybe_unused]] const AZ::Vector3& nonUniformScale) {}
|
||||
///@}
|
||||
|
||||
ManipulatorSpaceWithLocalTransform m_manipulatorSpaceWithLocalTransform; ///< The space and local transform for the manipulators.
|
||||
};
|
||||
|
||||
namespace Internal
|
||||
|
||||
+11
-6
@@ -176,7 +176,7 @@ namespace AzToolsFramework
|
||||
updated, fixedVertices, &AZ::FixedVerticesRequestBus<Vertex>::Handler::UpdateVertex,
|
||||
vertex.m_index, vertexPosition);
|
||||
|
||||
m_selectionManipulators[vertex.m_index]->SetPosition(AZ::AdaptVertexOut(vertexPosition));
|
||||
m_selectionManipulators[vertex.m_index]->SetLocalPosition(AZ::AdaptVertexOut(vertexPosition));
|
||||
});
|
||||
|
||||
m_translationManipulator->m_manipulator.SetLocalPosition(
|
||||
@@ -241,7 +241,8 @@ namespace AzToolsFramework
|
||||
|
||||
// create a new translation manipulator bound for the selected vertexIndex
|
||||
m_translationManipulator = AZStd::make_shared<IndexedTranslationManipulator<Vertex>>(
|
||||
Dimensions(), vertexIndex, vertex, WorldFromLocalWithUniformScale(entityComponentIdPair.GetEntityId()));
|
||||
Dimensions(), vertexIndex, vertex, WorldFromLocalWithUniformScale(entityComponentIdPair.GetEntityId()),
|
||||
GetNonUniformScale(entityComponentIdPair.GetEntityId()));
|
||||
|
||||
// setup how the manipulator should look
|
||||
m_manipulatorConfiguratorFn(&m_translationManipulator->m_manipulator);
|
||||
@@ -524,12 +525,13 @@ namespace AzToolsFramework
|
||||
vertexIndex, vertex);
|
||||
|
||||
m_selectionManipulators.push_back(SelectionManipulator::MakeShared(
|
||||
WorldFromLocalWithUniformScale(GetEntityId())));
|
||||
WorldFromLocalWithUniformScale(GetEntityId()),
|
||||
GetNonUniformScale(GetEntityId())));
|
||||
const auto& selectionManipulator = m_selectionManipulators.back();
|
||||
|
||||
selectionManipulator->Register(managerId);
|
||||
selectionManipulator->AddEntityComponentIdPair(entityComponentIdPair);
|
||||
selectionManipulator->SetPosition(AdaptVertexOut(vertex));
|
||||
selectionManipulator->SetLocalPosition(AdaptVertexOut(vertex));
|
||||
|
||||
SetupSelectionManipulator(selectionManipulator, entityComponentIdPair, managerId, vertexIndex);
|
||||
}
|
||||
@@ -975,7 +977,7 @@ namespace AzToolsFramework
|
||||
|
||||
if (found)
|
||||
{
|
||||
m_selectionManipulators[manipulatorIndex]->SetPosition(AZ::AdaptVertexOut(vertex));
|
||||
m_selectionManipulators[manipulatorIndex]->SetLocalPosition(AZ::AdaptVertexOut(vertex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,23 +992,26 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
template<typename Vertex>
|
||||
void EditorVertexSelectionBase<Vertex>::RefreshSpace(const AZ::Transform& worldFromLocal)
|
||||
void EditorVertexSelectionBase<Vertex>::RefreshSpace(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
||||
|
||||
for (auto& manipulator : m_selectionManipulators)
|
||||
{
|
||||
manipulator->SetSpace(TransformUniformScale(worldFromLocal));
|
||||
manipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
|
||||
if (m_translationManipulator)
|
||||
{
|
||||
m_translationManipulator->m_manipulator.SetSpace(TransformUniformScale(worldFromLocal));
|
||||
m_translationManipulator->m_manipulator.SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
|
||||
if (m_hoverSelection)
|
||||
{
|
||||
m_hoverSelection->SetSpace(TransformUniformScale(worldFromLocal));
|
||||
m_hoverSelection->SetNonUniformScale(nonUniformScale);
|
||||
m_hoverSelection->Refresh();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -122,8 +122,8 @@ namespace AzToolsFramework
|
||||
/// Update the translation manipulator to be correctly positioned based
|
||||
/// on the current selection (recenter it).
|
||||
void RefreshTranslationManipulator();
|
||||
/// Update manipulators based on changes to the entities transform.
|
||||
void RefreshSpace(const AZ::Transform& worldFromLocal);
|
||||
/// Update manipulators based on changes to the entity's transform and non-uniform scale.
|
||||
void RefreshSpace(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
|
||||
|
||||
/// Set bounds dirty (need recalculating) for all owned manipulators (selection, translation, hover).
|
||||
void SetBoundsDirty();
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace AzToolsFramework
|
||||
virtual void SetBoundsDirty() = 0;
|
||||
virtual void Refresh() = 0;
|
||||
virtual void SetSpace(const AZ::Transform& worldFromLocal) = 0;
|
||||
virtual void SetNonUniformScale(const AZ::Vector3& nonUniformScale) = 0;
|
||||
};
|
||||
|
||||
/// NullHoverSelection is used when vertices cannot be inserted. This serves as a no-op
|
||||
@@ -47,5 +48,6 @@ namespace AzToolsFramework
|
||||
void SetBoundsDirty() override {}
|
||||
void Refresh() override {}
|
||||
void SetSpace(const AZ::Transform& /*worldFromLocal*/) override {}
|
||||
void SetNonUniformScale([[maybe_unused]] const AZ::Vector3& nonUniformScale) override {}
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace AzToolsFramework
|
||||
lineSegmentManipulator->Register(managerId);
|
||||
lineSegmentManipulator->AddEntityComponentIdPair(entityComponentIdPair);
|
||||
lineSegmentManipulator->SetSpace(WorldFromLocalWithUniformScale(entityComponentIdPair.GetEntityId()));
|
||||
lineSegmentManipulator->SetNonUniformScale(GetNonUniformScale(entityComponentIdPair.GetEntityId()));
|
||||
|
||||
UpdateLineSegmentPosition<Vertex>(vertIndex, entityComponentIdPair.GetEntityId(), *lineSegmentManipulator);
|
||||
|
||||
@@ -174,6 +175,15 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Vertex>
|
||||
void LineSegmentHoverSelection<Vertex>::SetNonUniformScale(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
for (auto& lineSegmentManipulator : m_lineSegmentManipulators)
|
||||
{
|
||||
lineSegmentManipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
}
|
||||
|
||||
template class LineSegmentHoverSelection<AZ::Vector2>;
|
||||
template class LineSegmentHoverSelection<AZ::Vector3>;
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -45,9 +45,10 @@ namespace AzToolsFramework
|
||||
void SetBoundsDirty() override;
|
||||
void Refresh() override;
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) override;
|
||||
void SetNonUniformScale(const AZ::Vector3& nonUniformScale) override;
|
||||
|
||||
private:
|
||||
AZ::EntityId m_entityId;
|
||||
AZStd::vector<AZStd::shared_ptr<LineSegmentSelectionManipulator>> m_lineSegmentManipulators; ///< Manipulators for each line.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+8
-8
@@ -20,18 +20,18 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
LineSegmentSelectionManipulator::Action CalculateManipulationDataAction(
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
|
||||
const float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd)
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin,
|
||||
const AZ::Vector3& rayDirection, const float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd)
|
||||
{
|
||||
AZ::Vector3 worldClosestPositionRay, worldClosestPositionLineSegment;
|
||||
float rayProportion, lineSegmentProportion;
|
||||
AZ::Intersect::ClosestSegmentSegment(
|
||||
rayOrigin, rayOrigin + rayDirection * rayLength,
|
||||
worldFromLocal.TransformPoint(localStart), worldFromLocal.TransformPoint(localEnd),
|
||||
worldFromLocal.TransformPoint(nonUniformScale * localStart), worldFromLocal.TransformPoint(nonUniformScale * localEnd),
|
||||
rayProportion, lineSegmentProportion, worldClosestPositionRay, worldClosestPositionLineSegment);
|
||||
|
||||
AZ::Transform worldFromLocalNormalized = worldFromLocal;
|
||||
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractScale();
|
||||
const AZ::Vector3 scale = worldFromLocalNormalized.ExtractScale() * nonUniformScale;
|
||||
const AZ::Transform localFromWorldNormalized = worldFromLocalNormalized.GetInverse();
|
||||
|
||||
return { (localFromWorldNormalized.TransformPoint(worldClosestPositionLineSegment)) / scale };
|
||||
@@ -75,7 +75,7 @@ namespace AzToolsFramework
|
||||
&ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState);
|
||||
|
||||
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
|
||||
TransformUniformScale(m_worldFromLocal), interaction.m_mousePick.m_rayOrigin,
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(), interaction.m_mousePick.m_rayOrigin,
|
||||
interaction.m_mousePick.m_rayDirection, cameraState.m_farClip, m_localStart, m_localEnd));
|
||||
}
|
||||
}
|
||||
@@ -90,8 +90,8 @@ namespace AzToolsFramework
|
||||
&ViewportInteraction::ViewportInteractionRequestBus::Events::GetCameraState);
|
||||
|
||||
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
|
||||
TransformUniformScale(m_worldFromLocal), interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection,
|
||||
cameraState.m_farClip, m_localStart, m_localEnd));
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(), interaction.m_mousePick.m_rayOrigin,
|
||||
interaction.m_mousePick.m_rayDirection, cameraState.m_farClip, m_localStart, m_localEnd));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace AzToolsFramework
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
m_localStart, MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
|
||||
+3
-4
@@ -23,6 +23,7 @@ namespace AzToolsFramework
|
||||
/// A manipulator to expose where on a line a user is moving their mouse.
|
||||
class LineSegmentSelectionManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpace
|
||||
{
|
||||
/// Private constructor.
|
||||
LineSegmentSelectionManipulator();
|
||||
@@ -56,7 +57,6 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) { m_worldFromLocal = worldFromLocal; }
|
||||
void SetStart(const AZ::Vector3& startLocal) { m_localStart = startLocal; }
|
||||
void SetEnd(const AZ::Vector3& endLocal) { m_localEnd = endLocal; }
|
||||
const AZ::Vector3& GetStart() const { return m_localStart; }
|
||||
@@ -73,7 +73,6 @@ namespace AzToolsFramework
|
||||
void InvalidateImpl() override;
|
||||
void SetBoundsDirtyImpl() override;
|
||||
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
AZ::Vector3 m_localStart = AZ::Vector3::CreateZero();
|
||||
AZ::Vector3 m_localEnd = AZ::Vector3::CreateZero();
|
||||
|
||||
@@ -86,6 +85,6 @@ namespace AzToolsFramework
|
||||
};
|
||||
|
||||
LineSegmentSelectionManipulator::Action CalculateManipulationDataAction(
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& rayOrigin, const AZ::Vector3& rayDirection,
|
||||
float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd);
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Vector3& rayOrigin,
|
||||
const AZ::Vector3& rayDirection, float rayLength, const AZ::Vector3& localStart, const AZ::Vector3& localEnd);
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+32
-44
@@ -22,13 +22,13 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
LinearManipulator::Starter CalculateLinearManipulationDataStart(
|
||||
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
const float intersectionDistance, const AzFramework::CameraState& cameraState)
|
||||
{
|
||||
const ManipulatorInteraction manipulatorInteraction =
|
||||
BuildManipulatorInteraction(
|
||||
worldFromLocal, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
|
||||
const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis);
|
||||
const AZ::Vector3 rayCrossAxis = manipulatorInteraction.m_localRayDirection.Cross(axis);
|
||||
@@ -37,7 +37,9 @@ namespace AzToolsFramework
|
||||
LinearManipulator::StartTransition startTransition;
|
||||
// initialize m_localHitPosition to handle edge case where CalculateRayPlaneIntersectingPoint
|
||||
// fails because ray is parallel to the plane
|
||||
start.m_localHitPosition = localTransform.GetTranslation();
|
||||
// localTransform is in the reference frame of the object being manipulated (i.e. the world rotation, translation and uniform scale
|
||||
// from the world transform have been extracted), but non-uniform scale has to be accounted for separately
|
||||
start.m_localHitPosition = nonUniformScale * localTransform.GetTranslation();
|
||||
startTransition.m_localNormal = rayCrossAxis.Cross(axis).GetNormalizedSafe();
|
||||
|
||||
// initial intersect point
|
||||
@@ -84,12 +86,12 @@ namespace AzToolsFramework
|
||||
|
||||
LinearManipulator::Action CalculateLinearManipulationDataAction(
|
||||
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
|
||||
const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction)
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
const ManipulatorInteraction manipulatorInteraction =
|
||||
BuildManipulatorInteraction(
|
||||
worldFromLocal, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
|
||||
const auto& [startTransition, start] = starter;
|
||||
|
||||
@@ -106,10 +108,13 @@ namespace AzToolsFramework
|
||||
GetCameraState(interaction.m_interactionId.m_viewportId));
|
||||
|
||||
const AZ::Vector3 axis = TransformDirectionNoScaling(localTransform, fixed.m_axis);
|
||||
const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition);
|
||||
// The local positions have been transformed to the reference frame of the object being manipulated. But they appear in the world
|
||||
// with non-uniform scale applied, and the object being manipulated will want to work with unscaled deltas, so we need to divide by
|
||||
// the non-uniform scale here.
|
||||
const AZ::Vector3 hitDelta = (localHitPosition - start.m_localHitPosition) / nonUniformScale;
|
||||
const AZ::Vector3 unsnappedOffset = axis * axis.Dot(hitDelta);
|
||||
|
||||
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
|
||||
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal * axis.Dot(manipulatorInteraction.m_nonUniformScaleReciprocal);
|
||||
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
|
||||
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
|
||||
|
||||
@@ -123,7 +128,7 @@ namespace AzToolsFramework
|
||||
action.m_viewportId = interaction.m_interactionId.m_viewportId;
|
||||
|
||||
const AZ::Quaternion localRotation = QuaternionFromTransformNoScaling(localTransform);
|
||||
const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale;
|
||||
const AZ::Vector3 scaledUnsnappedOffset = unsnappedOffset * startTransition.m_screenToWorldScale * NonUniformScaleReciprocal(nonUniformScale);
|
||||
// how much to adjust the scale based on movement
|
||||
const AZ::Quaternion invLocalRotation = localRotation.GetInverseFull();
|
||||
action.m_current.m_localScaleOffset = snapping
|
||||
@@ -142,8 +147,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
LinearManipulator::LinearManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
AttachLeftMouseDownImpl();
|
||||
}
|
||||
|
||||
@@ -165,19 +170,19 @@ namespace AzToolsFramework
|
||||
void LinearManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
|
||||
m_starter = CalculateLinearManipulationDataStart(
|
||||
m_fixed, worldFromLocalUniformScale, m_localTransform,
|
||||
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction, rayIntersectionDistance,
|
||||
GetCameraState(interaction.m_interactionId.m_viewportId));
|
||||
|
||||
if (m_onLeftMouseDownCallback)
|
||||
{
|
||||
m_onLeftMouseDownCallback(CalculateLinearManipulationDataAction(
|
||||
m_fixed, m_starter, worldFromLocalUniformScale, m_localTransform,
|
||||
m_fixed, m_starter, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -190,7 +195,7 @@ namespace AzToolsFramework
|
||||
|
||||
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
|
||||
m_onMouseMoveCallback(CalculateLinearManipulationDataAction(
|
||||
m_fixed, m_starter, TransformUniformScale(m_worldFromLocal), m_localTransform,
|
||||
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -203,7 +208,7 @@ namespace AzToolsFramework
|
||||
|
||||
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
|
||||
m_onLeftMouseUpCallback(CalculateLinearManipulationDataAction(
|
||||
m_fixed, m_starter, TransformUniformScale(m_worldFromLocal), m_localTransform,
|
||||
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -216,8 +221,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
const AZ::Transform localTransform = m_useVisualsOverride
|
||||
? AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
m_visualOrientationOverride, m_localTransform.GetTranslation())
|
||||
: m_localTransform;
|
||||
m_visualOrientationOverride, GetLocalPosition())
|
||||
: GetLocalTransform();
|
||||
|
||||
if (cl_manipulatorDrawDebug)
|
||||
{
|
||||
@@ -227,17 +232,19 @@ namespace AzToolsFramework
|
||||
GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
|
||||
|
||||
const auto action = CalculateLinearManipulationDataAction(
|
||||
m_fixed, m_starter, TransformUniformScale(m_worldFromLocal), m_localTransform,
|
||||
m_fixed, m_starter, TransformUniformScale(GetSpace()), GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
|
||||
|
||||
// display the exact hit (ray intersection) of the mouse pick on the manipulator
|
||||
DrawTransformAxes(
|
||||
debugDisplay, TransformUniformScale(m_worldFromLocal) *
|
||||
debugDisplay, TransformUniformScale(GetSpace()) *
|
||||
AZ::Transform::CreateTranslation(
|
||||
action.m_start.m_localHitPosition + action.m_current.m_localPositionOffset));
|
||||
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localPositionOffset));
|
||||
}
|
||||
|
||||
const AZ::Transform combined = TransformUniformScale(m_worldFromLocal) * localTransform;
|
||||
AZ::Transform combined = GetLocalTransform();
|
||||
combined.SetTranslation(GetNonUniformScale() * combined.GetTranslation());
|
||||
combined = GetSpace() * combined;
|
||||
|
||||
DrawTransformAxes(debugDisplay, combined);
|
||||
DrawAxis(
|
||||
@@ -246,10 +253,12 @@ namespace AzToolsFramework
|
||||
|
||||
for (auto& view : m_manipulatorViews)
|
||||
{
|
||||
auto nonUniformScale = GetNonUniformScale();
|
||||
|
||||
view->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
m_worldFromLocal * localTransform,
|
||||
ApplySpace(localTransform), GetNonUniformScale(),
|
||||
AZ::Vector3::CreateZero(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
@@ -261,27 +270,6 @@ namespace AzToolsFramework
|
||||
m_fixed.m_axis = axis;
|
||||
}
|
||||
|
||||
void LinearManipulator::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
m_worldFromLocal = worldFromLocal;
|
||||
}
|
||||
|
||||
void LinearManipulator::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void LinearManipulator::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void LinearManipulator::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void LinearManipulator::InvalidateImpl()
|
||||
{
|
||||
for (auto& view : m_manipulatorViews)
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace AzToolsFramework
|
||||
/// in one dimension on an axis defined in 3D space.
|
||||
class LinearManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalTransform
|
||||
{
|
||||
/// Private constructor.
|
||||
explicit LinearManipulator(const AZ::Transform& worldFromLocal);
|
||||
@@ -116,12 +117,6 @@ namespace AzToolsFramework
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetAxis(const AZ::Vector3& axis);
|
||||
void SetSpace(const AZ::Transform& worldFromLocal);
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
|
||||
AZ::Vector3 GetPosition() const { return m_localTransform.GetTranslation(); }
|
||||
const AZ::Vector3& GetAxis() const { return m_fixed.m_axis; }
|
||||
|
||||
template<typename Views>
|
||||
@@ -151,9 +146,6 @@ namespace AzToolsFramework
|
||||
void InvalidateImpl() override;
|
||||
void SetBoundsDirtyImpl() override;
|
||||
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform of the manipulator.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
|
||||
bool m_useVisualsOverride = false; // Set this to true to use the Visual Quaternion Override (decoupled from logical axis).
|
||||
AZ::Quaternion m_visualOrientationOverride = AZ::Quaternion::CreateIdentity(); // Quaternion to use only for visuals.
|
||||
|
||||
@@ -168,12 +160,12 @@ namespace AzToolsFramework
|
||||
};
|
||||
|
||||
LinearManipulator::Starter CalculateLinearManipulationDataStart(
|
||||
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
const LinearManipulator::Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
float intersectionDistance, const AzFramework::CameraState& cameraState);
|
||||
|
||||
LinearManipulator::Action CalculateLinearManipulationDataAction(
|
||||
const LinearManipulator::Fixed& fixed, const LinearManipulator::Starter& starter,
|
||||
const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction);
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+4
-2
@@ -49,14 +49,16 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
ManipulatorInteraction BuildManipulatorInteraction(
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection)
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniform = AzToolsFramework::TransformUniformScale(worldFromLocal);
|
||||
const AZ::Transform localFromWorldUniform = worldFromLocalUniform.GetInverse();
|
||||
|
||||
return {localFromWorldUniform.TransformPoint(worldRayOrigin),
|
||||
TransformDirectionNoScaling(localFromWorldUniform, worldRayDirection),
|
||||
ScaleReciprocal(worldFromLocalUniform)};
|
||||
ScaleReciprocal(worldFromLocalUniform),
|
||||
NonUniformScaleReciprocal(nonUniformScale)};
|
||||
}
|
||||
|
||||
AZ::Vector3 CalculateSnappedOffset(
|
||||
|
||||
+16
-1
@@ -47,11 +47,14 @@ namespace AzToolsFramework
|
||||
AZ::Vector3 m_localRayDirection; ///< The ray direction in the reference from of the manipulator.
|
||||
float m_scaleReciprocal; ///< The scale reciprocal (1.0 / scale) of the transform used to move the
|
||||
///< ray from world space to local space.
|
||||
AZ::Vector3 m_nonUniformScaleReciprocal; ///< Handles inverting any non-uniform scale which was applied
|
||||
///< separately from the transform.
|
||||
};
|
||||
|
||||
/// Build a ManipulatorInteraction structure from the incoming viewport interaction.
|
||||
ManipulatorInteraction BuildManipulatorInteraction(
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection);
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Vector3& worldRayOrigin, const AZ::Vector3& worldRayDirection);
|
||||
|
||||
/// Calculate the offset along an axis to adjust a position
|
||||
/// to stay snapped to a given grid size.
|
||||
@@ -112,4 +115,16 @@ namespace AzToolsFramework
|
||||
{
|
||||
return Round3(transform.GetScale().GetReciprocal().GetMinElement());
|
||||
}
|
||||
|
||||
/// Find the reciprocal of the non-uniform scale.
|
||||
/// Each element will be rounded to three significant digits to eliminate noise
|
||||
/// when dealing with values far from the origin.
|
||||
inline AZ::Vector3 NonUniformScaleReciprocal(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
AZ::Vector3 scaleReciprocal = nonUniformScale.GetReciprocal();
|
||||
return AZ::Vector3(
|
||||
Round3(scaleReciprocal.GetX()),
|
||||
Round3(scaleReciprocal.GetY()),
|
||||
Round3(scaleReciprocal.GetZ()));
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ManipulatorSpace.h"
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
const AZ::Transform& ManipulatorSpace::GetSpace() const
|
||||
{
|
||||
return m_space;
|
||||
}
|
||||
|
||||
void ManipulatorSpace::SetSpace(const AZ::Transform& space)
|
||||
{
|
||||
m_space = space;
|
||||
}
|
||||
|
||||
const AZ::Vector3& ManipulatorSpace::GetNonUniformScale() const
|
||||
{
|
||||
return m_nonUniformScale;
|
||||
}
|
||||
|
||||
void ManipulatorSpace::SetNonUniformScale(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
m_nonUniformScale = nonUniformScale;
|
||||
}
|
||||
|
||||
AZ::Transform ManipulatorSpace::ApplySpace(const AZ::Transform& localTransform) const
|
||||
{
|
||||
AZ::Transform result;
|
||||
result.SetRotation(m_space.GetRotation() * localTransform.GetRotation());
|
||||
result.SetTranslation(m_space.TransformPoint(m_nonUniformScale * localTransform.GetTranslation()));
|
||||
result.SetScale(m_space.GetScale() * localTransform.GetScale());
|
||||
return result;
|
||||
}
|
||||
|
||||
const AZ::Vector3& ManipulatorSpaceWithLocalPosition::GetLocalPosition() const
|
||||
{
|
||||
return m_localPosition;
|
||||
}
|
||||
|
||||
void ManipulatorSpaceWithLocalPosition::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localPosition = localPosition;
|
||||
}
|
||||
|
||||
const AZ::Vector3& ManipulatorSpaceWithLocalTransform::GetLocalPosition() const
|
||||
{
|
||||
return m_localTransform.GetTranslation();
|
||||
}
|
||||
|
||||
void ManipulatorSpaceWithLocalTransform::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
const AZ::Transform& ManipulatorSpaceWithLocalTransform::GetLocalTransform() const
|
||||
{
|
||||
return m_localTransform;
|
||||
}
|
||||
|
||||
const AZ::Quaternion& ManipulatorSpaceWithLocalTransform::GetLocalOrientation() const
|
||||
{
|
||||
return m_localTransform.GetRotation();
|
||||
}
|
||||
|
||||
void ManipulatorSpaceWithLocalTransform::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void ManipulatorSpaceWithLocalTransform::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_localTransform.SetRotation(localOrientation);
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <AzCore/Math/Transform.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class Quaternion;
|
||||
} // namespace AZ
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
/// Handles location for manipulators which have a global space but no local transformation.
|
||||
class ManipulatorSpace
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(ManipulatorSpace, "{5D4B8974-8F98-4268-8D6B-3214A77C6382}")
|
||||
AZ_CLASS_ALLOCATOR(ManipulatorSpace, AZ::SystemAllocator, 0)
|
||||
|
||||
const AZ::Transform& GetSpace() const;
|
||||
void SetSpace(const AZ::Transform& space);
|
||||
const AZ::Vector3& GetNonUniformScale() const;
|
||||
void SetNonUniformScale(const AZ::Vector3& nonUniformScale);
|
||||
|
||||
/// Calculates a transform combining the space and local transform, taking non-uniform scale into account.
|
||||
AZ::Transform ApplySpace(const AZ::Transform& localTransform) const;
|
||||
|
||||
private:
|
||||
AZ::Transform m_space = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in.
|
||||
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); ///< Handles non-uniform scale for the space the manipulator is in.
|
||||
};
|
||||
|
||||
/// Handles location for manipulators which have a global space and a local position, but no local rotation.
|
||||
class ManipulatorSpaceWithLocalPosition
|
||||
: public ManipulatorSpace
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(ManipulatorSpaceWithLocalPosition, "{47BE15AF-60A8-436B-8F3F-7DDFB97220E6}")
|
||||
AZ_CLASS_ALLOCATOR(ManipulatorSpaceWithLocalPosition, AZ::SystemAllocator, 0)
|
||||
|
||||
const AZ::Vector3& GetLocalPosition() const;
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
|
||||
private:
|
||||
AZ::Vector3 m_localPosition = AZ::Vector3::CreateZero(); ///< Position in local space.
|
||||
};
|
||||
|
||||
/// Handles location for manipulators which have a global space and a local transform (position and rotation).
|
||||
class ManipulatorSpaceWithLocalTransform
|
||||
: public ManipulatorSpace
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(ManipulatorSpaceWithLocalTransform, "{6D100797-1DD8-45B0-A21C-8893B770C0BC}")
|
||||
AZ_CLASS_ALLOCATOR(ManipulatorSpaceWithLocalTransform, AZ::SystemAllocator, 0)
|
||||
|
||||
const AZ::Vector3& GetLocalPosition() const;
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
|
||||
const AZ::Transform& GetLocalTransform() const;
|
||||
const AZ::Quaternion& GetLocalOrientation() const;
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
|
||||
private:
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ManipulatorView.h"
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
#include <AzCore/Math/VectorConversions.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
@@ -38,6 +39,23 @@ namespace AzToolsFramework
|
||||
return TransformUniformScale(worldFromLocal);
|
||||
}
|
||||
|
||||
AZ::Vector3 GetNonUniformScale(AZ::EntityId entityId)
|
||||
{
|
||||
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
|
||||
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale);
|
||||
return nonUniformScale;
|
||||
}
|
||||
|
||||
AZ::Vector3 ManipulatorState::TransformPoint(const AZ::Vector3& point) const
|
||||
{
|
||||
return m_worldFromLocal.TransformPoint(m_nonUniformScale * point);
|
||||
}
|
||||
|
||||
AZ::Vector3 ManipulatorState::TransformDirectionNoScaling(const AZ::Vector3& direction) const
|
||||
{
|
||||
return AzToolsFramework::TransformDirectionNoScaling(m_worldFromLocal, direction);
|
||||
}
|
||||
|
||||
/// Take into account the location of the camera and orientate the axis so it faces the camera.
|
||||
/// if we did correct the camera (shouldCorrect is true) then we know the axis facing us it negative.
|
||||
/// we can use this to change the rendering for a flipped axis if we wish.
|
||||
@@ -70,14 +88,12 @@ namespace AzToolsFramework
|
||||
|
||||
/// Calculate quad bound in world space.
|
||||
static Picking::BoundShapeQuad CalculateQuadBound(
|
||||
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
|
||||
const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState,
|
||||
const AZ::Vector3& axis1, const AZ::Vector3& axis2, const float size)
|
||||
{
|
||||
const AZ::Vector3 worldPosition = worldFromLocal.TransformPoint(localPosition);
|
||||
const AZ::Vector3 endAxis1World = localPosition +
|
||||
TransformDirectionNoScaling(worldFromLocal, axis1) * size;
|
||||
const AZ::Vector3 endAxis2World = localPosition +
|
||||
TransformDirectionNoScaling(worldFromLocal, axis2) * size;
|
||||
const AZ::Vector3 worldPosition = manipulatorState.TransformPoint(localPosition);
|
||||
const AZ::Vector3 endAxis1World = manipulatorState.TransformDirectionNoScaling(axis1) * size;
|
||||
const AZ::Vector3 endAxis2World = manipulatorState.TransformDirectionNoScaling(axis2) * size;
|
||||
|
||||
Picking::BoundShapeQuad quadBound;
|
||||
quadBound.m_corner1 = worldPosition;
|
||||
@@ -117,11 +133,12 @@ namespace AzToolsFramework
|
||||
static Picking::BoundShapeLineSegment CalculateLineBound(
|
||||
const AZ::Vector3& localStartPosition,
|
||||
const AZ::Vector3& localEndPosition,
|
||||
const AZ::Transform& worldFromLocal, const float width)
|
||||
const ManipulatorState& manipulatorState,
|
||||
const float width)
|
||||
{
|
||||
Picking::BoundShapeLineSegment lineBound;
|
||||
lineBound.m_start = worldFromLocal.TransformPoint(localStartPosition);
|
||||
lineBound.m_end = worldFromLocal.TransformPoint(localEndPosition);
|
||||
lineBound.m_start = manipulatorState.TransformPoint(localStartPosition);
|
||||
lineBound.m_end = manipulatorState.TransformPoint(localEndPosition);
|
||||
lineBound.m_width = width;
|
||||
return lineBound;
|
||||
}
|
||||
@@ -166,11 +183,11 @@ namespace AzToolsFramework
|
||||
|
||||
/// Calculate sphere bound in world space.
|
||||
static Picking::BoundShapeSphere CalculateSphereBound(
|
||||
const AZ::Vector3& localPosition, const AZ::Transform& worldFromLocal,
|
||||
const AZ::Vector3& localPosition, const ManipulatorState& manipulatorState,
|
||||
const float radius)
|
||||
{
|
||||
Picking::BoundShapeSphere sphereBound;
|
||||
sphereBound.m_center = worldFromLocal.TransformPoint(localPosition);
|
||||
sphereBound.m_center = manipulatorState.TransformPoint(localPosition);
|
||||
sphereBound.m_radius = radius;
|
||||
return sphereBound;
|
||||
}
|
||||
@@ -305,7 +322,7 @@ namespace AzToolsFramework
|
||||
|
||||
const Picking::BoundShapeQuad quadBound =
|
||||
CalculateQuadBound(
|
||||
manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
|
||||
manipulatorState.m_localPosition, manipulatorState, m_cameraCorrectedAxis1, m_cameraCorrectedAxis2,
|
||||
m_size * ManipulatorViewScaleMultiplier(
|
||||
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState));
|
||||
|
||||
@@ -385,16 +402,16 @@ namespace AzToolsFramework
|
||||
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState);
|
||||
|
||||
const Picking::BoundShapeLineSegment lineBound =
|
||||
CalculateLineBound(m_localStart, m_localEnd, manipulatorState.m_worldFromLocal, m_width * viewScale);
|
||||
CalculateLineBound(m_localStart, m_localEnd, manipulatorState, m_width * viewScale);
|
||||
|
||||
if (manipulatorState.m_mouseOver)
|
||||
{
|
||||
const LineSegmentSelectionManipulator::Action action = CalculateManipulationDataAction(
|
||||
manipulatorState.m_worldFromLocal, mouseInteraction.m_mousePick.m_rayOrigin,
|
||||
mouseInteraction.m_mousePick.m_rayDirection,
|
||||
manipulatorState.m_worldFromLocal, manipulatorState.m_nonUniformScale,
|
||||
mouseInteraction.m_mousePick.m_rayOrigin, mouseInteraction.m_mousePick.m_rayDirection,
|
||||
cameraState.m_farClip, m_localStart, m_localEnd);
|
||||
|
||||
const AZ::Vector3 worldLineHitPosition = manipulatorState.m_worldFromLocal.TransformPoint(action.m_localLineHitPosition);
|
||||
const AZ::Vector3 worldLineHitPosition = manipulatorState.TransformPoint(action.m_localLineHitPosition);
|
||||
debugDisplay.SetColor(AZ::Vector4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
debugDisplay.DrawBall(
|
||||
worldLineHitPosition, ManipulatorViewScaleMultiplier(worldLineHitPosition, cameraState)
|
||||
@@ -510,9 +527,9 @@ namespace AzToolsFramework
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction)
|
||||
{
|
||||
const Picking::BoundShapeSphere sphereBound =
|
||||
CalculateSphereBound(manipulatorState.m_localPosition, manipulatorState.m_worldFromLocal,
|
||||
CalculateSphereBound(manipulatorState.m_localPosition, manipulatorState,
|
||||
m_radius * ManipulatorViewScaleMultiplier(
|
||||
manipulatorState.m_worldFromLocal.TransformPoint(manipulatorState.m_localPosition), cameraState));
|
||||
manipulatorState.TransformPoint(manipulatorState.m_localPosition), cameraState));
|
||||
|
||||
if (m_depthTest)
|
||||
{
|
||||
|
||||
@@ -36,8 +36,16 @@ namespace AzToolsFramework
|
||||
struct ManipulatorState
|
||||
{
|
||||
AZ::Transform m_worldFromLocal;
|
||||
AZ::Vector3 m_nonUniformScale;
|
||||
AZ::Vector3 m_localPosition;
|
||||
bool m_mouseOver;
|
||||
|
||||
/// Transforms a point, taking non-uniform scale into account.
|
||||
AZ::Vector3 TransformPoint(const AZ::Vector3& point) const;
|
||||
|
||||
/// Rotates a direction into the space of the manipulator and normalizes it.
|
||||
/// Non-uniform scaling and translation are not applied.
|
||||
AZ::Vector3 TransformDirectionNoScaling(const AZ::Vector3& direction) const;
|
||||
};
|
||||
|
||||
/// The base interface for the visual representation of manipulators.
|
||||
@@ -348,6 +356,9 @@ namespace AzToolsFramework
|
||||
/// the largest element.
|
||||
AZ::Transform WorldFromLocalWithUniformScale(AZ::EntityId entityId);
|
||||
|
||||
/// Get the non-uniform scale for this entity id.
|
||||
AZ::Vector3 GetNonUniformScale(AZ::EntityId entityId);
|
||||
|
||||
// Helpers to create various manipulator views.
|
||||
|
||||
AZStd::unique_ptr<ManipulatorViewQuad> CreateManipulatorViewQuad(
|
||||
|
||||
+16
-34
@@ -30,8 +30,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
MultiLinearManipulator::MultiLinearManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
AttachLeftMouseDownImpl();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
static MultiLinearManipulator::Action BuildMultiLinearManipulatorAction(
|
||||
const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
|
||||
const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
|
||||
const ViewportInteraction::MouseInteraction& interaction,
|
||||
const AZStd::vector<LinearManipulator::Fixed>& fixedAxes,
|
||||
const AZStd::vector<LinearManipulator::Starter>& starterStates, const GridSnapAction& gridSnapAction)
|
||||
@@ -68,8 +68,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
action.m_actions.push_back(
|
||||
CalculateLinearManipulationDataAction(
|
||||
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, localTransform, gridSnapAction,
|
||||
interaction));
|
||||
fixedAxes[fixedIndex], starterStates[fixedIndex], worldFromLocal, nonUniformScale, localTransform,
|
||||
gridSnapAction, interaction));
|
||||
}
|
||||
|
||||
return action;
|
||||
@@ -78,7 +78,7 @@ namespace AzToolsFramework
|
||||
void MultiLinearManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
const AzFramework::CameraState cameraState = GetCameraState(interaction.m_interactionId.m_viewportId);
|
||||
@@ -88,7 +88,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
// note: m_localTransform must not be made uniform as it may contain a local scale we want to snap
|
||||
const auto linearStart = CalculateLinearManipulationDataStart(
|
||||
fixed, worldFromLocalUniformScale, m_localTransform,
|
||||
fixed, worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction,
|
||||
rayIntersectionDistance, cameraState);
|
||||
|
||||
@@ -100,7 +100,8 @@ namespace AzToolsFramework
|
||||
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
|
||||
// pass action containing all linear actions for each axis to handler
|
||||
m_onLeftMouseDownCallback(BuildMultiLinearManipulatorAction(
|
||||
worldFromLocalUniformScale, m_localTransform, interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,12 +109,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (m_onMouseMoveCallback)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
|
||||
|
||||
m_onMouseMoveCallback(BuildMultiLinearManipulatorAction(
|
||||
worldFromLocalUniformScale, m_localTransform, interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,12 +123,13 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (m_onLeftMouseUpCallback)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
const GridSnapAction gridSnapAction = GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt());
|
||||
|
||||
m_onLeftMouseUpCallback(BuildMultiLinearManipulatorAction(
|
||||
worldFromLocalUniformScale, m_localTransform, interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
worldFromLocalUniformScale, GetNonUniformScale(), GetLocalTransform(),
|
||||
interaction, m_fixedAxes, m_starters, gridSnapAction));
|
||||
|
||||
m_starters.clear();
|
||||
}
|
||||
@@ -140,7 +143,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (cl_manipulatorDrawDebug)
|
||||
{
|
||||
const AZ::Transform combined = TransformUniformScale(m_worldFromLocal) * m_localTransform;
|
||||
const AZ::Transform combined = TransformUniformScale(GetSpace()) * GetLocalTransform();
|
||||
for (const auto& fixed : m_fixedAxes)
|
||||
{
|
||||
DrawAxis(
|
||||
@@ -153,7 +156,7 @@ namespace AzToolsFramework
|
||||
view->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
m_worldFromLocal * m_localTransform,
|
||||
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
|
||||
AZ::Vector3::CreateZero(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
@@ -176,27 +179,6 @@ namespace AzToolsFramework
|
||||
});
|
||||
}
|
||||
|
||||
void MultiLinearManipulator::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
m_worldFromLocal = worldFromLocal;
|
||||
}
|
||||
|
||||
void MultiLinearManipulator::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void MultiLinearManipulator::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void MultiLinearManipulator::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void MultiLinearManipulator::ClearAxes()
|
||||
{
|
||||
m_fixedAxes.clear();
|
||||
|
||||
+1
-27
@@ -26,6 +26,7 @@ namespace AzToolsFramework
|
||||
//! in one or more dimensions on axes defined in 3D space.
|
||||
class MultiLinearManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalTransform
|
||||
{
|
||||
//! Private constructor.
|
||||
explicit MultiLinearManipulator(const AZ::Transform& worldFromLocal);
|
||||
@@ -70,15 +71,6 @@ namespace AzToolsFramework
|
||||
void AddAxes(const AZStd::vector<AZ::Vector3>& axes);
|
||||
void ClearAxes();
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal);
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
|
||||
AZ::Vector3 GetLocalPosition() const;
|
||||
const AZ::Transform& GetSpace() const;
|
||||
const AZ::Transform& GetLocalTransform() const;
|
||||
|
||||
using ConstFixedIterator = AZStd::vector<LinearManipulator::Fixed>::const_iterator;
|
||||
ConstFixedIterator FixedBegin() const;
|
||||
ConstFixedIterator FixedEnd() const;
|
||||
@@ -100,9 +92,6 @@ namespace AzToolsFramework
|
||||
void InvalidateImpl() override;
|
||||
void SetBoundsDirtyImpl() override;
|
||||
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); //!< Local transform of the manipulator.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); //!< Space the manipulator is in (identity is world space).
|
||||
|
||||
AZStd::vector<LinearManipulator::Fixed> m_fixedAxes; //!< A collection of LinearManipulator fixed states.
|
||||
AZStd::vector<LinearManipulator::Starter> m_starters; //!< A collection of LinearManipulator starter states.
|
||||
|
||||
@@ -113,21 +102,6 @@ namespace AzToolsFramework
|
||||
ManipulatorViews m_manipulatorViews; //!< Look of manipulator.
|
||||
};
|
||||
|
||||
inline AZ::Vector3 MultiLinearManipulator::GetLocalPosition() const
|
||||
{
|
||||
return m_localTransform.GetTranslation();
|
||||
}
|
||||
|
||||
inline const AZ::Transform& MultiLinearManipulator::GetSpace() const
|
||||
{
|
||||
return m_localTransform;
|
||||
}
|
||||
|
||||
inline const AZ::Transform& MultiLinearManipulator::GetLocalTransform() const
|
||||
{
|
||||
return m_localTransform;
|
||||
}
|
||||
|
||||
inline MultiLinearManipulator::ConstFixedIterator MultiLinearManipulator::FixedBegin() const
|
||||
{
|
||||
return m_fixedAxes.cbegin();
|
||||
|
||||
+28
-46
@@ -22,13 +22,13 @@
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
PlanarManipulator::StartInternal PlanarManipulator::CalculateManipulationDataStart(
|
||||
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
const float intersectionDistance)
|
||||
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction, const float intersectionDistance)
|
||||
{
|
||||
const ManipulatorInteraction manipulatorInteraction =
|
||||
BuildManipulatorInteraction(
|
||||
worldFromLocal, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
|
||||
const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal);
|
||||
const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1);
|
||||
@@ -61,12 +61,12 @@ namespace AzToolsFramework
|
||||
|
||||
PlanarManipulator::Action PlanarManipulator::CalculateManipulationDataAction(
|
||||
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction)
|
||||
{
|
||||
const ManipulatorInteraction manipulatorInteraction =
|
||||
BuildManipulatorInteraction(
|
||||
worldFromLocal, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
worldFromLocal, nonUniformScale, interaction.m_mousePick.m_rayOrigin, interaction.m_mousePick.m_rayDirection);
|
||||
|
||||
const AZ::Vector3 normal = TransformDirectionNoScaling(localTransform, fixed.m_normal);
|
||||
|
||||
@@ -85,10 +85,11 @@ namespace AzToolsFramework
|
||||
const AZ::Vector3 axis1 = TransformDirectionNoScaling(localTransform, fixed.m_axis1);
|
||||
const AZ::Vector3 axis2 = TransformDirectionNoScaling(localTransform, fixed.m_axis2);
|
||||
|
||||
const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition);
|
||||
const AZ::Vector3 hitDelta = (localHitPosition - startInternal.m_localHitPosition) / nonUniformScale;
|
||||
const AZ::Vector3 unsnappedOffset = axis1.Dot(hitDelta) * axis1 + axis2.Dot(hitDelta) * axis2;
|
||||
|
||||
const float scaleRecip = manipulatorInteraction.m_scaleReciprocal;
|
||||
const AZ::Vector3 nonUniformScaleRecip = manipulatorInteraction.m_nonUniformScaleReciprocal;
|
||||
const float gridSize = gridSnapAction.m_gridSnapParams.m_gridSize;
|
||||
const bool snapping = gridSnapAction.m_gridSnapParams.m_gridSnap;
|
||||
|
||||
@@ -99,8 +100,8 @@ namespace AzToolsFramework
|
||||
action.m_start.m_localHitPosition = startInternal.m_localHitPosition;
|
||||
action.m_current.m_localOffset = snapping
|
||||
? unsnappedOffset +
|
||||
CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip) +
|
||||
CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip)
|
||||
CalculateSnappedOffset(unsnappedOffset, axis1, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis1)) +
|
||||
CalculateSnappedOffset(unsnappedOffset, axis2, gridSize * scaleRecip * nonUniformScaleRecip.Dot(axis2))
|
||||
: unsnappedOffset;
|
||||
|
||||
// record what modifier keys are held during this action
|
||||
@@ -115,8 +116,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
PlanarManipulator::PlanarManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
AttachLeftMouseDownImpl();
|
||||
}
|
||||
|
||||
@@ -138,19 +139,19 @@ namespace AzToolsFramework
|
||||
void PlanarManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, const float rayIntersectionDistance)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
m_startInternal = CalculateManipulationDataStart(
|
||||
m_fixed, worldFromLocalUniformScale, TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()),
|
||||
interaction, rayIntersectionDistance);
|
||||
|
||||
if (m_onLeftMouseDownCallback)
|
||||
{
|
||||
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
|
||||
m_fixed, m_startInternal, worldFromLocalUniformScale, TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, m_startInternal, worldFromLocalUniformScale, GetNonUniformScale(), TransformNormalizedScale(GetLocalTransform()),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -162,8 +163,8 @@ namespace AzToolsFramework
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
m_onMouseMoveCallback(CalculateManipulationDataAction(
|
||||
m_fixed, m_startInternal, TransformUniformScale(m_worldFromLocal),
|
||||
TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
TransformNormalizedScale(GetLocalTransform()),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -175,8 +176,8 @@ namespace AzToolsFramework
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
|
||||
m_fixed, m_startInternal, TransformUniformScale(m_worldFromLocal),
|
||||
TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
TransformNormalizedScale(GetLocalTransform()),
|
||||
GridSnapAction(gridSnapParams, interaction.m_keyboardModifiers.Alt()), interaction));
|
||||
}
|
||||
}
|
||||
@@ -193,27 +194,29 @@ namespace AzToolsFramework
|
||||
{
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(mouseInteraction.m_interactionId.m_viewportId);
|
||||
const auto action = CalculateManipulationDataAction(
|
||||
m_fixed, m_startInternal, TransformUniformScale(m_worldFromLocal),
|
||||
TransformNormalizedScale(m_localTransform),
|
||||
m_fixed, m_startInternal, TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
TransformNormalizedScale(GetLocalTransform()),
|
||||
GridSnapAction(gridSnapParams, mouseInteraction.m_keyboardModifiers.Alt()), mouseInteraction);
|
||||
|
||||
// display the exact hit (ray intersection) of the mouse pick on the manipulator
|
||||
DrawTransformAxes(
|
||||
debugDisplay, TransformUniformScale(m_worldFromLocal) *
|
||||
debugDisplay, TransformUniformScale(GetSpace()) *
|
||||
AZ::Transform::CreateTranslation(
|
||||
action.m_start.m_localHitPosition + action.m_current.m_localOffset));
|
||||
action.m_start.m_localHitPosition + GetNonUniformScale() * action.m_current.m_localOffset));
|
||||
}
|
||||
|
||||
const AZ::Transform combined = m_worldFromLocal * m_localTransform;
|
||||
AZ::Transform combined = GetLocalTransform();
|
||||
combined.SetTranslation(GetNonUniformScale() * combined.GetTranslation());
|
||||
combined = GetSpace() * combined;
|
||||
|
||||
DrawTransformAxes(debugDisplay, combined);
|
||||
|
||||
DrawAxis(
|
||||
debugDisplay, combined.GetTranslation(),
|
||||
TransformDirectionNoScaling(m_localTransform, m_fixed.m_axis1));
|
||||
TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis1));
|
||||
DrawAxis(
|
||||
debugDisplay, combined.GetTranslation(),
|
||||
TransformDirectionNoScaling(m_localTransform, m_fixed.m_axis2));
|
||||
TransformDirectionNoScaling(GetLocalTransform(), m_fixed.m_axis2));
|
||||
}
|
||||
|
||||
for (auto& view : m_manipulatorViews)
|
||||
@@ -221,7 +224,7 @@ namespace AzToolsFramework
|
||||
view->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
m_worldFromLocal * m_localTransform,
|
||||
ApplySpace(GetLocalTransform()), GetNonUniformScale(),
|
||||
AZ::Vector3::CreateZero(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
@@ -235,27 +238,6 @@ namespace AzToolsFramework
|
||||
m_fixed.m_normal = axis1.Cross(axis2);
|
||||
}
|
||||
|
||||
void PlanarManipulator::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
m_worldFromLocal = worldFromLocal;
|
||||
}
|
||||
|
||||
void PlanarManipulator::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
{
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void PlanarManipulator::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
{
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void PlanarManipulator::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void PlanarManipulator::InvalidateImpl()
|
||||
{
|
||||
for (auto& view : m_manipulatorViews)
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace AzToolsFramework
|
||||
/// in two dimension in a plane defined two non-collinear axes in 3D space.
|
||||
class PlanarManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalTransform
|
||||
{
|
||||
/// Private constructor.
|
||||
explicit PlanarManipulator(const AZ::Transform& worldFromLocal);
|
||||
@@ -93,14 +94,9 @@ namespace AzToolsFramework
|
||||
|
||||
/// Ensure @param axis1 and @param axis2 are not collinear.
|
||||
void SetAxes(const AZ::Vector3& axis1, const AZ::Vector3& axis2);
|
||||
void SetSpace(const AZ::Transform& worldFromLocal);
|
||||
void SetLocalTransform(const AZ::Transform& localTransform);
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition);
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation);
|
||||
|
||||
const AZ::Vector3& GetAxis1() const { return m_fixed.m_axis1; }
|
||||
const AZ::Vector3& GetAxis2() const { return m_fixed.m_axis2; }
|
||||
AZ::Vector3 GetPosition() const { return m_localTransform.GetTranslation(); }
|
||||
|
||||
template<typename Views>
|
||||
void SetViews(Views&& views)
|
||||
@@ -127,9 +123,6 @@ namespace AzToolsFramework
|
||||
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
|
||||
};
|
||||
|
||||
AZ::Transform m_localTransform = AZ::Transform::CreateIdentity(); ///< Local transform of the manipulator.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
|
||||
Fixed m_fixed;
|
||||
StartInternal m_startInternal;
|
||||
|
||||
@@ -140,13 +133,13 @@ namespace AzToolsFramework
|
||||
ManipulatorViews m_manipulatorViews; ///< Look of manipulator.
|
||||
|
||||
static StartInternal CalculateManipulationDataStart(
|
||||
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction,
|
||||
float intersectionDistance);
|
||||
const Fixed& fixed, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction, float intersectionDistance);
|
||||
|
||||
static Action CalculateManipulationDataAction(
|
||||
const Fixed& fixed, const StartInternal& startInternal, const AZ::Transform& worldFromLocal,
|
||||
const AZ::Transform& localTransform, const GridSnapAction& gridSnapAction,
|
||||
const ViewportInteraction::MouseInteraction& interaction);
|
||||
const AZ::Vector3& nonUniformScale, const AZ::Transform& localTransform,
|
||||
const GridSnapAction& gridSnapAction, const ViewportInteraction::MouseInteraction& interaction);
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+6
-15
@@ -25,7 +25,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_viewAngularManipulator = AngularManipulator::MakeShared(worldFromLocal);
|
||||
|
||||
m_space = worldFromLocal;
|
||||
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
|
||||
}
|
||||
|
||||
void RotationManipulators::InstallLeftMouseDownCallback(
|
||||
@@ -61,7 +61,7 @@ namespace AzToolsFramework
|
||||
m_viewAngularManipulator->InstallLeftMouseUpCallback(onMouseUpCallback);
|
||||
}
|
||||
|
||||
void RotationManipulators::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
void RotationManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
|
||||
{
|
||||
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
|
||||
{
|
||||
@@ -69,11 +69,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_viewAngularManipulator->SetLocalTransform(localTransform);
|
||||
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void RotationManipulators::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
void RotationManipulators::SetLocalPositionImpl(const AZ::Vector3& localPosition)
|
||||
{
|
||||
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
|
||||
{
|
||||
@@ -81,11 +79,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_viewAngularManipulator->SetLocalPosition(localPosition);
|
||||
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void RotationManipulators::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
void RotationManipulators::SetLocalOrientationImpl(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
|
||||
{
|
||||
@@ -93,9 +89,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_viewAngularManipulator->SetLocalOrientation(localOrientation);
|
||||
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void RotationManipulators::RefreshView(const AZ::Vector3& worldViewPosition)
|
||||
@@ -106,7 +99,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void RotationManipulators::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
void RotationManipulators::SetSpaceImpl(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
for (AZStd::shared_ptr<AngularManipulator>& manipulator : m_localAngularManipulators)
|
||||
{
|
||||
@@ -114,8 +107,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_viewAngularManipulator->SetSpace(worldFromLocal);
|
||||
|
||||
m_space = worldFromLocal;
|
||||
}
|
||||
|
||||
void RotationManipulators::SetLocalAxes(
|
||||
@@ -177,4 +168,4 @@ namespace AzToolsFramework
|
||||
|
||||
manipulatorFn(m_viewAngularManipulator.get());
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+5
-5
@@ -34,10 +34,10 @@ namespace AzToolsFramework
|
||||
void InstallLeftMouseUpCallback(const AngularManipulator::MouseActionCallback& onMouseUpCallback);
|
||||
void InstallMouseMoveCallback(const AngularManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransform(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation) override;
|
||||
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override;
|
||||
void RefreshView(const AZ::Vector3& worldViewPosition) override;
|
||||
|
||||
void SetLocalAxes(
|
||||
@@ -57,4 +57,4 @@ namespace AzToolsFramework
|
||||
AZStd::array<AZStd::shared_ptr<AngularManipulator>, 3> m_localAngularManipulators;
|
||||
AZStd::shared_ptr<AngularManipulator> m_viewAngularManipulator;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+5
-14
@@ -25,7 +25,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_uniformScaleManipulator = LinearManipulator::MakeShared(worldFromLocal);
|
||||
|
||||
m_space = worldFromLocal;
|
||||
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
|
||||
}
|
||||
|
||||
void ScaleManipulators::InstallAxisLeftMouseDownCallback(
|
||||
@@ -73,7 +73,7 @@ namespace AzToolsFramework
|
||||
m_uniformScaleManipulator->InstallLeftMouseUpCallback(onMouseUpCallback);
|
||||
}
|
||||
|
||||
void ScaleManipulators::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
void ScaleManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
|
||||
{
|
||||
@@ -85,11 +85,9 @@ namespace AzToolsFramework
|
||||
m_uniformScaleManipulator->SetLocalTransform(
|
||||
AZ::Transform::CreateTranslation(localTransform.GetTranslation()) *
|
||||
AZ::Transform::CreateScale(localTransform.GetScale()));
|
||||
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void ScaleManipulators::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
void ScaleManipulators::SetLocalPositionImpl(const AZ::Vector3& localPosition)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
|
||||
{
|
||||
@@ -97,22 +95,17 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_uniformScaleManipulator->SetLocalPosition(localPosition);
|
||||
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void ScaleManipulators::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
void ScaleManipulators::SetLocalOrientationImpl(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
|
||||
{
|
||||
manipulator->SetLocalOrientation(localOrientation);
|
||||
}
|
||||
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void ScaleManipulators::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
void ScaleManipulators::SetSpaceImpl(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_axisScaleManipulators)
|
||||
{
|
||||
@@ -120,8 +113,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
m_uniformScaleManipulator->SetSpace(worldFromLocal);
|
||||
|
||||
m_space = worldFromLocal;
|
||||
}
|
||||
|
||||
void ScaleManipulators::SetAxes(
|
||||
|
||||
@@ -37,10 +37,10 @@ namespace AzToolsFramework
|
||||
void InstallUniformMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
void InstallUniformLeftMouseUpCallback(const LinearManipulator::MouseActionCallback& onMouseUpCallback);
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransform(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation) override;
|
||||
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override;
|
||||
|
||||
void SetAxes(
|
||||
const AZ::Vector3& axis1,
|
||||
@@ -62,4 +62,4 @@ namespace AzToolsFramework
|
||||
AZStd::array<AZStd::shared_ptr<LinearManipulator>, 3> m_axisScaleManipulators;
|
||||
AZStd::shared_ptr<LinearManipulator> m_uniformScaleManipulator;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+8
-6
@@ -16,14 +16,16 @@
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
AZStd::shared_ptr<SelectionManipulator> SelectionManipulator::MakeShared(const AZ::Transform& worldFromLocal)
|
||||
AZStd::shared_ptr<SelectionManipulator> SelectionManipulator::MakeShared(const AZ::Transform& worldFromLocal,
|
||||
const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
return AZStd::shared_ptr<SelectionManipulator>(aznew SelectionManipulator(worldFromLocal));
|
||||
return AZStd::shared_ptr<SelectionManipulator>(aznew SelectionManipulator(worldFromLocal, nonUniformScale));
|
||||
}
|
||||
|
||||
SelectionManipulator::SelectionManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
SelectionManipulator::SelectionManipulator(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
SetNonUniformScale(nonUniformScale);
|
||||
AttachLeftMouseDownImpl();
|
||||
AttachRightMouseDownImpl();
|
||||
}
|
||||
@@ -93,8 +95,8 @@ namespace AzToolsFramework
|
||||
view->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
m_position, MouseOver()
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
GetLocalPosition(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
}
|
||||
|
||||
+4
-10
@@ -24,9 +24,10 @@ namespace AzToolsFramework
|
||||
/// For example clicking a preview point to create a translation manipulator.
|
||||
class SelectionManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalPosition
|
||||
{
|
||||
/// Private constructor.
|
||||
explicit SelectionManipulator(const AZ::Transform& worldFromLocal);
|
||||
SelectionManipulator(const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
|
||||
|
||||
public:
|
||||
AZ_RTTI(SelectionManipulator, "{966F44B7-E287-4C28-9734-5958F1A13A1D}", BaseManipulator);
|
||||
@@ -39,7 +40,8 @@ namespace AzToolsFramework
|
||||
~SelectionManipulator() = default;
|
||||
|
||||
/// A Manipulator must only be created and managed through a shared_ptr.
|
||||
static AZStd::shared_ptr<SelectionManipulator> MakeShared(const AZ::Transform& worldFromLocal);
|
||||
static AZStd::shared_ptr<SelectionManipulator> MakeShared(const AZ::Transform& worldFromLocal,
|
||||
const AZ::Vector3& nonUniformScale = AZ::Vector3::CreateOne());
|
||||
|
||||
/// This is the function signature of callbacks that will be invoked
|
||||
/// whenever a selection manipulator is clicked on.
|
||||
@@ -56,11 +58,6 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetPosition(const AZ::Vector3& position) { m_position = position; }
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) { m_worldFromLocal = worldFromLocal; }
|
||||
|
||||
const AZ::Vector3& GetPosition() const { return m_position; }
|
||||
|
||||
bool Selected() const { return m_selected; }
|
||||
void Select() { m_selected = true; }
|
||||
void Deselect() { m_selected = false; }
|
||||
@@ -85,9 +82,6 @@ namespace AzToolsFramework
|
||||
void InvalidateImpl() override;
|
||||
void SetBoundsDirtyImpl() override;
|
||||
|
||||
AZ::Vector3 m_position = AZ::Vector3::CreateZero(); ///< Position in local space.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
|
||||
bool m_selected = false;
|
||||
|
||||
MouseActionCallback m_onLeftMouseDownCallback = nullptr;
|
||||
|
||||
@@ -86,4 +86,12 @@ namespace AzToolsFramework
|
||||
m_splineSelectionManipulator->SetSpace(worldFromLocal);
|
||||
}
|
||||
}
|
||||
|
||||
void SplineHoverSelection::SetNonUniformScale(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
if (m_splineSelectionManipulator)
|
||||
{
|
||||
m_splineSelectionManipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+2
-1
@@ -43,8 +43,9 @@ namespace AzToolsFramework
|
||||
void SetBoundsDirty() override;
|
||||
void Refresh() override;
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) override;
|
||||
void SetNonUniformScale(const AZ::Vector3& nonUniformScale) override;
|
||||
|
||||
private:
|
||||
AZStd::shared_ptr<SplineSelectionManipulator> m_splineSelectionManipulator; ///< Manipulator for adding points to spline.
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+3
-3
@@ -65,7 +65,7 @@ namespace AzToolsFramework
|
||||
if (m_onLeftMouseDownCallback)
|
||||
{
|
||||
m_onLeftMouseDownCallback(CalculateManipulationDataAction(
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
TransformUniformScale(GetSpace()),
|
||||
interaction.m_mousePick.m_rayOrigin,
|
||||
interaction.m_mousePick.m_rayDirection, m_spline));
|
||||
}
|
||||
@@ -76,7 +76,7 @@ namespace AzToolsFramework
|
||||
if (MouseOver() && m_onLeftMouseUpCallback)
|
||||
{
|
||||
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
TransformUniformScale(GetSpace()),
|
||||
interaction.m_mousePick.m_rayOrigin,
|
||||
interaction.m_mousePick.m_rayDirection, m_spline));
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace AzToolsFramework
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
AZ::Vector3::CreateZero(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
|
||||
+1
-2
@@ -27,6 +27,7 @@ namespace AzToolsFramework
|
||||
/// used to test mouse picking ray against to preview closest point on spline.
|
||||
class SplineSelectionManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpace
|
||||
{
|
||||
/// Private constructor.
|
||||
SplineSelectionManipulator();
|
||||
@@ -61,7 +62,6 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) { m_worldFromLocal = worldFromLocal; }
|
||||
void SetSpline(AZStd::shared_ptr<const AZ::Spline> spline) { m_spline = AZStd::move(spline); }
|
||||
AZStd::weak_ptr<const AZ::Spline> GetSpline() const { return m_spline; }
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace AzToolsFramework
|
||||
void InvalidateImpl() override;
|
||||
void SetBoundsDirtyImpl() override;
|
||||
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
AZStd::weak_ptr<const AZ::Spline> m_spline;
|
||||
AZStd::unique_ptr<ManipulatorView> m_manipulatorView = nullptr; ///< Look of manipulator and bounds for interaction.
|
||||
MouseActionCallback m_onLeftMouseDownCallback = nullptr;
|
||||
|
||||
+7
-7
@@ -73,8 +73,8 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
SurfaceManipulator::SurfaceManipulator(const AZ::Transform& worldFromLocal)
|
||||
: m_worldFromLocal(worldFromLocal)
|
||||
{
|
||||
SetSpace(worldFromLocal);
|
||||
AttachLeftMouseDownImpl();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace AzToolsFramework
|
||||
void SurfaceManipulator::OnLeftMouseDownImpl(
|
||||
const ViewportInteraction::MouseInteraction& interaction, float /*rayIntersectionDistance*/)
|
||||
{
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(m_worldFromLocal);
|
||||
const AZ::Transform worldFromLocalUniformScale = TransformUniformScale(GetSpace());
|
||||
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace AzToolsFramework
|
||||
interaction.m_mousePick.m_screenCoordinates));
|
||||
|
||||
m_startInternal = CalculateManipulationDataStart(
|
||||
worldFromLocalUniformScale, worldSurfacePosition, m_position,
|
||||
worldFromLocalUniformScale, worldSurfacePosition, GetLocalPosition(),
|
||||
gridSnapParams.m_gridSnap, gridSnapParams.m_gridSize,
|
||||
interaction.m_interactionId.m_viewportId);
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace AzToolsFramework
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
m_onLeftMouseUpCallback(CalculateManipulationDataAction(
|
||||
m_startInternal, TransformUniformScale(m_worldFromLocal), worldSurfacePosition,
|
||||
m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition,
|
||||
gridSnapParams.m_gridSnap,
|
||||
gridSnapParams.m_gridSize,
|
||||
interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId));
|
||||
@@ -156,7 +156,7 @@ namespace AzToolsFramework
|
||||
const GridSnapParameters gridSnapParams = GridSnapSettings(interaction.m_interactionId.m_viewportId);
|
||||
|
||||
m_onMouseMoveCallback(CalculateManipulationDataAction(
|
||||
m_startInternal, TransformUniformScale(m_worldFromLocal), worldSurfacePosition,
|
||||
m_startInternal, TransformUniformScale(GetSpace()), worldSurfacePosition,
|
||||
gridSnapParams.m_gridSnap,
|
||||
gridSnapParams.m_gridSize,
|
||||
interaction.m_keyboardModifiers, interaction.m_interactionId.m_viewportId));
|
||||
@@ -177,8 +177,8 @@ namespace AzToolsFramework
|
||||
m_manipulatorView->Draw(
|
||||
GetManipulatorManagerId(), managerState,
|
||||
GetManipulatorId(), {
|
||||
TransformUniformScale(m_worldFromLocal),
|
||||
m_position, MouseOver()
|
||||
TransformUniformScale(GetSpace()), GetNonUniformScale(),
|
||||
GetLocalPosition(), MouseOver()
|
||||
},
|
||||
debugDisplay, cameraState, mouseInteraction);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace AzToolsFramework
|
||||
/// while also staying aligned exactly to the height of the terrain.
|
||||
class SurfaceManipulator
|
||||
: public BaseManipulator
|
||||
, public ManipulatorSpaceWithLocalPosition
|
||||
{
|
||||
/// Private constructor.
|
||||
explicit SurfaceManipulator(const AZ::Transform& worldFromLocal);
|
||||
@@ -77,11 +78,6 @@ namespace AzToolsFramework
|
||||
const AzFramework::CameraState& cameraState,
|
||||
const ViewportInteraction::MouseInteraction& mouseInteraction) override;
|
||||
|
||||
void SetPosition(const AZ::Vector3& position) { m_position = position; }
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) { m_worldFromLocal = worldFromLocal; }
|
||||
|
||||
const AZ::Vector3& GetPosition() const { return m_position; }
|
||||
|
||||
void SetView(AZStd::unique_ptr<ManipulatorView>&& view);
|
||||
|
||||
private:
|
||||
@@ -103,9 +99,6 @@ namespace AzToolsFramework
|
||||
AZ::Vector3 m_snapOffset; ///< The snap offset amount to ensure manipulator is aligned to the grid.
|
||||
};
|
||||
|
||||
AZ::Vector3 m_position = AZ::Vector3::CreateZero(); ///< Position in local space.
|
||||
AZ::Transform m_worldFromLocal = AZ::Transform::CreateIdentity(); ///< Space the manipulator is in (identity is world space).
|
||||
|
||||
StartInternal m_startInternal; ///< Internal initial state recorded/created in OnMouseDown.
|
||||
|
||||
AZStd::unique_ptr<ManipulatorView> m_manipulatorView = nullptr; ///< Look of manipulator.
|
||||
|
||||
+26
-16
@@ -27,7 +27,7 @@ namespace AzToolsFramework
|
||||
static const AZ::Color s_surfaceManipulatorColor = AZ::Color(1.0f, 1.0f, 0.0f, 0.5f);
|
||||
|
||||
TranslationManipulators::TranslationManipulators(
|
||||
const Dimensions dimensions, const AZ::Transform& worldFromLocal)
|
||||
const Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
|
||||
: m_dimensions(dimensions)
|
||||
{
|
||||
switch (dimensions)
|
||||
@@ -55,7 +55,8 @@ namespace AzToolsFramework
|
||||
break;
|
||||
}
|
||||
|
||||
m_space = worldFromLocal;
|
||||
m_manipulatorSpaceWithLocalTransform.SetSpace(worldFromLocal);
|
||||
SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
|
||||
void TranslationManipulators::InstallLinearManipulatorMouseDownCallback(
|
||||
@@ -139,7 +140,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetLocalTransform(const AZ::Transform& localTransform)
|
||||
void TranslationManipulators::SetLocalTransformImpl(const AZ::Transform& localTransform)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
{
|
||||
@@ -153,13 +154,11 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_surfaceManipulator)
|
||||
{
|
||||
m_surfaceManipulator->SetPosition(localTransform.GetTranslation());
|
||||
m_surfaceManipulator->SetLocalPosition(localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
m_localTransform = localTransform;
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetLocalPosition(const AZ::Vector3& localPosition)
|
||||
void TranslationManipulators::SetLocalPositionImpl(const AZ::Vector3& localPosition)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
{
|
||||
@@ -173,13 +172,11 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_surfaceManipulator)
|
||||
{
|
||||
m_surfaceManipulator->SetPosition(localPosition);
|
||||
m_surfaceManipulator->SetLocalPosition(localPosition);
|
||||
}
|
||||
|
||||
m_localTransform.SetTranslation(localPosition);
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetLocalOrientation(const AZ::Quaternion& localOrientation)
|
||||
void TranslationManipulators::SetLocalOrientationImpl(const AZ::Quaternion& localOrientation)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
{
|
||||
@@ -190,12 +187,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
manipulator->SetLocalOrientation(localOrientation);
|
||||
}
|
||||
|
||||
m_localTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
localOrientation, m_localTransform.GetTranslation());
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetSpace(const AZ::Transform& worldFromLocal)
|
||||
void TranslationManipulators::SetSpaceImpl(const AZ::Transform& worldFromLocal)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
{
|
||||
@@ -211,8 +205,24 @@ namespace AzToolsFramework
|
||||
{
|
||||
m_surfaceManipulator->SetSpace(worldFromLocal);
|
||||
}
|
||||
}
|
||||
|
||||
m_space = worldFromLocal;
|
||||
void TranslationManipulators::SetNonUniformScaleImpl(const AZ::Vector3& nonUniformScale)
|
||||
{
|
||||
for (AZStd::shared_ptr<LinearManipulator>& manipulator : m_linearManipulators)
|
||||
{
|
||||
manipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
|
||||
for (AZStd::shared_ptr<PlanarManipulator>& manipulator : m_planarManipulators)
|
||||
{
|
||||
manipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
|
||||
if (m_surfaceManipulator)
|
||||
{
|
||||
m_surfaceManipulator->SetNonUniformScale(nonUniformScale);
|
||||
}
|
||||
}
|
||||
|
||||
void TranslationManipulators::SetAxes(
|
||||
|
||||
+9
-8
@@ -35,7 +35,7 @@ namespace AzToolsFramework
|
||||
Three
|
||||
};
|
||||
|
||||
TranslationManipulators(Dimensions dimensions, const AZ::Transform& worldFromLocal);
|
||||
TranslationManipulators(Dimensions dimensions, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale);
|
||||
|
||||
void InstallLinearManipulatorMouseDownCallback(const LinearManipulator::MouseActionCallback& onMouseDownCallback);
|
||||
void InstallLinearManipulatorMouseMoveCallback(const LinearManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
@@ -49,10 +49,11 @@ namespace AzToolsFramework
|
||||
void InstallSurfaceManipulatorMouseMoveCallback(const SurfaceManipulator::MouseActionCallback& onMouseMoveCallback);
|
||||
void InstallSurfaceManipulatorMouseUpCallback(const SurfaceManipulator::MouseActionCallback& onMouseUpCallback);
|
||||
|
||||
void SetSpace(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransform(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPosition(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientation(const AZ::Quaternion& localOrientation) override;
|
||||
void SetSpaceImpl(const AZ::Transform& worldFromLocal) override;
|
||||
void SetLocalTransformImpl(const AZ::Transform& localTransform) override;
|
||||
void SetLocalPositionImpl(const AZ::Vector3& localPosition) override;
|
||||
void SetLocalOrientationImpl(const AZ::Quaternion& localOrientation) override;
|
||||
void SetNonUniformScaleImpl(const AZ::Vector3& nonUniformScale) override;
|
||||
|
||||
void SetAxes(
|
||||
const AZ::Vector3& axis1, const AZ::Vector3& axis2,
|
||||
@@ -91,8 +92,8 @@ namespace AzToolsFramework
|
||||
{
|
||||
explicit IndexedTranslationManipulator(
|
||||
TranslationManipulators::Dimensions dimensions, AZ::u64 vertIndex,
|
||||
const Vertex& position, const AZ::Transform& worldFromLocal)
|
||||
: m_manipulator(dimensions, worldFromLocal)
|
||||
const Vertex& position, const AZ::Transform& worldFromLocal, const AZ::Vector3& nonUniformScale)
|
||||
: m_manipulator(dimensions, worldFromLocal, nonUniformScale)
|
||||
{
|
||||
m_vertices.push_back({ position, Vertex::CreateZero(), vertIndex });
|
||||
}
|
||||
@@ -128,4 +129,4 @@ namespace AzToolsFramework
|
||||
void ConfigureTranslationManipulatorAppearance2d(
|
||||
TranslationManipulators* translationManipulators);
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/TemplateInstanceMapperInterface.h>
|
||||
@@ -36,6 +40,10 @@ namespace AzToolsFramework
|
||||
"Template Instance Mapper Interface could not be found. "
|
||||
"It is a requirement for the Prefab Instance class. "
|
||||
"Check that it is being correctly initialized.");
|
||||
|
||||
m_containerEntity = AZStd::make_unique<AZ::Entity>();
|
||||
EntityAlias containerEntityAlias = GenerateEntityAlias();
|
||||
RegisterEntity(m_containerEntity->GetId(), containerEntityAlias);
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
@@ -63,6 +71,7 @@ namespace AzToolsFramework
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<Instance>()
|
||||
->Field("m_containerEntity", &Instance::m_containerEntity)
|
||||
->Field("m_entities", &Instance::m_entities)
|
||||
->Field("m_nestedInstances", &Instance::m_nestedInstances)
|
||||
->Field("m_templateSourcePath", &Instance::m_templateSourcePath)
|
||||
@@ -120,6 +129,12 @@ namespace AzToolsFramework
|
||||
void Instance::SetTemplateSourcePath(AZStd::string sourcePath)
|
||||
{
|
||||
m_templateSourcePath = AZStd::move(sourcePath);
|
||||
|
||||
AZStd::string filename;
|
||||
if (AZ::StringFunc::Path::GetFileName(m_templateSourcePath.c_str(), filename))
|
||||
{
|
||||
m_containerEntity->SetName(filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool Instance::AddEntity(AZ::Entity& entity)
|
||||
@@ -167,6 +182,60 @@ namespace AzToolsFramework
|
||||
return removedEntity;
|
||||
}
|
||||
|
||||
void Instance::DetachNestedEntities(const AZStd::function<void(AZStd::unique_ptr<AZ::Entity>)>& callback)
|
||||
{
|
||||
DetachEntities(callback);
|
||||
|
||||
for (const auto& [instanceAlias, instance] : m_nestedInstances)
|
||||
{
|
||||
instance->DetachNestedEntities(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::DetachEntities(const AZStd::function<void(AZStd::unique_ptr<AZ::Entity>)>& callback)
|
||||
{
|
||||
for (auto&& [entityAlias, entity] : m_entities)
|
||||
{
|
||||
m_instanceEntityMapper->UnregisterEntity(entity->GetId());
|
||||
m_templateToInstanceEntityIdMap.erase(entityAlias);
|
||||
m_instanceToTemplateEntityIdMap.erase(entity->GetId());
|
||||
|
||||
callback(AZStd::move(entity));
|
||||
}
|
||||
|
||||
m_entities.clear();
|
||||
}
|
||||
|
||||
void Instance::RemoveNestedEntities(
|
||||
const AZStd::function<bool(const AZStd::unique_ptr<AZ::Entity>&)>& filter)
|
||||
{
|
||||
RemoveEntities(filter);
|
||||
|
||||
for (const auto& [instanceAlias, instance] : m_nestedInstances)
|
||||
{
|
||||
instance->RemoveNestedEntities(filter);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::RemoveEntities(
|
||||
const AZStd::function<bool(const AZStd::unique_ptr<AZ::Entity>&)>& filter)
|
||||
{
|
||||
AZStd::erase_if(m_entities,
|
||||
[this, &filter](const auto& item)
|
||||
{
|
||||
const auto& [entityAlias, entity] = item;
|
||||
const bool shouldRemove = filter(entity);
|
||||
if (shouldRemove)
|
||||
{
|
||||
m_instanceEntityMapper->UnregisterEntity(entity->GetId());
|
||||
m_templateToInstanceEntityIdMap.erase(entityAlias);
|
||||
m_instanceToTemplateEntityIdMap.erase(entity->GetId());
|
||||
}
|
||||
return shouldRemove;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void Instance::ClearEntities()
|
||||
{
|
||||
for (const auto&[entityAlias, entity] : m_entities)
|
||||
@@ -209,20 +278,14 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
InstanceOptionalReference Instance::AddInstance(AZStd::unique_ptr<Instance> instance)
|
||||
Instance& Instance::AddInstance(AZStd::unique_ptr<Instance> instance)
|
||||
{
|
||||
InstanceAlias newInstanceAlias = GenerateInstanceAlias();
|
||||
const auto [it, added] = m_nestedInstances.emplace(AZStd::make_pair(newInstanceAlias, AZStd::move(instance)));
|
||||
|
||||
if (added)
|
||||
{
|
||||
it->second->m_parent = this;
|
||||
it->second->m_alias = newInstanceAlias;
|
||||
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
AZ_Assert(instance.get(), "instance argument is nullptr");
|
||||
AZ_Assert(m_nestedInstances.find(newInstanceAlias) == m_nestedInstances.end(), "InstanceAlias' unique id collision, this should never happen.");
|
||||
instance->m_parent = this;
|
||||
instance->m_alias = newInstanceAlias;
|
||||
return *(m_nestedInstances[newInstanceAlias] = std::move(instance));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<Instance> Instance::DetachNestedInstance(const InstanceAlias& instanceAlias)
|
||||
@@ -252,19 +315,19 @@ namespace AzToolsFramework
|
||||
return entityAliases;
|
||||
}
|
||||
|
||||
void Instance::GetNestedEntityIds(const AZStd::function<bool(const AZ::EntityId&)>& callback)
|
||||
void Instance::GetNestedEntityIds(const AZStd::function<bool(AZ::EntityId)>& callback)
|
||||
{
|
||||
GetEntityIds(callback);
|
||||
|
||||
for (const auto&[instanceAlias, instance] : m_nestedInstances)
|
||||
for (auto&&[instanceAlias, instance] : m_nestedInstances)
|
||||
{
|
||||
instance->GetNestedEntityIds(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetEntityIds(const AZStd::function<bool(const AZ::EntityId&)>& callback)
|
||||
void Instance::GetEntityIds(const AZStd::function<bool(AZ::EntityId)>& callback)
|
||||
{
|
||||
for (const auto&[entityAlias, entityId] : m_templateToInstanceEntityIdMap)
|
||||
for (auto&&[entityAlias, entityId] : m_templateToInstanceEntityIdMap)
|
||||
{
|
||||
if (!callback(entityId))
|
||||
{
|
||||
@@ -273,6 +336,53 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetConstNestedEntities(const AZStd::function<bool(const AZ::Entity&)>& callback)
|
||||
{
|
||||
GetConstEntities(callback);
|
||||
|
||||
for (const auto& [instanceAlias, instance] : m_nestedInstances)
|
||||
{
|
||||
instance->GetConstNestedEntities(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetConstEntities(const AZStd::function<bool(const AZ::Entity&)>& callback)
|
||||
{
|
||||
for (const auto& [entityAlias, entity] : m_entities)
|
||||
{
|
||||
if (!entity)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!callback(*entity))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetNestedEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback)
|
||||
{
|
||||
GetEntities(callback);
|
||||
|
||||
for (auto& [instanceAlias, instance] : m_nestedInstances)
|
||||
{
|
||||
instance->GetNestedEntities(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback)
|
||||
{
|
||||
for (auto& [entityAlias, entity] : m_entities)
|
||||
{
|
||||
if (!callback(entity))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::GetEntities(EntityList& entities, bool includeNestedEntities)
|
||||
{
|
||||
// Non-recursive traversal of instances
|
||||
@@ -308,14 +418,14 @@ namespace AzToolsFramework
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::EntityId> Instance::GetEntityId(const EntityAlias& alias)
|
||||
AZ::EntityId Instance::GetEntityId(const EntityAlias& alias)
|
||||
{
|
||||
if (m_templateToInstanceEntityIdMap.count(alias))
|
||||
{
|
||||
return m_templateToInstanceEntityIdMap[alias];
|
||||
}
|
||||
|
||||
return AZStd::nullopt;
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
AZStd::vector<InstanceAlias> Instance::GetNestedInstanceAliases(TemplateId templateId) const
|
||||
@@ -430,5 +540,10 @@ namespace AzToolsFramework
|
||||
{
|
||||
return &instance == m_parent;
|
||||
}
|
||||
|
||||
AZ::EntityId Instance::GetContainerEntityId() const
|
||||
{
|
||||
return m_containerEntity->GetId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,10 @@ namespace AzToolsFramework
|
||||
|
||||
bool AddEntity(AZ::Entity& entity);
|
||||
AZStd::unique_ptr<AZ::Entity> DetachEntity(const AZ::EntityId& entityId);
|
||||
void DetachNestedEntities(const AZStd::function<void(AZStd::unique_ptr<AZ::Entity>)>& callback);
|
||||
void RemoveNestedEntities(const AZStd::function<bool(const AZStd::unique_ptr<AZ::Entity>&)>& filter);
|
||||
|
||||
InstanceOptionalReference AddInstance(AZStd::unique_ptr<Instance> instance);
|
||||
Instance& AddInstance(AZStd::unique_ptr<Instance> instance);
|
||||
AZStd::unique_ptr<Instance> DetachNestedInstance(const InstanceAlias& instanceAlias);
|
||||
|
||||
/**
|
||||
@@ -91,9 +93,17 @@ namespace AzToolsFramework
|
||||
/**
|
||||
* Gets the ids for the entities in the Instance DOM. Can recursively trace all nested instances.
|
||||
*/
|
||||
void GetNestedEntityIds(const AZStd::function<bool(const AZ::EntityId&)>& callback);
|
||||
void GetNestedEntityIds(const AZStd::function<bool(AZ::EntityId)>& callback);
|
||||
|
||||
void GetEntityIds(const AZStd::function<bool(const AZ::EntityId&)>& callback);
|
||||
void GetEntityIds(const AZStd::function<bool(AZ::EntityId)>& callback);
|
||||
|
||||
/**
|
||||
* Gets the entities in the Instance DOM. Can recursively trace all nested instances.
|
||||
*/
|
||||
void GetConstNestedEntities(const AZStd::function<bool(const AZ::Entity&)>& callback);
|
||||
void GetConstEntities(const AZStd::function<bool(const AZ::Entity&)>& callback);
|
||||
void GetNestedEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback);
|
||||
void GetEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback);
|
||||
|
||||
/**
|
||||
* Gets the alias for a given EnitityId in the Instance DOM.
|
||||
@@ -105,9 +115,9 @@ namespace AzToolsFramework
|
||||
/**
|
||||
* Gets the id for a given EnitityAlias in the Instance DOM.
|
||||
*
|
||||
* @return entityId via optional
|
||||
* @return entityId, invalid ID if not found
|
||||
*/
|
||||
AZStd::optional<AZ::EntityId> GetEntityId(const EntityAlias& alias);
|
||||
AZ::EntityId GetEntityId(const EntityAlias& alias);
|
||||
|
||||
|
||||
/**
|
||||
@@ -146,6 +156,8 @@ namespace AzToolsFramework
|
||||
|
||||
bool IsParentInstance(const Instance& instance) const;
|
||||
|
||||
AZ::EntityId GetContainerEntityId() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Gets the entities owned by this instance
|
||||
@@ -156,6 +168,9 @@ namespace AzToolsFramework
|
||||
|
||||
void ClearEntities();
|
||||
|
||||
void DetachEntities(const AZStd::function<void(AZStd::unique_ptr<AZ::Entity>)>& callback);
|
||||
void RemoveEntities(const AZStd::function<bool(const AZStd::unique_ptr<AZ::Entity>&)>& filter);
|
||||
|
||||
bool RegisterEntity(const AZ::EntityId& entityId, const EntityAlias& entityAlias);
|
||||
AZStd::unique_ptr<AZ::Entity> DetachEntity(const EntityAlias& entityAlias);
|
||||
|
||||
@@ -172,8 +187,10 @@ namespace AzToolsFramework
|
||||
// A map of prefab instance pointers that this prefab instance owns.
|
||||
AliasToInstanceMap m_nestedInstances;
|
||||
|
||||
// The entity representing this Instance as a container in the entity hierarchy.
|
||||
AZStd::unique_ptr<AZ::Entity> m_containerEntity;
|
||||
|
||||
// The id of the link that connects the template of this instance to it's source template.
|
||||
// The id of the link that connects the template of this instance to its source template.
|
||||
// This is not unique per instance. It's unique per link. It is invalid for instances that aren't nested under other instances.
|
||||
LinkId m_linkId = InvalidLinkId;
|
||||
|
||||
|
||||
+109
-103
@@ -42,26 +42,21 @@ namespace AzToolsFramework
|
||||
inputAlias = EntityAlias(inputValue.GetString(), inputValue.GetStringLength());
|
||||
}
|
||||
|
||||
if(!inputAlias.empty())
|
||||
if (!inputAlias.empty())
|
||||
{
|
||||
auto entityIdMapIter = m_loadingInstance->m_templateToInstanceEntityIdMap.find(inputAlias);
|
||||
|
||||
if (entityIdMapIter != m_loadingInstance->m_templateToInstanceEntityIdMap.end())
|
||||
if (m_isEntityReference)
|
||||
{
|
||||
mappedValue = entityIdMapIter->second;
|
||||
m_unresolvedEntityAliases[m_loadingInstance].emplace_back(inputAlias, &outputValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputAlias[0] != ReferencePathDelimiter)
|
||||
mappedValue = AZ::Entity::MakeId();
|
||||
|
||||
if (m_loadingInstance->RegisterEntity(mappedValue, inputAlias))
|
||||
{
|
||||
mappedValue = AZ::Entity::MakeId();
|
||||
m_resolvedEntityAliases[m_loadingInstance].emplace_back(inputAlias, mappedValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappedValue = ResolveEntityReferencePath(inputAlias);
|
||||
}
|
||||
|
||||
if (!m_loadingInstance->RegisterEntity(mappedValue, inputAlias))
|
||||
{
|
||||
mappedValue = AZ::EntityId(AZ::EntityId::InvalidEntityId);
|
||||
context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed,
|
||||
@@ -92,15 +87,27 @@ namespace AzToolsFramework
|
||||
EntityAlias mappedValue;
|
||||
if (inputValue.IsValid())
|
||||
{
|
||||
auto idMapIter = m_storingInstance->m_instanceToTemplateEntityIdMap.find(inputValue);
|
||||
|
||||
if (idMapIter != m_storingInstance->m_instanceToTemplateEntityIdMap.end())
|
||||
if (m_isEntityReference)
|
||||
{
|
||||
mappedValue = idMapIter->second;
|
||||
mappedValue = ResolveReferenceId(inputValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappedValue = ResolveEntityId(inputValue);
|
||||
auto idMapIter = m_storingInstance->m_instanceToTemplateEntityIdMap.find(inputValue);
|
||||
|
||||
if (idMapIter != m_storingInstance->m_instanceToTemplateEntityIdMap.end())
|
||||
{
|
||||
mappedValue = idMapIter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::string defaultErrorMessage =
|
||||
"Entity with Id " + inputValue.ToString() +
|
||||
" could not be found within its owning instance. Defaulting to invalid Id for Store.";
|
||||
|
||||
AZ_Assert(false, defaultErrorMessage.c_str());
|
||||
context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, defaultErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +119,7 @@ namespace AzToolsFramework
|
||||
void InstanceEntityIdMapper::SetStoringInstance(const Instance& storingInstance)
|
||||
{
|
||||
m_storingInstance = &storingInstance;
|
||||
GetAbsoluteInstanceAliasPath(m_storingInstance, m_instanceAbsolutePath);
|
||||
}
|
||||
|
||||
void InstanceEntityIdMapper::SetLoadingInstance(Instance& loadingInstance)
|
||||
@@ -119,77 +127,87 @@ namespace AzToolsFramework
|
||||
m_loadingInstance = &loadingInstance;
|
||||
}
|
||||
|
||||
AZ::EntityId InstanceEntityIdMapper::ResolveEntityReferencePath(const AZStd::string& entityIdReferencePath)
|
||||
void InstanceEntityIdMapper::FixUpUnresolvedEntityReferences()
|
||||
{
|
||||
// If we can't resolve the path treat the entire path as one alias.
|
||||
// Assigning a random id instead of an invalid id will save off a unique mapping.
|
||||
// Allowing the ability to store the instance back to this full alias again.
|
||||
// This prevents the replacement of the path with an empty alias and avoids data loss.
|
||||
AZ::EntityId resolvedId = AZ::Entity::MakeId();
|
||||
|
||||
AZStd::string_view referencePathView = entityIdReferencePath;
|
||||
|
||||
// Trim the starting '/' from the path view as tokenizing it would result in an empty token
|
||||
referencePathView.remove_prefix(1);
|
||||
|
||||
AZStd::optional<AZStd::string_view> currentPathToken = AZ::StringFunc::TokenizeNext(referencePathView, ReferencePathDelimiter);
|
||||
|
||||
const Instance* currentInstance = m_loadingInstance;
|
||||
|
||||
// Walk down the instance hierarchy using the Alias path
|
||||
while(!referencePathView.empty() && currentPathToken.has_value())
|
||||
// Nothing to resolve
|
||||
if (m_unresolvedEntityAliases.empty())
|
||||
{
|
||||
auto aliasedInstanceIter = currentInstance->m_nestedInstances.find(currentPathToken.value());
|
||||
if (aliasedInstanceIter != currentInstance->m_nestedInstances.end())
|
||||
{
|
||||
AZ_Assert(aliasedInstanceIter->second,
|
||||
"Prefab - EntityIdMapper: An instance of %s contained a null instance using alias %.*s",
|
||||
currentInstance->GetTemplateSourcePath().c_str(),
|
||||
aznumeric_cast<int>(currentPathToken.value().size()), currentPathToken.value().data());
|
||||
return;
|
||||
}
|
||||
|
||||
currentInstance = aliasedInstanceIter->second.get();
|
||||
// Calculate the absolute path to each instance based on its position in the hierarchy
|
||||
// We'll use this to generate the absolute paths of resolved and unresolved aliases
|
||||
AZStd::unordered_map<Instance*, AliasPath> absoluteInstanceAliasPaths;
|
||||
absoluteInstanceAliasPaths.reserve(m_resolvedEntityAliases.bucket_count());
|
||||
|
||||
// Also calculate the absolute path to each resolved entity based on its position in the hierarchy
|
||||
AZStd::unordered_map<AliasPath, AZ::EntityId> resolvedAbsoluteEntityAliasPaths;
|
||||
|
||||
for (auto& [instance, resolvedAliasIdList] : m_resolvedEntityAliases)
|
||||
{
|
||||
AliasPath absoluteInstancePath;
|
||||
GetAbsoluteInstanceAliasPath(instance, absoluteInstancePath);
|
||||
|
||||
absoluteInstanceAliasPaths.emplace(instance, absoluteInstancePath);
|
||||
|
||||
for (auto& [entityAlias, entityId] : resolvedAliasIdList)
|
||||
{
|
||||
resolvedAbsoluteEntityAliasPaths.emplace(absoluteInstancePath / entityAlias, entityId);
|
||||
}
|
||||
}
|
||||
|
||||
// Using the absolute paths of the instances containing the unresolved aliases
|
||||
// Attempt to find a match within the resolved paths
|
||||
// A match will allow us to update the unresolved reference id to match the id it's referencing
|
||||
for (auto& [instance, unresolvedAliasIdList] : m_unresolvedEntityAliases)
|
||||
{
|
||||
auto findResolvedInstance = absoluteInstanceAliasPaths.find(instance);
|
||||
|
||||
if (findResolvedInstance != absoluteInstanceAliasPaths.end())
|
||||
{
|
||||
AliasPath& absoluteInstancePath = findResolvedInstance->second;
|
||||
|
||||
for (auto& [entityAlias, entityPointer] : unresolvedAliasIdList)
|
||||
{
|
||||
AliasPath absoluteEntityReferencePath = (absoluteInstancePath / entityAlias).LexicallyNormal();
|
||||
|
||||
auto foundResolvedPath =
|
||||
resolvedAbsoluteEntityAliasPaths.find(absoluteEntityReferencePath);
|
||||
|
||||
if (foundResolvedPath != resolvedAbsoluteEntityAliasPaths.end())
|
||||
{
|
||||
*entityPointer = foundResolvedPath->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("Prefabs", false,
|
||||
"Unable to resolve entity reference alias path [%s] while loading Prefab instance. "
|
||||
"The reference was likely made on a parent or sibling prefab without the use of an override. "
|
||||
"Defaulting the reference to an invalid EntityId.",
|
||||
absoluteEntityReferencePath.String().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's ever a path mismatch then there's no valid entity to reference
|
||||
return resolvedId;
|
||||
AZ_Assert(false, "Prefabs - "
|
||||
"Attempted to resolve entity alias path(s) but the instance owning the unresolved reference has no entities. "
|
||||
"An Entity Reference can only come from an entity/component property.");
|
||||
}
|
||||
|
||||
currentPathToken = AZ::StringFunc::TokenizeNext(referencePathView, ReferencePathDelimiter);
|
||||
}
|
||||
|
||||
// If we ever recieved an invalid token then our path was empty or we walked too far
|
||||
if (!currentPathToken.has_value())
|
||||
{
|
||||
return resolvedId;
|
||||
}
|
||||
|
||||
// Our current alias should be an entity in our current instance
|
||||
auto aliasedEntityIter = currentInstance->m_entities.find(currentPathToken.value());
|
||||
if (aliasedEntityIter != currentInstance->m_entities.end())
|
||||
{
|
||||
const AZStd::unique_ptr<AZ::Entity>& aliasedEntity = aliasedEntityIter->second;
|
||||
|
||||
AZ_Assert(aliasedEntity,
|
||||
"Prefab - EntityIdMapper: An instance of %s contained a null entity using alias %s",
|
||||
currentInstance->GetTemplateSourcePath().c_str(),
|
||||
aznumeric_cast<int>(currentPathToken.value().size()), currentPathToken.value().data());
|
||||
|
||||
resolvedId = aliasedEntity->GetId();
|
||||
}
|
||||
|
||||
return resolvedId;
|
||||
return;
|
||||
}
|
||||
|
||||
EntityAlias InstanceEntityIdMapper::ResolveEntityId(const AZ::EntityId& entityId)
|
||||
EntityAlias InstanceEntityIdMapper::ResolveReferenceId(const AZ::EntityId& entityId)
|
||||
{
|
||||
// Acquire the owning instance of our entity
|
||||
InstanceOptionalReference currentInstanceOptionalReference = m_storingInstance->m_instanceEntityMapper->FindOwningInstance(entityId);
|
||||
InstanceOptionalReference owningInstanceReference = m_storingInstance->m_instanceEntityMapper->FindOwningInstance(entityId);
|
||||
|
||||
// Start with an empty alias to build out our reference path
|
||||
// If we can't resolve this id we'll return a random new alias instead of a reference path
|
||||
EntityAlias resolvedAlias;
|
||||
if (!currentInstanceOptionalReference)
|
||||
AliasPath relativeEntityAliasPath;
|
||||
if (!owningInstanceReference)
|
||||
{
|
||||
AZ_Assert(false,
|
||||
"Prefab - EntityIdMapper: Entity with Id %s has no registered owning instance",
|
||||
@@ -197,41 +215,29 @@ namespace AzToolsFramework
|
||||
|
||||
return Instance::GenerateEntityAlias();
|
||||
}
|
||||
Instance* currentInstance = &(currentInstanceOptionalReference->get());
|
||||
|
||||
// This entity should have an alias in its owning instance
|
||||
// If not
|
||||
auto entityAliasIter = currentInstance->m_instanceToTemplateEntityIdMap.find(entityId);
|
||||
if (entityAliasIter == currentInstance->m_instanceToTemplateEntityIdMap.end())
|
||||
Instance* owningInstance = &(owningInstanceReference->get());
|
||||
|
||||
// Build out the absolute path of this alias
|
||||
// so we can compare it to the absolute path of our currently scoped instance
|
||||
GetAbsoluteInstanceAliasPath(owningInstance, relativeEntityAliasPath);
|
||||
relativeEntityAliasPath.Append(owningInstance->GetEntityAlias(entityId)->get());
|
||||
|
||||
return relativeEntityAliasPath.LexicallyRelative(m_instanceAbsolutePath).String();
|
||||
}
|
||||
|
||||
void InstanceEntityIdMapper::GetAbsoluteInstanceAliasPath(const Instance* instance, AliasPath& aliasPathResult)
|
||||
{
|
||||
// Reset the path using our preferred seperator
|
||||
aliasPathResult = AliasPath(m_aliasPathSeperator);
|
||||
const Instance* currentInstance = instance;
|
||||
|
||||
// If no parent instance we are a root instance and our absolute path is empty
|
||||
while (currentInstance->m_parent)
|
||||
{
|
||||
AZ_Assert(false,
|
||||
"Prefab - EntityIdMapper: Instance of Prefab %s was registered to own entity with Id %s. "
|
||||
"However the entity has no alias within the instance",
|
||||
currentInstance->GetTemplateSourcePath().c_str(), entityId.ToString().c_str());
|
||||
|
||||
return Instance::GenerateEntityAlias();
|
||||
}
|
||||
|
||||
// Start off the reference path with /EntityAlias
|
||||
resolvedAlias = ReferencePathDelimiter + entityAliasIter->second;
|
||||
|
||||
// Walk up the instance hierarchy
|
||||
while (currentInstance)
|
||||
{
|
||||
if (currentInstance == m_storingInstance)
|
||||
{
|
||||
// Path is resolved if we intersect with the instance resolving this id
|
||||
return resolvedAlias;
|
||||
}
|
||||
|
||||
// Continue building out the reference path
|
||||
// /InstanceAlias/InstanceAlias/EntityAlias
|
||||
resolvedAlias = ReferencePathDelimiter + currentInstance->m_alias + resolvedAlias;
|
||||
aliasPathResult.Append(currentInstance->m_alias);
|
||||
currentInstance = currentInstance->m_parent;
|
||||
}
|
||||
|
||||
// If we hit a null instance we failed to resolve the id
|
||||
return Instance::GenerateEntityAlias();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-4
@@ -13,13 +13,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/EntityIdSerializer.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class Instance;
|
||||
|
||||
class InstanceEntityIdMapper
|
||||
class InstanceEntityIdMapper final
|
||||
: public AZ::JsonEntityIdSerializer::JsonEntityIdMapper
|
||||
{
|
||||
public:
|
||||
@@ -31,14 +33,33 @@ namespace AzToolsFramework
|
||||
void SetStoringInstance(const Instance& storingInstance);
|
||||
void SetLoadingInstance(Instance& loadingInstance);
|
||||
|
||||
/**
|
||||
* Fixes up any unresolved entity references by assigning them to the id value of the entity it references.
|
||||
* This is done by computing the absolute alias paths of all EntityIds and EntityId references
|
||||
* then matching the references to the id values they reference.
|
||||
* During a load instance and alias information is stored to build out these paths,
|
||||
* but will be incomplete until the whole Load call is finished.
|
||||
* Calling this after Load and the mapper have finished will give complete information
|
||||
* on all entities and references discovered in the load
|
||||
*/
|
||||
void FixUpUnresolvedEntityReferences();
|
||||
|
||||
private:
|
||||
AZ::EntityId ResolveEntityReferencePath(const AZStd::string& entityIdReferencePath);
|
||||
EntityAlias ResolveEntityId(const AZ::EntityId& entityId);
|
||||
using AliasPath = AZ::IO::Path;
|
||||
|
||||
EntityAlias ResolveReferenceId(const AZ::EntityId& entityId);
|
||||
|
||||
void GetAbsoluteInstanceAliasPath(const Instance* instance, AliasPath& aliasPathResult);
|
||||
|
||||
AliasPath m_instanceAbsolutePath;
|
||||
|
||||
const Instance* m_storingInstance = nullptr;
|
||||
Instance* m_loadingInstance = nullptr;
|
||||
|
||||
inline static constexpr char ReferencePathDelimiter = '/';
|
||||
static constexpr const char m_aliasPathSeperator = '/';
|
||||
|
||||
AZStd::unordered_map<Instance*, AZStd::vector<AZStd::pair<EntityAlias, AZ::EntityId>>> m_resolvedEntityAliases;
|
||||
AZStd::unordered_map<Instance*, AZStd::vector<AZStd::pair<EntityAlias, AZ::EntityId*>>> m_unresolvedEntityAliases;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ namespace AzToolsFramework
|
||||
protected:
|
||||
// Only the Instance class is allowed to register and unregister entities
|
||||
friend class Instance;
|
||||
friend class JsonInstanceSerializer;
|
||||
|
||||
virtual bool RegisterEntityToInstance(const AZ::EntityId& entityId, Prefab::Instance& instance) = 0;
|
||||
virtual bool UnregisterEntity(const AZ::EntityId& entityId) = 0;
|
||||
|
||||
+28
-15
@@ -15,6 +15,7 @@
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceSerializer.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -50,6 +51,14 @@ namespace AzToolsFramework
|
||||
|
||||
result = ContinueStoringToJsonObjectField(outputValue, "Source", sourcePath, defaultSourcePath, azrtti_typeid<AZStd::string>(), context);
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathContainerEntity(context, "m_containerEntity");
|
||||
JSR::ResultCode resultContainerEntity = ContinueStoringToJsonObjectField(outputValue, "ContainerEntity",
|
||||
&instance->m_containerEntity, nullptr, azrtti_typeid<decltype(instance->m_containerEntity)>(), context);
|
||||
|
||||
result.Combine(resultContainerEntity);
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathEntities(context, "m_entities");
|
||||
@@ -94,15 +103,8 @@ namespace AzToolsFramework
|
||||
|
||||
InstanceEntityIdMapper** idMapper = context.GetMetadata().Find<InstanceEntityIdMapper*>();
|
||||
|
||||
if (idMapper && *idMapper)
|
||||
{
|
||||
(*idMapper)->SetLoadingInstance(*instance);
|
||||
}
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
{
|
||||
AZ::ScopedContextPath subPathSource(context, "Source");
|
||||
|
||||
JSR::ResultCode sourceLoadResult =
|
||||
ContinueLoadingFromJsonObjectField(&instance->m_templateSourcePath, azrtti_typeid<AZStd::string>(), inputValue, "Source", context);
|
||||
|
||||
@@ -123,8 +125,6 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathInstances(context, "Instances");
|
||||
|
||||
// An already filled instance should be cleared if inputValue's Instances member is empty
|
||||
// The Json serializer will not do this by default as it will not attempt to load a missing member
|
||||
if (!instance->m_nestedInstances.empty() && !inputValue.HasMember("Instances"))
|
||||
@@ -146,19 +146,32 @@ namespace AzToolsFramework
|
||||
result.Combine(instanceResult);
|
||||
}
|
||||
|
||||
// An already filled instance should be cleared if inputValue's Entities member is empty
|
||||
// The Json serializer will not do this by default as it will not attempt to load a missing member
|
||||
instance->ClearEntities();
|
||||
|
||||
if (instance->m_containerEntity)
|
||||
{
|
||||
AZ::ScopedContextPath subPathEntities(context, "Entities");
|
||||
instance->m_instanceEntityMapper->UnregisterEntity(instance->m_containerEntity->GetId());
|
||||
}
|
||||
|
||||
// An already filled instance should be cleared if inputValue's Entities member is empty
|
||||
// The Json serializer will not do this by default as it will not attempt to load a missing member
|
||||
instance->ClearEntities();
|
||||
if (idMapper && *idMapper)
|
||||
{
|
||||
(*idMapper)->SetLoadingInstance(*instance);
|
||||
}
|
||||
|
||||
{
|
||||
JSR::ResultCode containerEntityResult = ContinueLoadingFromJsonObjectField(
|
||||
&instance->m_containerEntity, azrtti_typeid<decltype(instance->m_containerEntity)>(), inputValue, "ContainerEntity", context);
|
||||
|
||||
result.Combine(containerEntityResult);
|
||||
}
|
||||
|
||||
{
|
||||
result.Combine(ContinueLoadingFromJsonObjectField(&instance->m_entities, azrtti_typeid<Instance::AliasToEntityMap>(), inputValue, "Entities", context));
|
||||
}
|
||||
|
||||
{
|
||||
AZ::ScopedContextPath subPathEntities(context, "LinkId");
|
||||
|
||||
result.Combine(ContinueLoadingFromJsonObjectField(&instance->m_linkId, azrtti_typeid<LinkId>(), inputValue, "LinkId", context));
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -30,7 +30,7 @@ namespace AzToolsFramework
|
||||
virtual bool GenerateDomForEntity(PrefabDom& generatedEntityDom, const AZ::Entity& entity) = 0;
|
||||
|
||||
//! Generates a prefabdom for the instance in its current state and places the result in generatedDom
|
||||
virtual bool GenerateDomForInstance(PrefabDom& generatedInstanceDom, const Prefab::Instance& instance) = 0;
|
||||
virtual bool GenerateDomForInstance(PrefabDom& generatedInstanceDom, const Instance& instance) = 0;
|
||||
|
||||
//! Generates a patch using serialization system and places the result in generatedPatch
|
||||
virtual bool GeneratePatch(PrefabDom& generatedPatch, const PrefabDom& initialState, const PrefabDom& modifiedState) = 0;
|
||||
@@ -42,6 +42,8 @@ namespace AzToolsFramework
|
||||
//! Updates the affected template for a given entityId using the providedPatch
|
||||
virtual void PatchEntityInTemplate(PrefabDomValue& providedPatch, const AZ::EntityId& entityId) = 0;
|
||||
|
||||
virtual void PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId) = 0;
|
||||
|
||||
//! Updates the template links (updating instances) for the given templateId using the providedPatch
|
||||
virtual void PatchTemplate(PrefabDomValue& providedPatch, const AzToolsFramework::Prefab::TemplateId& templateId) = 0;
|
||||
|
||||
|
||||
+15
-14
@@ -124,44 +124,45 @@ namespace AzToolsFramework
|
||||
|
||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
PrefabDom templateDom;
|
||||
templateDom.CopyFrom(templateDomReference, templateDom.GetAllocator());
|
||||
PatchEntityInTemplate(providedPatch, entityAlias.value(), templateId);
|
||||
}
|
||||
|
||||
void InstanceToTemplatePropagator::PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId)
|
||||
{
|
||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
//query into the template dom for the alias
|
||||
PrefabDomValueReference entityList = PrefabDomUtils::FindPrefabDomValue(templateDom, "Entities");
|
||||
PrefabDomValueReference entityList = PrefabDomUtils::FindPrefabDomValue(templateDomReference, PrefabDomUtils::EntitiesName);
|
||||
|
||||
PrefabDomValueReference entity = PrefabDomUtils::FindPrefabDomValue(entityList->get(), entityAlias->c_str());
|
||||
PrefabDomValueReference entity = PrefabDomUtils::FindPrefabDomValue(entityList->get(), entityAlias.c_str());
|
||||
AZ_Error("Prefab", entity != AZStd::nullopt, "Failed to aquire entity value reference")
|
||||
|
||||
//apply patch to section
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(entity->get(),
|
||||
templateDom.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
|
||||
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
||||
"Patch was not successfully applied")
|
||||
|
||||
//update the Dom and trigger propogation
|
||||
m_prefabSystemComponentInterface->UpdatePrefabTemplate(templateId, templateDom);
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId);
|
||||
}
|
||||
|
||||
void InstanceToTemplatePropagator::PatchTemplate(PrefabDomValue& providedPatch, const TemplateId& templateId)
|
||||
{
|
||||
const PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
PrefabDom templateDom;
|
||||
templateDom.CopyFrom(templateDomReference, templateDom.GetAllocator());
|
||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||
|
||||
//apply patch to template
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDom,
|
||||
templateDom.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference,
|
||||
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
||||
|
||||
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
||||
"Patch was not successfully applied")
|
||||
"Patch was not successfully applied");
|
||||
|
||||
//update the Dom and trigger propogation
|
||||
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success)
|
||||
{
|
||||
m_prefabSystemComponentInterface->UpdatePrefabTemplate(templateId, templateDom);
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ namespace AzToolsFramework
|
||||
bool GeneratePatchForLink(PrefabDom& generatedPatch, const PrefabDom& initialState,
|
||||
const PrefabDom& modifiedState, LinkId linkId) override;
|
||||
void PatchEntityInTemplate(PrefabDomValue& providedPatch, const AZ::EntityId& entityId) override;
|
||||
void PatchEntityInTemplate(PrefabDomValue& providedPatch, const EntityAlias& entityAlias, const TemplateId& templateId) override;
|
||||
|
||||
InstanceOptionalReference GetTopMostInstanceInHierarchy(AZ::EntityId entityId);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/JSON/pointer.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -23,6 +24,7 @@ namespace AzToolsFramework
|
||||
using PrefabDom = rapidjson::Document;
|
||||
using PrefabDomValue = rapidjson::Value;
|
||||
using PrefabDomPath = rapidjson::Pointer;
|
||||
using PrefabDomList = AZStd::vector<PrefabDom>;
|
||||
|
||||
using PrefabDomValueReference = AZStd::optional<AZStd::reference_wrapper<PrefabDomValue>>;
|
||||
using PrefabDomValueConstReference = AZStd::optional<AZStd::reference_wrapper<const PrefabDomValue>>;
|
||||
|
||||
@@ -93,6 +93,8 @@ namespace AzToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
entityIdMapper.FixUpUnresolvedEntityReferences();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace AzToolsFramework
|
||||
inline static const char* PatchesName = "Patches";
|
||||
inline static const char* SourceName = "Source";
|
||||
inline static const char* LinkIdName = "LinkId";
|
||||
inline static const char* EntitiesName = "Entities";
|
||||
|
||||
/**
|
||||
* Find Prefab value from given parent value and target value's name.
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
"PrefabLoader::LoadTemplate - "
|
||||
"Prefab fie %s has been detected to directly or indirectly depend on itself."
|
||||
"Prefab file %s has been detected to directly or indirectly depend on itself."
|
||||
"Terminating any further loading of this branch of its prefab hierarchy.",
|
||||
filePath.c_str());
|
||||
return InvalidTemplateId;
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
||||
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
PrefabPublicHandler::PrefabPublicHandler()
|
||||
{
|
||||
m_instanceEntityMapperInterface = AZ::Interface<InstanceEntityMapperInterface>::Get();
|
||||
AZ_Assert(m_instanceEntityMapperInterface, "PrefabPublicHandler - Could not retrieve instance of InstanceEntityMapperInterface");
|
||||
|
||||
AZ::Interface<PrefabPublicInterface>::Register(this);
|
||||
}
|
||||
|
||||
PrefabPublicHandler::~PrefabPublicHandler()
|
||||
{
|
||||
AZ::Interface<PrefabPublicInterface>::Unregister(this);
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath)
|
||||
{
|
||||
// Retrieve entityList from entityIds
|
||||
EntityList inputEntityList;
|
||||
inputEntityList.reserve(entityIds.size());
|
||||
|
||||
for (AZ::EntityId entityId : entityIds)
|
||||
{
|
||||
if (entityId.IsValid())
|
||||
{
|
||||
inputEntityList.emplace_back(GetEntityById(entityId));
|
||||
}
|
||||
}
|
||||
|
||||
// Find common root and top level entities
|
||||
bool entitiesHaveCommonRoot = false;
|
||||
AZ::EntityId commonRootEntityId;
|
||||
EntityList topLevelEntities;
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(
|
||||
entitiesHaveCommonRoot,
|
||||
&AzToolsFramework::ToolsApplicationRequests::FindCommonRootInactive,
|
||||
inputEntityList,
|
||||
commonRootEntityId,
|
||||
&topLevelEntities
|
||||
);
|
||||
|
||||
// Bail if entities don't share a common root
|
||||
if (!entitiesHaveCommonRoot)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - entities do not share a common root."));
|
||||
}
|
||||
|
||||
AZ::Entity* commonRootEntity = nullptr;
|
||||
if (commonRootEntityId.IsValid())
|
||||
{
|
||||
commonRootEntity = GetEntityById(commonRootEntityId);
|
||||
}
|
||||
|
||||
// Retrieve the owning instance of the common root entity, which will be our new instance's parent instance.
|
||||
InstanceOptionalReference commonRootEntityOwningInstance = GetCommonRootEntityOwningInstance(commonRootEntityId);
|
||||
AZ_Assert(commonRootEntityOwningInstance.has_value(), "Failed to create prefab : "
|
||||
"Couldn't get a valid owning instance for the common root entity of the enities provided");
|
||||
|
||||
AZStd::vector<AZ::Entity*> entities;
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> instances;
|
||||
|
||||
// Retrieve all entities affected and identify Instances
|
||||
if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - entities do not share a common root."));
|
||||
}
|
||||
|
||||
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
if (!prefabEditorEntityOwnershipInterface)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
|
||||
"(PrefabEditorEntityOwnershipInterface unavailable)."));
|
||||
}
|
||||
|
||||
InstanceOptionalReference instance = prefabEditorEntityOwnershipInterface->CreatePrefab(
|
||||
entities, AZStd::move(instances), filePath, commonRootEntityOwningInstance->get());
|
||||
|
||||
if (!instance)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
|
||||
"(A null instance is returned)."));
|
||||
}
|
||||
|
||||
auto prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
if (prefabLoaderInterface == nullptr)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error (PrefabLoaderInterface unavailable)."));
|
||||
}
|
||||
|
||||
AZ::EntityId containerEntityId = instance->get().GetContainerEntityId();
|
||||
AZ::Vector3 containerEntityTranslation(AZ::Vector3::CreateZero());
|
||||
AZ::Quaternion containerEntityRotation(AZ::Quaternion::CreateZero());
|
||||
|
||||
// Set the transform (translation, rotation) of the container entity
|
||||
GenerateContainerEntityTransform(topLevelEntities, containerEntityTranslation, containerEntityRotation);
|
||||
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalTranslation, containerEntityTranslation);
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, containerEntityRotation);
|
||||
|
||||
// Set container entity to be child of common root
|
||||
AZ::TransformBus::Event(containerEntityId, &AZ::TransformBus::Events::SetParent, commonRootEntityId);
|
||||
|
||||
// Change top level entities to be parented to the container entity
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
AZ::TransformBus::Event(topLevelEntity->GetId(), &AZ::TransformBus::Events::SetParent, containerEntityId);
|
||||
}
|
||||
|
||||
// Register container entity to PrefabUiHandler
|
||||
auto editorEntityUiInterface = AZ::Interface<EditorEntityUiInterface>::Get();
|
||||
|
||||
if (editorEntityUiInterface != nullptr)
|
||||
{
|
||||
editorEntityUiInterface->RegisterEntity(containerEntityId, 1);
|
||||
}
|
||||
|
||||
// Save Template
|
||||
prefabLoaderInterface->SaveTemplate(instance->get().GetTemplateId());
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(AZStd::string_view /*filePath*/, AZ::EntityId /*parent*/, AZ::Vector3 /*position*/)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Prefab - InstantiatePrefab is yet to be implemented."));
|
||||
}
|
||||
|
||||
bool PrefabPublicHandler::IsInstanceContainerEntity(AZ::EntityId entityId)
|
||||
{
|
||||
AZ::Entity* entity = GetEntityById(entityId);
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entity->GetId());
|
||||
return owningInstance && (owningInstance->get().GetContainerEntityId() == entityId);
|
||||
}
|
||||
|
||||
AZ::EntityId PrefabPublicHandler::GetInstanceContainerEntityId(AZ::EntityId entityId)
|
||||
{
|
||||
AZ::Entity* entity = GetEntityById(entityId);
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entity->GetId());
|
||||
if (owningInstance)
|
||||
{
|
||||
return owningInstance->get().GetContainerEntityId();
|
||||
}
|
||||
|
||||
return AZ::EntityId();
|
||||
}
|
||||
|
||||
void PrefabPublicHandler::GenerateContainerEntityTransform(const EntityList& topLevelEntities,
|
||||
AZ::Vector3& translation, AZ::Quaternion& rotation)
|
||||
{
|
||||
// --- Multiple top level entities
|
||||
// Translation is the average of all translations, with the minimum Z value.
|
||||
// Rotation is set to zero.
|
||||
if (topLevelEntities.size() > 1)
|
||||
{
|
||||
AZ::Vector3 translationSum = AZ::Vector3::CreateZero();
|
||||
float minZ = AZStd::numeric_limits<float>::max();
|
||||
int transformCount = 0;
|
||||
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
if (topLevelEntity != nullptr)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
topLevelEntity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
if (transformComponent != nullptr)
|
||||
{
|
||||
++transformCount;
|
||||
|
||||
auto currentTranslation = transformComponent->GetLocalTranslation();
|
||||
translationSum += currentTranslation;
|
||||
minZ = AZ::GetMin<float>(minZ, currentTranslation.GetZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (transformCount > 0)
|
||||
{
|
||||
translation = translationSum / aznumeric_cast<float>(transformCount);
|
||||
translation.SetZ(minZ);
|
||||
|
||||
rotation = AZ::Quaternion::CreateZero();
|
||||
}
|
||||
|
||||
}
|
||||
// --- Single top level entity
|
||||
// World Translation and Rotation are inherited, unchanged.
|
||||
else if (topLevelEntities.size() == 1)
|
||||
{
|
||||
AZ::Entity* topLevelEntity = topLevelEntities[0];
|
||||
if (topLevelEntity)
|
||||
{
|
||||
AzToolsFramework::Components::TransformComponent* transformComponent =
|
||||
topLevelEntity->FindComponent<AzToolsFramework::Components::TransformComponent>();
|
||||
|
||||
if (transformComponent)
|
||||
{
|
||||
translation = transformComponent->GetLocalTranslation();
|
||||
|
||||
rotation = transformComponent->GetLocalRotationQuaternion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstanceOptionalReference PrefabPublicHandler::GetCommonRootEntityOwningInstance(AZ::EntityId entityId)
|
||||
{
|
||||
if (entityId.IsValid())
|
||||
{
|
||||
return m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||
}
|
||||
|
||||
// If the commonRootEntity is invalid, then the owning instance would be the root prefab instance of the
|
||||
// PrefabEditorEntityOwnershipService.
|
||||
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
|
||||
if (!prefabEditorEntityOwnershipInterface)
|
||||
{
|
||||
AZ_Assert(false, "Could not get owining instance of common root entity :"
|
||||
"PrefabEditorEntityOwnershipInterface unavailable.");
|
||||
}
|
||||
return prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
|
||||
}
|
||||
|
||||
Instance* PrefabPublicHandler::GetParentInstance(Instance* instance)
|
||||
{
|
||||
auto instanceRef = instance->GetParentInstance();
|
||||
|
||||
if (instanceRef != AZStd::nullopt)
|
||||
{
|
||||
return &instanceRef->get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Instance* PrefabPublicHandler::GetAncestorOfInstanceThatIsChildOfRoot(const Instance* root, Instance* instance)
|
||||
{
|
||||
while (instance != nullptr)
|
||||
{
|
||||
Instance* parent = GetParentInstance(instance);
|
||||
|
||||
if (parent == root)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
instance = parent;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PrefabPublicHandler::RetrieveAndSortPrefabEntitiesAndInstances(
|
||||
const EntityList& inputEntities, const Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities, AZStd::vector<AZStd::unique_ptr<Instance>>& outInstances) const
|
||||
{
|
||||
AZStd::queue<AZ::Entity*> entityQueue;
|
||||
|
||||
for (auto inputEntity : inputEntities)
|
||||
{
|
||||
entityQueue.push(inputEntity);
|
||||
}
|
||||
|
||||
// Support sets to easily identify if we're processing the same entity multiple times.
|
||||
AZStd::unordered_set<AZ::Entity*> entities;
|
||||
AZStd::unordered_set<Instance*> instances;
|
||||
|
||||
while (!entityQueue.empty())
|
||||
{
|
||||
AZ::Entity* entity = entityQueue.front();
|
||||
entityQueue.pop();
|
||||
|
||||
// Get this entity's owning instance.
|
||||
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entity->GetId());
|
||||
AZ_Assert(owningInstance.has_value(), "An error occored while retrieving entities and prefab instances : "
|
||||
"Owning instance of entity with id '%llu' couldn't be found", entity->GetId());
|
||||
|
||||
// Check if this entity is owned by the same instance owning the root.
|
||||
if (&owningInstance->get() == &commonRootEntityOwningInstance)
|
||||
{
|
||||
AZStd::unique_ptr<AZ::Entity> detachedEntity = owningInstance->get().DetachEntity(entity->GetId());
|
||||
// If it's the same instance, we can add this entity to the new instance entities.
|
||||
int priorEntitiesSize = entities.size();
|
||||
|
||||
entities.insert(detachedEntity.release());
|
||||
|
||||
// If the size of entities increased, then it wasn't added before.
|
||||
// In that case, add the children of this entity to the queue.
|
||||
if (entities.size() > priorEntitiesSize)
|
||||
{
|
||||
EntityIdList childrenIds;
|
||||
EditorEntityInfoRequestBus::EventResult(
|
||||
childrenIds,
|
||||
entity->GetId(),
|
||||
&EditorEntityInfoRequests::GetChildren
|
||||
);
|
||||
|
||||
for (AZ::EntityId childId : childrenIds)
|
||||
{
|
||||
AZ::Entity* child = GetEntityById(childId);
|
||||
entityQueue.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The instances differ, so we should add the instance to the instances set,
|
||||
// but only if it's a direct descendant of the root instance!
|
||||
Instance* childInstance = GetAncestorOfInstanceThatIsChildOfRoot(&commonRootEntityOwningInstance, &owningInstance->get());
|
||||
|
||||
if (childInstance != nullptr)
|
||||
{
|
||||
instances.insert(childInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This can only happen if one entity does not share the common root!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store results
|
||||
outEntities.clear();
|
||||
outEntities.resize(entities.size());
|
||||
AZStd::copy(entities.begin(), entities.end(), outEntities.begin());
|
||||
|
||||
outInstances.clear();
|
||||
outInstances.reserve(instances.size());
|
||||
for (Instance* instancePtr : instances)
|
||||
{
|
||||
auto parentInstance = instancePtr->GetParentInstance();
|
||||
|
||||
if (parentInstance.has_value())
|
||||
{
|
||||
auto uniquePtr = parentInstance->get().DetachNestedInstance(instancePtr->GetInstanceAlias());
|
||||
outInstances.push_back(AZStd::move(uniquePtr));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
|
||||
|
||||
using EntityList = AZStd::vector<AZ::Entity*>;
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class Instance;
|
||||
class InstanceEntityMapperInterface;
|
||||
|
||||
class PrefabPublicHandler final
|
||||
: public PrefabPublicInterface
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabPublicHandler, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(PrefabPublicHandler, "{35802943-6B60-430F-9DED-075E3A576A25}", PrefabPublicInterface);
|
||||
|
||||
PrefabPublicHandler();
|
||||
~PrefabPublicHandler();
|
||||
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) override;
|
||||
PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, AZ::Vector3 position) override;
|
||||
|
||||
bool IsInstanceContainerEntity(AZ::EntityId entityId) override;
|
||||
AZ::EntityId GetInstanceContainerEntityId(AZ::EntityId entityId) override;
|
||||
|
||||
private:
|
||||
|
||||
bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, const Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities, AZStd::vector<AZStd::unique_ptr<Instance>>& outInstances) const;
|
||||
|
||||
//! Gets the owning instance of a valid commonRootEntity and the root prefab instance for an invalid commonRootEntity.
|
||||
InstanceOptionalReference GetCommonRootEntityOwningInstance(AZ::EntityId entityId);
|
||||
static Instance* GetParentInstance(Instance* instance);
|
||||
static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant);
|
||||
static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation);
|
||||
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
typedef AZ::Outcome<void, AZStd::string> PrefabOperationResult;
|
||||
|
||||
/*!
|
||||
* PrefabPublicInterface
|
||||
* Interface to expose Prefab functionality directly to UI and Scripting.
|
||||
* Functions will correctly call the Undo/Redo system under the hood.
|
||||
*/
|
||||
class PrefabPublicInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PrefabPublicInterface, "{931AAE9D-C775-4818-9070-A2DA69489CBE}");
|
||||
|
||||
/**
|
||||
* Create a prefab out of the entities provided, at the path provided.
|
||||
* Automatically detects descendants of entities, and discerns between entities and child instances.
|
||||
* @param entityIds The entities that should form the new prefab (along with their descendants).
|
||||
* @param filePath The path for the new prefab file.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
* @param filePath The path to the prefab file to instantiate.
|
||||
* @param parent The entity the prefab should be a child of in the transform hierarchy.
|
||||
* @param position The position in world space the prefab should be instantiated in.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, AZ::Vector3 position) = 0;
|
||||
|
||||
/**
|
||||
* Detects if an entity is the container entity for its owning prefab instance.
|
||||
* @param entityId The entity to query.
|
||||
* @return True if the entity is the container entity for its owning prefab instance, false otherwise.
|
||||
*/
|
||||
virtual bool IsInstanceContainerEntity(AZ::EntityId entityId) = 0;
|
||||
|
||||
/**
|
||||
* Gets the entity id for the instance container of the owning instance.
|
||||
* @param entityId The id of the entity to query.
|
||||
* @return The entity id of the instance container owning the queried entity.
|
||||
*/
|
||||
virtual AZ::EntityId GetInstanceContainerEntityId(AZ::EntityId entityId) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Prefab
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityIdMapper.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceSerializer.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorInfoRemover.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -46,12 +49,14 @@ namespace AzToolsFramework
|
||||
void PrefabSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
Instance::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor::Reflect(context);
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
|
||||
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
{
|
||||
serialize->Class<PrefabSystemComponent, AZ::Component>()
|
||||
;
|
||||
serialize->Class<PrefabSystemComponent, AZ::Component>()->Version(1);
|
||||
}
|
||||
|
||||
AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast<AZ::JsonRegistrationContext*>(context);
|
||||
@@ -62,8 +67,9 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::GetProvidedServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
void PrefabSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("PrefabSystem"));
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
@@ -273,7 +279,6 @@ namespace AzToolsFramework
|
||||
"PrefabSystemComponent::CreateTemplateFromInstance - "
|
||||
"Attempted to create a prefab template from an instance without a source file path. "
|
||||
"Unable to proceed.");
|
||||
|
||||
return InvalidTemplateId;
|
||||
}
|
||||
|
||||
@@ -411,7 +416,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
for (auto linkId : templateToLinkIterator->second)
|
||||
{
|
||||
result = RemoveLinkIdFromTargetTemplate(linkId);
|
||||
result = RemoveLinkFromTargetTemplate(linkId);
|
||||
AZ_Assert(result,
|
||||
"Prefab - PrefabSystemComponent::RemoveTemplate - "
|
||||
"Failed to remove Link with Id '%llu' that depend on the source Template with Id '%llu' on file path '%s'.",
|
||||
@@ -509,6 +514,101 @@ namespace AzToolsFramework
|
||||
return newLinkId;
|
||||
}
|
||||
|
||||
LinkId PrefabSystemComponent::CreateLink(
|
||||
const TemplateId& linkTargetId,
|
||||
const TemplateId& linkSourceId,
|
||||
const InstanceAlias& instanceAlias,
|
||||
const LinkId& linkId)
|
||||
{
|
||||
if (linkTargetId == InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Invalid Link Target Template Id");
|
||||
}
|
||||
|
||||
TemplateReference targetTemplateRef = FindTemplate(linkTargetId);
|
||||
|
||||
if (targetTemplateRef == AZStd::nullopt)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Link Target Template not found");
|
||||
}
|
||||
|
||||
if (linkSourceId == InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Invalid Link Source Template Id");
|
||||
}
|
||||
|
||||
TemplateReference sourceTemplateRef = FindTemplate(linkSourceId);
|
||||
|
||||
if (sourceTemplateRef == AZStd::nullopt)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Link Source Template not found");
|
||||
}
|
||||
|
||||
//use an existing link id if provided
|
||||
LinkId newLinkId = linkId;
|
||||
if (newLinkId == InvalidLinkId)
|
||||
{
|
||||
newLinkId = CreateUniqueLinkId();
|
||||
}
|
||||
|
||||
//setup initial link values
|
||||
Link newLink(newLinkId);
|
||||
newLink.SetTargetTemplateId(linkTargetId);
|
||||
newLink.SetSourceTemplateId(linkSourceId);
|
||||
newLink.SetInstanceName(instanceAlias.c_str());
|
||||
|
||||
//get owner template and add the link
|
||||
Template& targetTemplate = targetTemplateRef->get();
|
||||
|
||||
if (!targetTemplate.AddLink(newLinkId))
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to add link id '%llu' to '%s'", newLinkId, targetTemplate.GetFilePath().c_str());
|
||||
}
|
||||
|
||||
//insert nested instance alias into the template owner dom
|
||||
PrefabDom& targetTemplateDom = targetTemplate.GetPrefabDom();
|
||||
auto memberFound = targetTemplateDom.FindMember(PrefabDomUtils::InstancesName);
|
||||
|
||||
PrefabDomValueReference instancesValue;
|
||||
if (memberFound == targetTemplateDom.MemberEnd())
|
||||
{
|
||||
//add the instance alias to the template dom
|
||||
instancesValue = targetTemplateDom.AddMember(rapidjson::StringRef(PrefabDomUtils::InstancesName),
|
||||
PrefabDomValue(),
|
||||
targetTemplateDom.GetAllocator());
|
||||
|
||||
//when AddMember returns, it returns the object that the member was added to, not the added
|
||||
//member itself, so we need to move instancesValue to the correct position for the next insert
|
||||
memberFound = instancesValue->get().FindMember(PrefabDomUtils::InstancesName);
|
||||
instancesValue = memberFound->value;
|
||||
instancesValue->get().SetObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
instancesValue = memberFound->value;
|
||||
}
|
||||
|
||||
instancesValue->get().AddMember(rapidjson::StringRef(instanceAlias.c_str()), PrefabDomValue(), targetTemplateDom.GetAllocator());
|
||||
|
||||
//setup the link dom
|
||||
Template& sourceTemplate = sourceTemplateRef->get();
|
||||
newLink.GetLinkDom().SetObject();
|
||||
newLink.GetLinkDom().AddMember(rapidjson::StringRef(PrefabDomUtils::SourceName),
|
||||
rapidjson::StringRef(sourceTemplate.GetFilePath().c_str()), newLink.GetLinkDom().GetAllocator());
|
||||
|
||||
//update the target template dom to have the proper values for the source template dom
|
||||
if (!newLink.UpdateTarget())
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to update link with template information");
|
||||
}
|
||||
|
||||
//add the link to the link maps
|
||||
m_linkIdMap.emplace(AZStd::make_pair(newLinkId, AZStd::move(newLink)));
|
||||
m_templateToLinkIdsMap[linkSourceId].emplace(newLinkId);
|
||||
|
||||
return newLinkId;
|
||||
}
|
||||
|
||||
void PrefabSystemComponent::RemoveLink(const LinkId& linkId)
|
||||
{
|
||||
auto findLinkResult = FindLink(linkId);
|
||||
@@ -531,13 +631,15 @@ namespace AzToolsFramework
|
||||
"from TemplateToLinkIdsMap.",
|
||||
linkId, link.GetSourceTemplateId(), link.GetInstanceName().c_str());
|
||||
|
||||
result = RemoveLinkIdFromTargetTemplate(linkId, link);
|
||||
result = RemoveLinkFromTargetTemplate(linkId, link);
|
||||
AZ_Assert(result,
|
||||
"Prefab - PrefabSystemComponent::RemoveLink - "
|
||||
"Failed to remove Link with Id '%llu' for Instance '%s' of source Template with Id '%llu' "
|
||||
"from target Template with Id '%llu'.",
|
||||
linkId, link.GetSourceTemplateId(), link.GetInstanceName().c_str(), link.GetTargetTemplateId());
|
||||
|
||||
m_linkIdMap.erase(linkId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -724,7 +826,7 @@ namespace AzToolsFramework
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool PrefabSystemComponent::RemoveLinkIdFromTargetTemplate(const LinkId& linkId)
|
||||
bool PrefabSystemComponent::RemoveLinkFromTargetTemplate(const LinkId& linkId)
|
||||
{
|
||||
auto findLinkResult = FindLink(linkId);
|
||||
if (!findLinkResult.has_value())
|
||||
@@ -733,10 +835,10 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
Link& link = findLinkResult->get();
|
||||
return RemoveLinkIdFromTargetTemplate(linkId, link);
|
||||
return RemoveLinkFromTargetTemplate(linkId, link);
|
||||
}
|
||||
|
||||
bool PrefabSystemComponent::RemoveLinkIdFromTargetTemplate(const LinkId& linkId, const Link& link)
|
||||
bool PrefabSystemComponent::RemoveLinkFromTargetTemplate(const LinkId& linkId, const Link& link)
|
||||
{
|
||||
TemplateId targetTemplateId = link.GetTargetTemplateId();
|
||||
|
||||
@@ -745,6 +847,17 @@ namespace AzToolsFramework
|
||||
if (templateIterator != m_templateIdMap.end())
|
||||
{
|
||||
removed = templateIterator->second.RemoveLink(linkId);
|
||||
|
||||
//remove link
|
||||
PrefabDomValueReference templateInstancesRef = templateIterator->second.GetInstancesValue();
|
||||
if (templateInstancesRef == AZStd::nullopt)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to get template reference");
|
||||
return false;
|
||||
}
|
||||
|
||||
removed = templateInstancesRef->get().RemoveMember(link.GetInstanceName().c_str())
|
||||
? removed : false;
|
||||
}
|
||||
|
||||
return removed;
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#include <AzToolsFramework/Prefab/Link/Link.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoader.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Template/Template.h>
|
||||
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class Entity;
|
||||
@@ -123,6 +123,21 @@ namespace AzToolsFramework
|
||||
PrefabDomValue::MemberIterator& instanceIterator,
|
||||
InstanceOptionalReference instance) override;
|
||||
|
||||
/**
|
||||
* Create a new Link with Prefab System Component and create a unique id for it.
|
||||
* @param linkTargetId The Id of Template which owns this Link.
|
||||
* @param linkSourceId The Id of Template whose instance is referred by targetTemplate.
|
||||
* @param instanceAlias The alias of the instance that should be included in link.
|
||||
* @param linkId The id of the link. If invalid, create a new link id. If valid, use to recreate
|
||||
* a prior link.
|
||||
* @return A unique id for the new Link.
|
||||
*/
|
||||
LinkId CreateLink(
|
||||
const TemplateId& linkTargetId,
|
||||
const TemplateId& linkSourceId,
|
||||
const InstanceAlias& instanceAlias,
|
||||
const LinkId& linkId = InvalidLinkId) override;
|
||||
|
||||
/**
|
||||
* Remove the Link associated with the given id from Prefab System Component.
|
||||
* @param linkId A unique id of a Link.
|
||||
@@ -272,13 +287,13 @@ namespace AzToolsFramework
|
||||
* Remove given Link Id from the Link's target Template.
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool RemoveLinkIdFromTargetTemplate(const LinkId& linkId);
|
||||
bool RemoveLinkFromTargetTemplate(const LinkId& linkId);
|
||||
|
||||
/**
|
||||
* Given Link and its Id, remove the Id from the Link's target Template..
|
||||
* Given Link and its Id, remove the link from the target Template..
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool RemoveLinkIdFromTargetTemplate(const LinkId& linkId, const Link& link);
|
||||
bool RemoveLinkFromTargetTemplate(const LinkId& linkId, const Link& link);
|
||||
|
||||
// A container for mapping Templates to the Links they may propagate changes to.
|
||||
AZStd::unordered_map<TemplateId, AZStd::unordered_set<LinkId>> m_templateToLinkIdsMap;
|
||||
@@ -307,6 +322,9 @@ namespace AzToolsFramework
|
||||
// Used for loading/saving Prefab Template files.
|
||||
PrefabLoader m_prefabLoader;
|
||||
|
||||
// Handler the public Prefab API used by UI and scripting
|
||||
PrefabPublicHandler m_prefabPublicHandler;
|
||||
|
||||
// Used for updating Instances of Prefab Template.
|
||||
InstanceUpdateExecutor m_instanceUpdateExecutor;
|
||||
|
||||
|
||||
+5
@@ -40,6 +40,11 @@ namespace AzToolsFramework
|
||||
|
||||
virtual LinkId AddLink(const TemplateId& sourceTemplateId, const TemplateId& targetTemplateId,
|
||||
PrefabDomValue::MemberIterator& instanceIterator, InstanceOptionalReference instance) = 0;
|
||||
|
||||
//creates a new Link
|
||||
virtual LinkId CreateLink(const TemplateId& linkTargetId, const TemplateId& linkSourceId,
|
||||
const InstanceAlias& instanceAlias, const LinkId& linkId = InvalidLinkId) = 0;
|
||||
|
||||
virtual void RemoveLink(const LinkId& linkId) = 0;
|
||||
|
||||
virtual TemplateId GetTemplateIdFromFilePath(AZStd::string_view filePath) const = 0;
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
|
||||
#include <Prefab/PrefabUndo.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
PrefabUndoBase::PrefabUndoBase(const AZStd::string& undoOperationName)
|
||||
: UndoSystem::URSequencePoint(undoOperationName)
|
||||
, m_changed(true)
|
||||
, m_templateId(InvalidTemplateId)
|
||||
{
|
||||
m_instanceToTemplateInterface = AZ::Interface<InstanceToTemplateInterface>::Get();
|
||||
AZ_Assert(m_instanceToTemplateInterface, "Failed to grab instance to template interface");
|
||||
}
|
||||
|
||||
|
||||
//PrefabInstanceUndo
|
||||
PrefabUndoInstance::PrefabUndoInstance(const AZStd::string& undoOperationName)
|
||||
: PrefabUndoBase(undoOperationName)
|
||||
{
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::Capture(
|
||||
PrefabDom& initialState,
|
||||
PrefabDom& endState,
|
||||
const TemplateId& templateId)
|
||||
{
|
||||
m_templateId = templateId;
|
||||
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_redoPatch, initialState, endState);
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_undoPatch, endState, initialState);
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::Undo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_undoPatch, m_templateId);
|
||||
}
|
||||
|
||||
void PrefabUndoInstance::Redo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchTemplate(m_redoPatch, m_templateId);
|
||||
}
|
||||
|
||||
|
||||
//PrefabEntityUpdateUndo
|
||||
PrefabUndoEntityUpdate::PrefabUndoEntityUpdate(const AZStd::string& undoOperationName)
|
||||
: PrefabUndoBase(undoOperationName)
|
||||
{
|
||||
m_instanceEntityMapperInterface = AZ::Interface<InstanceEntityMapperInterface>::Get();
|
||||
AZ_Assert(m_instanceEntityMapperInterface, "Failed to grab instance entity mapper interface");
|
||||
}
|
||||
|
||||
void PrefabUndoEntityUpdate::Capture(
|
||||
PrefabDom& initialState,
|
||||
PrefabDom& endState,
|
||||
const AZ::EntityId& entityId)
|
||||
{
|
||||
//get the entity alias for future undo/redo
|
||||
InstanceOptionalReference instanceOptionalReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
|
||||
AZ_Error("Prefab", instanceOptionalReference,
|
||||
"Failed to find an owning instance for the entity with id %llu.", static_cast<AZ::u64>(entityId));
|
||||
Instance& instance = instanceOptionalReference->get();
|
||||
m_templateId = instance.GetTemplateId();
|
||||
m_entityAlias = (instance.GetEntityAlias(entityId)).value();
|
||||
|
||||
//generate undo/redo patches
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_redoPatch, initialState, endState);
|
||||
m_instanceToTemplateInterface->GeneratePatch(m_undoPatch, endState, initialState);
|
||||
}
|
||||
|
||||
void PrefabUndoEntityUpdate::Undo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchEntityInTemplate(m_undoPatch, m_entityAlias, m_templateId);
|
||||
}
|
||||
|
||||
void PrefabUndoEntityUpdate::Redo()
|
||||
{
|
||||
m_instanceToTemplateInterface->PatchEntityInTemplate(m_redoPatch, m_entityAlias, m_templateId);
|
||||
}
|
||||
|
||||
//PrefabInstanceLinkUndo
|
||||
PrefabUndoInstanceLink::PrefabUndoInstanceLink(const AZStd::string& undoOperationName)
|
||||
: PrefabUndoBase(undoOperationName)
|
||||
, m_targetId(InvalidTemplateId)
|
||||
, m_sourceId(InvalidTemplateId)
|
||||
, m_instanceAlias("")
|
||||
, m_linkId(InvalidLinkId)
|
||||
, m_link(Link())
|
||||
, m_linkStatus(LinkStatus::LINKSTATUS)
|
||||
{
|
||||
m_prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
AZ_Assert(m_instanceToTemplateInterface, "Failed to grab interface");
|
||||
}
|
||||
|
||||
void PrefabUndoInstanceLink::Capture(
|
||||
const TemplateId& targetId,
|
||||
const TemplateId& sourceId,
|
||||
const InstanceAlias& instanceAlias,
|
||||
const LinkId& linkId,
|
||||
const Link& link)
|
||||
{
|
||||
m_targetId = targetId;
|
||||
m_sourceId = sourceId;
|
||||
m_instanceAlias = instanceAlias;
|
||||
m_linkId = linkId;
|
||||
m_link = link;
|
||||
|
||||
//if linkId is invalid, set as ADD
|
||||
if (m_linkId == InvalidLinkId)
|
||||
{
|
||||
m_linkStatus = LinkStatus::ADD;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_linkStatus = LinkStatus::REMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabUndoInstanceLink::Undo()
|
||||
{
|
||||
switch (m_linkStatus)
|
||||
{
|
||||
case LinkStatus::ADD:
|
||||
RemoveLink();
|
||||
break;
|
||||
|
||||
case LinkStatus::REMOVE:
|
||||
AddLink();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(m_targetId);
|
||||
}
|
||||
|
||||
void PrefabUndoInstanceLink::Redo()
|
||||
{
|
||||
switch (m_linkStatus)
|
||||
{
|
||||
case LinkStatus::ADD:
|
||||
AddLink();
|
||||
break;
|
||||
|
||||
case LinkStatus::REMOVE:
|
||||
RemoveLink();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(m_targetId);
|
||||
}
|
||||
|
||||
void PrefabUndoInstanceLink::AddLink()
|
||||
{
|
||||
m_linkId = m_prefabSystemComponentInterface->CreateLink(m_targetId, m_sourceId, m_instanceAlias, m_linkId);
|
||||
|
||||
//if data already exists, repopulate
|
||||
if (m_linkStatus == LinkStatus::REMOVE)
|
||||
{
|
||||
LinkReference link = m_prefabSystemComponentInterface->FindLink(m_linkId);
|
||||
link = m_link;
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabUndoInstanceLink::RemoveLink()
|
||||
{
|
||||
m_prefabSystemComponentInterface->RemoveLink(m_linkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <AzToolsFramework/Undo/UndoSystem.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
|
||||
|
||||
//for link undo
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
||||
#include <AzToolsFramework/Prefab/Link/Link.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
class PrefabUndoBase
|
||||
: public UndoSystem::URSequencePoint
|
||||
{
|
||||
public:
|
||||
explicit PrefabUndoBase(const AZStd::string& undoOperationName);
|
||||
|
||||
bool Changed() const override { return m_changed; }
|
||||
|
||||
protected:
|
||||
TemplateId m_templateId;
|
||||
|
||||
PrefabDom m_redoPatch;
|
||||
PrefabDom m_undoPatch;
|
||||
|
||||
InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr;
|
||||
|
||||
bool m_changed;
|
||||
};
|
||||
|
||||
//! handles the addition and removal of entities from instances
|
||||
class PrefabUndoInstance
|
||||
: public PrefabUndoBase
|
||||
{
|
||||
public:
|
||||
explicit PrefabUndoInstance(const AZStd::string& undoOperationName);
|
||||
|
||||
void Capture(
|
||||
PrefabDom& initialState,
|
||||
PrefabDom& endState,
|
||||
const TemplateId& templateId);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
};
|
||||
|
||||
//! handles entity updates, such as when the values on an entity change
|
||||
class PrefabUndoEntityUpdate
|
||||
: public PrefabUndoBase
|
||||
{
|
||||
public:
|
||||
explicit PrefabUndoEntityUpdate(const AZStd::string& undoOperationName);
|
||||
|
||||
void Capture(
|
||||
PrefabDom& initialState,
|
||||
PrefabDom& endState,
|
||||
const AZ::EntityId& entity);
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr;
|
||||
EntityAlias m_entityAlias;
|
||||
};
|
||||
|
||||
//! handles link changes on instances
|
||||
class PrefabUndoInstanceLink
|
||||
: public PrefabUndoBase
|
||||
{
|
||||
public:
|
||||
enum class LinkStatus
|
||||
{
|
||||
ADD,
|
||||
REMOVE,
|
||||
UPDATE,
|
||||
LINKSTATUS
|
||||
};
|
||||
|
||||
explicit PrefabUndoInstanceLink(const AZStd::string& undoOperationName);
|
||||
|
||||
//capture for add/remove
|
||||
void Capture(
|
||||
const TemplateId& targetId,
|
||||
const TemplateId& sourceId,
|
||||
const InstanceAlias& instanceAlias,
|
||||
const LinkId& linkId = InvalidLinkId,
|
||||
const Link& link = Link());
|
||||
|
||||
void Undo() override;
|
||||
void Redo() override;
|
||||
|
||||
private:
|
||||
//used for special cases of add/delete
|
||||
void AddLink();
|
||||
|
||||
void RemoveLink();
|
||||
|
||||
TemplateId m_targetId;
|
||||
TemplateId m_sourceId;
|
||||
InstanceAlias m_instanceAlias;
|
||||
|
||||
LinkId m_linkId;
|
||||
Link m_link; //data for delete/update
|
||||
LinkStatus m_linkStatus;
|
||||
|
||||
PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ComponentRequirementsValidator.h>
|
||||
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
void ComponentRequirementsValidator::SetPlatformTags(AZ::PlatformTagSet platformTags)
|
||||
{
|
||||
m_platformTags = AZStd::move(platformTags);
|
||||
}
|
||||
|
||||
|
||||
void ComponentRequirementsValidator::SetEntities(const AZStd::vector<AZ::Entity*>& entities)
|
||||
{
|
||||
m_immutableEntities.clear();
|
||||
m_immutableEntities.assign(entities.cbegin(), entities.cend());
|
||||
}
|
||||
|
||||
ComponentRequirementsValidator::ValidationResult ComponentRequirementsValidator::Validate(
|
||||
const AZ::Component* component)
|
||||
{
|
||||
AZ::ComponentValidationResult result = component->ValidateComponentRequirements(m_immutableEntities, m_platformTags);
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
// Try to cast to GenericComponentWrapper, and if we can, get the internal template.
|
||||
const char* componentName = component->RTTI_GetTypeName();
|
||||
const auto* asEditorComponent = azrtti_cast<const Components::EditorComponentBase*>(component);
|
||||
const Components::GenericComponentWrapper* wrapper = azrtti_cast<const Components::GenericComponentWrapper*>(asEditorComponent);
|
||||
if (wrapper && wrapper->GetTemplate())
|
||||
{
|
||||
componentName = wrapper->GetTemplate()->RTTI_GetTypeName();
|
||||
}
|
||||
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Editor Component '%s' could not pass validation due to the error - %s",
|
||||
componentName,
|
||||
result.GetError().c_str())
|
||||
);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/ComponentExport.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class ComponentRequirementsValidator
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ComponentRequirementsValidator, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::ComponentRequirementsValidator, "{1E9CD55D-FFEA-4E71-A316-731E25E6C981}");
|
||||
|
||||
virtual ~ComponentRequirementsValidator() = default;
|
||||
|
||||
void SetPlatformTags(AZ::PlatformTagSet platformTags);
|
||||
void SetEntities(const AZStd::vector<AZ::Entity*>& entities);
|
||||
|
||||
using ValidationResult = AZ::Outcome<void, AZStd::string>;
|
||||
ValidationResult Validate(const AZ::Component* component);
|
||||
|
||||
private:
|
||||
AZ::ImmutableEntityVector m_immutableEntities;
|
||||
AZ::PlatformTagSet m_platformTags;
|
||||
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+632
@@ -0,0 +1,632 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentExport.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorInfoRemover.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorOnlyEntityComponentBus.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
EditorInfoRemover::~EditorInfoRemover()
|
||||
{
|
||||
for (auto* handler : m_editorOnlyEntityHandlerCandidates)
|
||||
{
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorInfoRemover::Process(PrefabProcessorContext& prefabProcessorContext)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (!serializeContext)
|
||||
{
|
||||
AZ_Assert(serializeContext, "Failed to retrieve serialize context.");
|
||||
return;
|
||||
}
|
||||
|
||||
prefabProcessorContext.ListPrefabs([this, &serializeContext, &prefabProcessorContext](AZStd::string_view prefabName, PrefabDom& prefab)
|
||||
{
|
||||
auto result = RemoveEditorInfo(prefab, serializeContext, prefabProcessorContext);
|
||||
if (!result)
|
||||
{
|
||||
AZ_Assert(false,
|
||||
"Converting to runtime Prefab '%.*s' failed, Error: %s .",
|
||||
AZ_STRING_ARG(prefabName),
|
||||
result.GetError().c_str());
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EditorInfoRemover::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
|
||||
{
|
||||
serializeContext->Class<EditorInfoRemover, PrefabProcessor>()->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Entity*> EditorInfoRemover::GetEntitiesFromInstance(AZStd::unique_ptr<Instance>& instance)
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> result;
|
||||
|
||||
instance->GetNestedEntities(
|
||||
[&result](const AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
{
|
||||
result.emplace_back(entity.get());
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EditorInfoRemover::SetEditorOnlyEntityHandlerFromCandidates(const EntityList& entities)
|
||||
{
|
||||
ClearEditorOnlyEntityIds();
|
||||
m_editorOnlyEntityHandler = nullptr;
|
||||
for (auto& handlerCandidate : m_editorOnlyEntityHandlerCandidates)
|
||||
{
|
||||
// See if this handler can handle at least one of the entities.
|
||||
for (auto entity : entities)
|
||||
{
|
||||
if (handlerCandidate->IsEntityUniquelyForThisHandler(entity))
|
||||
{
|
||||
m_editorOnlyEntityHandler = handlerCandidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HasValidEditorOnlyHandler())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorInfoRemover::HasValidEditorOnlyHandler() const
|
||||
{
|
||||
return m_editorOnlyEntityHandler != nullptr;
|
||||
}
|
||||
|
||||
void EditorInfoRemover::ClearEditorOnlyEntityIds()
|
||||
{
|
||||
m_editorOnlyEntityIds.clear();
|
||||
}
|
||||
|
||||
void EditorInfoRemover::AddEntityIdIfEditorOnly(AZ::Entity* entity)
|
||||
{
|
||||
bool isEditorOnly = false;
|
||||
EditorOnlyEntityComponentRequestBus::EventResult(isEditorOnly, entity->GetId(), &EditorOnlyEntityComponentRequests::IsEditorOnlyEntity);
|
||||
if (isEditorOnly && HasValidEditorOnlyHandler())
|
||||
{
|
||||
m_editorOnlyEntityHandler->AddEditorOnlyEntity(entity, m_editorOnlyEntityIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify and remove any entities marked as editor-only.
|
||||
* If any are discovered, adjust descendants' transforms to retain spatial relationships.
|
||||
* Note we cannot use EBuses for this purpose, since we're crunching data, and can't assume any entities are active.
|
||||
*/
|
||||
EditorInfoRemover::RemoveEditorOnlyEntitiesResult EditorInfoRemover::RemoveEditorOnlyEntities(EntityList& entities)
|
||||
{
|
||||
if (HasValidEditorOnlyHandler())
|
||||
{
|
||||
const auto handlerResult =
|
||||
m_editorOnlyEntityHandler->HandleEditorOnlyEntities(entities, m_editorOnlyEntityIds, *m_serializeContext);
|
||||
if (!handlerResult)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Error occurred when handle editor-only entities. Error: %s",
|
||||
handlerResult.GetError().c_str())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove editor-only entities from the given entity list.
|
||||
AZStd::erase_if(
|
||||
entities,
|
||||
[this](auto entity)
|
||||
{
|
||||
return m_editorOnlyEntityIds.find(entity->GetId()) != m_editorOnlyEntityIds.end();
|
||||
}
|
||||
);
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
EditorInfoRemover::ExportEntityResult EditorInfoRemover::ExportEntity(AZ::Entity* sourceEntity, PrefabProcessorContext& context)
|
||||
{
|
||||
// For export, components can assume they're initialized, but not activated.
|
||||
if (sourceEntity->GetState() == AZ::Entity::State::Constructed)
|
||||
{
|
||||
sourceEntity->Init();
|
||||
}
|
||||
|
||||
AZ::Entity* exportEntity = aznew AZ::Entity(sourceEntity->GetId(), sourceEntity->GetName().c_str());
|
||||
exportEntity->SetRuntimeActiveByDefault(sourceEntity->IsRuntimeActiveByDefault());
|
||||
|
||||
AddEntityIdIfEditorOnly(sourceEntity);
|
||||
|
||||
const AZ::Entity::ComponentArrayType& editorComponents = sourceEntity->GetComponents();
|
||||
EntityList exportedEntities;
|
||||
for (AZ::Component* component : editorComponents)
|
||||
{
|
||||
auto result = ExportComponent(component, context, sourceEntity, exportEntity);
|
||||
if (!result)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - export component '%s' failed. Error: %s",
|
||||
exportEntity->GetName().c_str(),
|
||||
exportEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName(),
|
||||
result.GetError().c_str())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-sort prior to exporting so it isn't required at instantiation time.
|
||||
const auto sortResult = exportEntity->EvaluateDependenciesGetDetails();
|
||||
/* :CBR_TODO: verify AZ::Entity::DependencySortResult::HasIncompatibleServices and
|
||||
AZ::Entity::DependencySortResult::DescriptorNotRegistered are still covered here*/
|
||||
if (!sortResult.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - dependency evaluation failed. Error: %s",
|
||||
exportEntity->GetName().c_str(),
|
||||
exportEntity->GetId().ToString().c_str(),
|
||||
sortResult.GetError().m_message.c_str()));
|
||||
}
|
||||
|
||||
return AZ::Success(exportEntity);
|
||||
}
|
||||
|
||||
bool EditorInfoRemover::ReadComponentAttribute(
|
||||
AZ::Component* component,
|
||||
AZ::Edit::Attribute* attribute,
|
||||
AZStd::vector<AZ::Crc32>& attributeTags)
|
||||
{
|
||||
attributeTags.clear();
|
||||
PropertyAttributeReader reader(component, attribute);
|
||||
return reader.Read<AZStd::vector<AZ::Crc32>>(attributeTags);
|
||||
}
|
||||
|
||||
EditorInfoRemover::ShouldExportResult EditorInfoRemover::ShouldExportComponent(
|
||||
AZ::Component* component,
|
||||
PrefabProcessorContext& context) const
|
||||
{
|
||||
const AZ::SerializeContext::ClassData* classData = m_serializeContext->FindClassData(component->RTTI_GetType());
|
||||
if (!classData || !classData->m_editData)
|
||||
{
|
||||
return AZ::Success(true);
|
||||
}
|
||||
|
||||
const AZ::Edit::ElementData* editorDataElement = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
|
||||
if (!editorDataElement)
|
||||
{
|
||||
return AZ::Success(true);
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Crc32> attributeTags;
|
||||
const auto& platformTags = context.GetPlatformTags();
|
||||
|
||||
// If the component has declared the 'ExportIfAllPlatforms' attribute, skip export if any of the flags are not present.
|
||||
AZ::Edit::Attribute* allTagsAttribute = editorDataElement->FindAttribute(AZ::Edit::Attributes::ExportIfAllPlatformTags);
|
||||
if (allTagsAttribute)
|
||||
{
|
||||
if (!ReadComponentAttribute(component, allTagsAttribute, attributeTags))
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string("'ExportIfAllPlatforms' attribute is not bound to the correct return type. Expects AZStd::vector<AZ::Crc32>.")
|
||||
);
|
||||
}
|
||||
|
||||
for (AZ::Crc32 tag : attributeTags)
|
||||
{
|
||||
if (platformTags.find(tag) == platformTags.end())
|
||||
{
|
||||
// Export platform tags does not contain all tags specified in 'ExportIfAllPlatforms' attribute.
|
||||
return AZ::Success(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the component has declared the 'ExportIfAnyPlatforms' attribute, skip export if none of the flags are present.
|
||||
AZ::Edit::Attribute* anyTagsAttribute = editorDataElement->FindAttribute(AZ::Edit::Attributes::ExportIfAnyPlatformTags);
|
||||
if (anyTagsAttribute)
|
||||
{
|
||||
if (!ReadComponentAttribute(component, anyTagsAttribute, attributeTags))
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string("'ExportIfAnyPlatforms' attribute is not bound to the correct return type. Expects AZStd::vector<AZ::Crc32>.")
|
||||
);
|
||||
}
|
||||
|
||||
bool anyFlagSet = false;
|
||||
for (AZ::Crc32 tag : attributeTags)
|
||||
{
|
||||
if (platformTags.find(tag) != platformTags.end())
|
||||
{
|
||||
anyFlagSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!anyFlagSet)
|
||||
{
|
||||
// None of the flags in 'ExportIfAnyPlatforms' was present in the export platform tags.
|
||||
return AZ::Success(false);
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Success(true);
|
||||
}
|
||||
|
||||
EditorInfoRemover::ResolveExportedComponentResult EditorInfoRemover::ResolveExportedComponent(
|
||||
AZ::ExportedComponent& component,
|
||||
PrefabProcessorContext& prefabProcessorContext)
|
||||
{
|
||||
AZ::Component* inputComponent = component.m_component;
|
||||
if (!inputComponent)
|
||||
{
|
||||
return AZ::Success(component);
|
||||
}
|
||||
|
||||
// Don't export the component if it has unmet platform tag requirements.
|
||||
ShouldExportResult shouldExportResult = ShouldExportComponent(inputComponent, prefabProcessorContext);
|
||||
if (!shouldExportResult)
|
||||
{
|
||||
return AZ::Failure(shouldExportResult.TakeError());
|
||||
}
|
||||
|
||||
if (!shouldExportResult.GetValue())
|
||||
{
|
||||
// If the platform tag requirements aren't met, return a null component that's been flagged as exported,
|
||||
// so that we know not to try and process it any further.
|
||||
return AZ::Success(AZ::ExportedComponent());
|
||||
}
|
||||
|
||||
// Determine if the component has a custom export callback, and invoke it if so.
|
||||
// If there's no custom export callback, just return what we were given.
|
||||
const AZ::SerializeContext::ClassData* classData = m_serializeContext->FindClassData(inputComponent->RTTI_GetType());
|
||||
if (!classData || !classData->m_editData)
|
||||
{
|
||||
return AZ::Success(component);
|
||||
}
|
||||
const AZ::Edit::ElementData* editorDataElement = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
|
||||
if (!editorDataElement)
|
||||
{
|
||||
return AZ::Success(component);
|
||||
}
|
||||
AZ::Edit::Attribute* exportCallbackAttribute = editorDataElement->FindAttribute(AZ::Edit::Attributes::RuntimeExportCallback);
|
||||
if (!exportCallbackAttribute)
|
||||
{
|
||||
return AZ::Success(component);
|
||||
}
|
||||
|
||||
PropertyAttributeReader reader(inputComponent, exportCallbackAttribute);
|
||||
AZ::ExportedComponent exportedComponent;
|
||||
if (reader.Read<AZ::ExportedComponent>(exportedComponent, inputComponent, prefabProcessorContext.GetPlatformTags()))
|
||||
{
|
||||
// If the callback handled the export and provided a different component instance, continue to resolve recursively.
|
||||
if (exportedComponent.m_componentExportHandled && (exportedComponent.m_component != inputComponent))
|
||||
{
|
||||
return ResolveExportedComponent(exportedComponent, prefabProcessorContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// It provided the *same* component back (or didn't handle the export at all), so we're done.
|
||||
return AZ::Success(exportedComponent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Bound 'CustomExportCallback' does not have the required return type/signature."));
|
||||
}
|
||||
}
|
||||
|
||||
EditorInfoRemover::BuildGameEntityResult EditorInfoRemover::BuildGameEntity(
|
||||
AzToolsFramework::Components::EditorComponentBase* editorComponent,
|
||||
AZ::Entity* sourceEntity,
|
||||
AZ::Entity* exportEntity)
|
||||
{
|
||||
const size_t oldComponentCount = exportEntity->GetComponents().size();
|
||||
editorComponent->BuildGameEntity(exportEntity);
|
||||
AZ::ComponentId newID = editorComponent->GetId();
|
||||
for (auto i = oldComponentCount; i < exportEntity->GetComponents().size(); ++i)
|
||||
{
|
||||
AZ::Component* exportComponent = exportEntity->GetComponents()[i];
|
||||
|
||||
// Verify that the result of BuildGameEntity() wasn't an editor component.
|
||||
auto* exportAsEditorComponent = azrtti_cast<Components::EditorComponentBase*>(exportComponent);
|
||||
if (exportAsEditorComponent)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' exported an editor component from BuildGameEntity() for runtime use.",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
editorComponent->RTTI_GetType().ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
else if (editorComponent->GetId() == AZ::InvalidComponentId)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' doesn't have a valid component Id.",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
editorComponent->RTTI_GetType().ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
|
||||
exportComponent->SetId(newID++);
|
||||
// The first time round set the new component the same as the editor one. This will change in a separate ticket
|
||||
// when 8 bit runtime Ids are implemented.
|
||||
// Make sure the newID isn't already on the source Entity. If it is increment the ID and try again.
|
||||
while (sourceEntity->FindComponent(newID))
|
||||
{
|
||||
++newID;
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
EditorInfoRemover::ExportComponentResult EditorInfoRemover::ExportComponent(
|
||||
AZ::Component* component,
|
||||
PrefabProcessorContext& prefabProcessorContext,
|
||||
AZ::Entity* sourceEntity,
|
||||
AZ::Entity* exportEntity)
|
||||
{
|
||||
auto validationResult = m_componentRequirementsValidator.Validate(component);
|
||||
if (!validationResult.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - validation of component '%s' failed: %s",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName(),
|
||||
validationResult.GetError().c_str())
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
AZ::ExportedComponent exportComponent(component, false, false);
|
||||
auto exportResult = ResolveExportedComponent(
|
||||
exportComponent, prefabProcessorContext);
|
||||
if (!exportResult)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' could not be exported due to export attributes: %s.",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName(),
|
||||
exportResult.GetError().c_str()));
|
||||
}
|
||||
|
||||
AZ::ExportedComponent& exportedComponent = exportResult.GetValue();
|
||||
|
||||
// If ResolveExportedComponent didn't handle the component export, then we'll do the following:
|
||||
// - For editor components, fall back on the legacy BuildGameEntity() path for handling component exports.
|
||||
// - For runtime components, provide a default behavior of "clone / add" to export the component.
|
||||
if (!exportedComponent.m_componentExportHandled)
|
||||
{
|
||||
auto* asEditorComponent = azrtti_cast<Components::EditorComponentBase*>(component);
|
||||
// Editor components: Try to use BuildGameEntity()
|
||||
if (asEditorComponent) // BEGIN BuildGameEntity compatibility path for editor components not using the newer RuntimeExportCallback functionality.
|
||||
{
|
||||
auto buildGameEntityResult = BuildGameEntity(asEditorComponent, sourceEntity, exportEntity);
|
||||
if (!buildGameEntityResult.IsSuccess())
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' to build game entity failed. Error: %s.",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName(),
|
||||
buildGameEntityResult.GetError().c_str()));
|
||||
}
|
||||
|
||||
// Since this is an editor component, we very specifically do *not* want to clone and add it as a runtime
|
||||
// component by default, so regardless of whether or not the BuildGameEntity() call did anything,
|
||||
// null out the editor component and mark it handled.
|
||||
return AZ::Success();
|
||||
|
||||
} // END BuildGameEntity compatibility path for editor components not using the newer RuntimeExportCallback functionality.
|
||||
else
|
||||
{
|
||||
// Nothing else has handled the component export, so fall back on the default behavior
|
||||
// for runtime components: clone and add the runtime component that already exists.
|
||||
exportedComponent = AZ::ExportedComponent(component, false);
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, either ResolveExportedComponent or the default logic above should have set the component export
|
||||
// as being handled. If not, there is likely a new code path that requires a default export behavior.
|
||||
AZ_Assert(exportedComponent.m_componentExportHandled,
|
||||
"Entity '%s' %s - component '%s' had no export handlers and could not be added to the entity.",
|
||||
exportEntity->GetName().c_str(),
|
||||
exportEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName());
|
||||
|
||||
// If we have an exported component, we add it to the exported entity.
|
||||
// If we don't (m_component == nullptr), this component chose not to be exported, so we skip it.
|
||||
if (exportedComponent.m_componentExportHandled && exportedComponent.m_component)
|
||||
{
|
||||
AZ::Component* runtimeComponent = exportedComponent.m_component;
|
||||
|
||||
// Verify that we aren't trying to export an editor component.
|
||||
auto* exportAsEditorComponent = azrtti_cast<Components::EditorComponentBase*>(runtimeComponent);
|
||||
if (exportAsEditorComponent)
|
||||
{
|
||||
auto* asEditorComponent =
|
||||
azrtti_cast<Components::EditorComponentBase*>(component);
|
||||
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' is trying to export an Editor component for runtime use.",
|
||||
sourceEntity->GetName().c_str(),
|
||||
sourceEntity->GetId().ToString().c_str(),
|
||||
asEditorComponent->RTTI_GetType().ToString<AZStd::string>().c_str()));
|
||||
}
|
||||
|
||||
// If the final component is not owned by us, make our own copy.
|
||||
if (!exportedComponent.m_deleteAfterExport)
|
||||
{
|
||||
runtimeComponent = m_serializeContext->CloneObject(runtimeComponent);
|
||||
}
|
||||
|
||||
// Synchronize to source component Id, and add to the export entity.
|
||||
runtimeComponent->SetId(component->GetId());
|
||||
|
||||
if (!exportEntity->AddComponent(runtimeComponent))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - component '%s' could not be added to this entity.",
|
||||
exportEntity->GetName().c_str(),
|
||||
exportEntity->GetId().ToString().c_str(),
|
||||
runtimeComponent->RTTI_GetTypeName())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
EditorInfoRemover::RemoveEditorInfoResult EditorInfoRemover::RemoveEditorInfo(
|
||||
PrefabDom& prefab,
|
||||
AZ::SerializeContext* serializeContext,
|
||||
PrefabProcessorContext& prefabProcessorContext)
|
||||
{
|
||||
if (!serializeContext)
|
||||
{
|
||||
return AZ::Failure(AZStd::string("Invalid Serialize Context used."));
|
||||
}
|
||||
m_serializeContext = serializeContext;
|
||||
|
||||
m_componentRequirementsValidator.SetPlatformTags(prefabProcessorContext.GetPlatformTags());
|
||||
|
||||
// convert Prefab DOM into Prefab Instance.
|
||||
AZStd::unique_ptr<Instance> instance(aznew Instance());
|
||||
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab, false))
|
||||
{
|
||||
PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
|
||||
|
||||
AZStd::string errorMessage("Failed to Load Prefab Instance from given Prefab Dom during Removal of Editor Info.");
|
||||
if (sourceReference.has_value() &&
|
||||
sourceReference->get().IsString() &&
|
||||
sourceReference->get().GetStringLength() != 0)
|
||||
{
|
||||
AZStd::string_view source(sourceReference->get().GetString(), sourceReference->get().GetStringLength());
|
||||
errorMessage += AZStd::string::format("Prefab Source: %.*s", AZ_STRING_ARG(source));
|
||||
}
|
||||
|
||||
return AZ::Failure(errorMessage);
|
||||
}
|
||||
|
||||
// grab all nested entities from the Instance as source entities.
|
||||
EntityList sourceEntities = GetEntitiesFromInstance(instance);
|
||||
EntityList exportEntities;
|
||||
|
||||
// prepare for validation of component requirements.
|
||||
m_componentRequirementsValidator.SetEntities(sourceEntities);
|
||||
|
||||
// find valid editor-only entity handler for removing editor-only entities later.
|
||||
SetEditorOnlyEntityHandlerFromCandidates(sourceEntities);
|
||||
|
||||
// export entities.
|
||||
for (AZ::Entity* entity : sourceEntities)
|
||||
{
|
||||
const auto result = ExportEntity(entity, prefabProcessorContext);
|
||||
if (!result)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - export entity failed. Error: %s",
|
||||
entity->GetName().c_str(),
|
||||
entity->GetId().ToString().c_str(),
|
||||
result.GetError().c_str())
|
||||
);
|
||||
}
|
||||
|
||||
exportEntities.emplace_back(result.GetValue());
|
||||
}
|
||||
|
||||
// remove editor-only entities with valid editor-only entity handler.
|
||||
const auto removeEditorOnlyEntitiesResult = RemoveEditorOnlyEntities(exportEntities);
|
||||
if (!removeEditorOnlyEntitiesResult)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Remove Editor-Only Entities failed. Error: '%s'",
|
||||
removeEditorOnlyEntitiesResult.GetError().c_str())
|
||||
);
|
||||
}
|
||||
|
||||
// validate component requirements for exported entities.
|
||||
m_componentRequirementsValidator.SetEntities(exportEntities);
|
||||
for (AZ::Entity* exportEntity : exportEntities)
|
||||
{
|
||||
const AZ::Entity::ComponentArrayType& gameComponents = exportEntity->GetComponents();
|
||||
for (const AZ::Component* component : gameComponents)
|
||||
{
|
||||
const auto result = m_componentRequirementsValidator.Validate(component);
|
||||
if (!result)
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Entity '%s' %s - validation of export component '%s' failed: %s",
|
||||
exportEntity->GetName().c_str(),
|
||||
exportEntity->GetId().ToString().c_str(),
|
||||
component->RTTI_GetTypeName(),
|
||||
result.GetError().c_str())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove editor-only entities from instance.
|
||||
AZStd::unordered_map<AZ::EntityId, AZ::Entity*> exportEntitiesMap;
|
||||
AZStd::for_each(exportEntities.begin(), exportEntities.end(),
|
||||
[&exportEntitiesMap](auto& entity)
|
||||
{
|
||||
exportEntitiesMap.emplace(entity->GetId(), entity);
|
||||
}
|
||||
);
|
||||
instance->RemoveNestedEntities(
|
||||
[&exportEntitiesMap](const AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
{
|
||||
return exportEntitiesMap.find(entity->GetId()) == exportEntitiesMap.end();
|
||||
}
|
||||
);
|
||||
|
||||
// replace entities of instance with exported ones.
|
||||
instance->GetNestedEntities(
|
||||
[&exportEntitiesMap](AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
{
|
||||
auto entityId = entity->GetId();
|
||||
entity.release();
|
||||
entity.reset(exportEntitiesMap[entityId]);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
// save the final result in the target Prefab DOM.
|
||||
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*instance, prefab))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"Saving exported Prefab Instance within a Prefab Dom failed.")
|
||||
);
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ComponentRequirementsValidator.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/EditorOnlyEntityHandler.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessor.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework::Components
|
||||
{
|
||||
class EditorComponentBase;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class EditorInfoRemover
|
||||
: public PrefabProcessor
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorInfoRemover, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover,
|
||||
"{50B48C7E-C9DE-48DE-8438-1A186A8EEAC8}", PrefabProcessor);
|
||||
|
||||
~EditorInfoRemover() override;
|
||||
|
||||
void Process(PrefabProcessorContext& prefabProcessorContext) override;
|
||||
|
||||
using RemoveEditorInfoResult = AZ::Outcome<void, AZStd::string>;
|
||||
RemoveEditorInfoResult RemoveEditorInfo(
|
||||
PrefabDom& prefab,
|
||||
AZ::SerializeContext* serializeContext,
|
||||
PrefabProcessorContext& prefabProcessorContext);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
protected:
|
||||
using EntityList = AZStd::vector<AZ::Entity*>;
|
||||
static EntityList GetEntitiesFromInstance(
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance>& instance);
|
||||
|
||||
static bool ReadComponentAttribute(
|
||||
AZ::Component* component,
|
||||
AZ::Edit::Attribute* attribute,
|
||||
AZStd::vector<AZ::Crc32>& attributeTags);
|
||||
|
||||
void SetEditorOnlyEntityHandlerFromCandidates(const EntityList& entities);
|
||||
|
||||
bool HasValidEditorOnlyHandler() const;
|
||||
|
||||
void ClearEditorOnlyEntityIds();
|
||||
|
||||
void AddEntityIdIfEditorOnly(AZ::Entity* entity);
|
||||
|
||||
using RemoveEditorOnlyEntitiesResult = AZ::Outcome<void, AZStd::string>;
|
||||
RemoveEditorOnlyEntitiesResult RemoveEditorOnlyEntities(EntityList& entities);
|
||||
|
||||
using ExportEntityResult = AZ::Outcome<AZ::Entity*, AZStd::string>;
|
||||
ExportEntityResult ExportEntity(AZ::Entity* sourceEntity, PrefabProcessorContext& context);
|
||||
|
||||
using ResolveExportedComponentResult = AZ::Outcome<AZ::ExportedComponent, AZStd::string>;
|
||||
ResolveExportedComponentResult ResolveExportedComponent(
|
||||
AZ::ExportedComponent& component, PrefabProcessorContext& prefabProcessorContext);
|
||||
|
||||
using ShouldExportResult = AZ::Outcome<bool, AZStd::string>;
|
||||
ShouldExportResult ShouldExportComponent(
|
||||
AZ::Component* component,
|
||||
PrefabProcessorContext& prefabProcessorContext) const;
|
||||
|
||||
using BuildGameEntityResult = AZ::Outcome<void, AZStd::string>;
|
||||
BuildGameEntityResult BuildGameEntity(
|
||||
AzToolsFramework::Components::EditorComponentBase* editorComponent,
|
||||
AZ::Entity* sourceEntity,
|
||||
AZ::Entity* exportEntity
|
||||
);
|
||||
|
||||
using ExportComponentResult = AZ::Outcome<void, AZStd::string>;
|
||||
ExportComponentResult ExportComponent(
|
||||
AZ::Component* component,
|
||||
PrefabProcessorContext& prefabProcessorContext,
|
||||
AZ::Entity* sourceEntity,
|
||||
AZ::Entity* exportEntity);
|
||||
|
||||
AZ::SerializeContext* m_serializeContext{ nullptr };
|
||||
EditorOnlyEntityHandler* m_editorOnlyEntityHandler{ nullptr };
|
||||
EditorOnlyEntityHandlers m_editorOnlyEntityHandlerCandidates{
|
||||
aznew WorldEditorOnlyEntityHandler(),
|
||||
aznew UiEditorOnlyEntityHandler() };
|
||||
ComponentRequirementsValidator m_componentRequirementsValidator;
|
||||
EntityIdSet m_editorOnlyEntityIds;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/EditorOnlyEntityHandler.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
void EditorOnlyEntityHandler::AddEditorOnlyEntity(
|
||||
AZ::Entity* editorOnlyEntity,
|
||||
AZStd::unordered_set<AZ::EntityId>& editorOnlyEntities)
|
||||
{
|
||||
editorOnlyEntities.insert(editorOnlyEntity->GetId());
|
||||
}
|
||||
|
||||
EditorOnlyEntityHandler::Result EditorOnlyEntityHandler::HandleEditorOnlyEntities(
|
||||
const EntityList& /*entities*/,
|
||||
const EntityIdSet& /*editorOnlyEntityIds*/,
|
||||
AZ::SerializeContext& /*serializeContext*/)
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
EditorOnlyEntityHandler::Result EditorOnlyEntityHandler::ValidateReferences(
|
||||
const EntityList& entities,
|
||||
const EntityIdSet& editorOnlyEntityIds,
|
||||
AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
EditorOnlyEntityHandler::Result result = AZ::Success();
|
||||
|
||||
// Inspect all runtime entities via the serialize context and identify any references to editor-only entity Ids.
|
||||
for (AZ::Entity* runtimeEntity : entities)
|
||||
{
|
||||
if (editorOnlyEntityIds.end() != editorOnlyEntityIds.find(runtimeEntity->GetId()))
|
||||
{
|
||||
continue; // This is not a runtime entity, so no need to validate its references as it's going away.
|
||||
}
|
||||
|
||||
AZ::EntityUtils::EnumerateEntityIds<AZ::Entity>(
|
||||
runtimeEntity,
|
||||
[&editorOnlyEntityIds, &result, runtimeEntity](const AZ::EntityId& id, bool /*isEntityId*/, const AZ::SerializeContext::ClassElement* /*elementData*/)
|
||||
{
|
||||
if (editorOnlyEntityIds.end() != editorOnlyEntityIds.find(id))
|
||||
{
|
||||
result = AZ::Failure(
|
||||
AZStd::string::format(
|
||||
"A runtime entity (%s) contains references to an entity marked as editor-only.",
|
||||
runtimeEntity->GetName().c_str()
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
&serializeContext
|
||||
);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
/**
|
||||
* Callback handler interface for processing prefab prior to stripping of editor-only entities.
|
||||
*/
|
||||
class EditorOnlyEntityHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorOnlyEntityHandler, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::EditorOnlyEntityHandler, "{C420F65D-18AE-4CAF-BB18-70FA4FE73243}");
|
||||
|
||||
virtual ~EditorOnlyEntityHandler() = default;
|
||||
|
||||
virtual bool IsEntityUniquelyForThisHandler(AZ::Entity* entity) const = 0;
|
||||
|
||||
/**
|
||||
* Adds the given entity ID to the set of editor only entities.
|
||||
*
|
||||
* Handlers can customize this behavior, such as additionally adding child entities
|
||||
* when a parent is marked as editor-only.
|
||||
*/
|
||||
virtual void AddEditorOnlyEntity(
|
||||
AZ::Entity* editorOnlyEntity,
|
||||
AZStd::unordered_set<AZ::EntityId>& editorOnlyEntities);
|
||||
|
||||
using Result = AZ::Outcome<void, AZStd::string>;
|
||||
|
||||
/**
|
||||
* This handler is responsible for making any necessary modifications to other entities in the Prefab prior to the removal
|
||||
* of all editor-only entities.
|
||||
* After this callback returns, editor-only entities will be removed from the Prefab.
|
||||
* See \ref WorldEditorOnlyEntityHandler below for an example of processing and validation that occurs for standard world entities.
|
||||
* @param entities a list of all entities in the Prefab, including those marked as editor-only.
|
||||
* @param editorOnlyEntityIds a precomputed set containing Ids for all entities within the 'entities' list that were marked as editor-only.
|
||||
* @param serializeContext useful to inspect entity data for validation purposes.
|
||||
*/
|
||||
virtual Result HandleEditorOnlyEntities(
|
||||
const EntityList& /*entities*/,
|
||||
const EntityIdSet& /*editorOnlyEntityIds*/,
|
||||
AZ::SerializeContext& /*serializeContext*/);
|
||||
|
||||
// Verify that none of the runtime entities reference editor-only entities. Fail w/ details if so.
|
||||
static Result ValidateReferences(
|
||||
const EntityList& entities,
|
||||
const EntityIdSet& editorOnlyEntityIds,
|
||||
AZ::SerializeContext& serializeContext);
|
||||
};
|
||||
|
||||
using EditorOnlyEntityHandlers = AZStd::vector<EditorOnlyEntityHandler*>;
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/UiEditorOnlyEntityHandler.h>
|
||||
|
||||
#include <AzFramework/InGameUI/UiFrameworkBus.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
bool UiEditorOnlyEntityHandler::IsEntityUniquelyForThisHandler(AZ::Entity* entity) const
|
||||
{
|
||||
// Assume that an entity is a UI element if it has a UI element component.
|
||||
bool uniqueForThisHandler = false;
|
||||
UiFrameworkBus::BroadcastResult(uniqueForThisHandler, &UiFrameworkInterface::HasUiElementComponent, entity);
|
||||
|
||||
return uniqueForThisHandler;
|
||||
}
|
||||
|
||||
void UiEditorOnlyEntityHandler::AddEditorOnlyEntity(AZ::Entity* editorOnlyEntity, EntityIdSet& editorOnlyEntities)
|
||||
{
|
||||
UiFrameworkBus::Broadcast(&UiFrameworkInterface::AddEditorOnlyEntity, editorOnlyEntity, editorOnlyEntities);
|
||||
}
|
||||
|
||||
EditorOnlyEntityHandler::Result UiEditorOnlyEntityHandler::HandleEditorOnlyEntities(
|
||||
const AzToolsFramework::EntityList& exportEntities,
|
||||
const AzToolsFramework::EntityIdSet& editorOnlyEntityIds,
|
||||
AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
UiFrameworkBus::Broadcast(&UiFrameworkInterface::HandleEditorOnlyEntities, exportEntities, editorOnlyEntityIds);
|
||||
|
||||
// Perform a final check to verify that all editor-only entities have been removed
|
||||
auto result = ValidateReferences(exportEntities, editorOnlyEntityIds, serializeContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/EditorOnlyEntityHandler.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
/**
|
||||
* EditorOnlyEntity handler for UI entities.
|
||||
* - Removes editor-only entities and their descedent hierarchy entirely.
|
||||
* -- This differs from the world-entity handler where editor-only entities
|
||||
* are removed "in-place".
|
||||
* - Validates that no editor entities are referenced by non-editor entities.
|
||||
*/
|
||||
class UiEditorOnlyEntityHandler
|
||||
: public EditorOnlyEntityHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(UiEditorOnlyEntityHandler, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::UiEditorOnlyEntityHandler, "{949CF813-4A8E-4D55-B323-0ED2A967CDCC}", EditorOnlyEntityHandler);
|
||||
|
||||
bool IsEntityUniquelyForThisHandler(AZ::Entity* entity) const override;
|
||||
|
||||
void AddEditorOnlyEntity(AZ::Entity* editorOnlyEntity, EntityIdSet& editorOnlyEntities) override;
|
||||
|
||||
Result HandleEditorOnlyEntities(
|
||||
const AzToolsFramework::EntityList& entities,
|
||||
const AzToolsFramework::EntityIdSet& editorOnlyEntityIds,
|
||||
AZ::SerializeContext& serializeContext) override;
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/WorldEditorOnlyEntityHandler.h>
|
||||
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
bool WorldEditorOnlyEntityHandler::IsEntityUniquelyForThisHandler(AZ::Entity* entity) const
|
||||
{
|
||||
return AZ::EntityUtils::FindFirstDerivedComponent<AZ::TransformInterface>(entity) != nullptr;
|
||||
}
|
||||
|
||||
EditorOnlyEntityHandler::Result WorldEditorOnlyEntityHandler::HandleEditorOnlyEntities(const AzToolsFramework::EntityList& entities, const AzToolsFramework::EntityIdSet& editorOnlyEntityIds, AZ::SerializeContext& serializeContext)
|
||||
{
|
||||
FixTransformRelationships(entities, editorOnlyEntityIds);
|
||||
|
||||
return ValidateReferences(entities, editorOnlyEntityIds, serializeContext);
|
||||
}
|
||||
|
||||
void WorldEditorOnlyEntityHandler::FixTransformRelationships(const AzToolsFramework::EntityList& entities, const AzToolsFramework::EntityIdSet& editorOnlyEntityIds)
|
||||
{
|
||||
AZStd::unordered_map<AZ::EntityId, AZStd::vector<AZ::Entity*>> parentToChildren;
|
||||
|
||||
// Build a map of entity Ids to their parent Ids, for faster lookup during processing.
|
||||
for (AZ::Entity* entity : entities)
|
||||
{
|
||||
AZ::TransformInterface* transformComponent = AZ::EntityUtils::FindFirstDerivedComponent<AZ::TransformInterface>(entity);
|
||||
if (transformComponent)
|
||||
{
|
||||
const AZ::EntityId parentId = transformComponent->GetParentId();
|
||||
if (parentId.IsValid())
|
||||
{
|
||||
parentToChildren[parentId].push_back(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identify any editor-only entities. If we encounter one, adjust transform relationships
|
||||
// for all of its children to ensure relative transforms are maintained and respected at
|
||||
// runtime.
|
||||
// This works regardless of entity ordering in the Prefab because we add reassigned children to
|
||||
// parentToChildren cache during the operation.
|
||||
for (AZ::Entity* entity : entities)
|
||||
{
|
||||
if (editorOnlyEntityIds.end() == editorOnlyEntityIds.find(entity->GetId()))
|
||||
{
|
||||
continue; // This is not an editor-only entity.
|
||||
}
|
||||
|
||||
AZ::TransformInterface* transformComponent = AZ::EntityUtils::FindFirstDerivedComponent<AZ::TransformInterface>(entity);
|
||||
if (transformComponent)
|
||||
{
|
||||
const AZ::Transform& parentLocalTm = transformComponent->GetLocalTM();
|
||||
|
||||
// Identify all transform children and adjust them to be children of the removed entity's parent.
|
||||
for (AZ::Entity* childEntity : parentToChildren[entity->GetId()])
|
||||
{
|
||||
AZ::TransformInterface* childTransformComponent = AZ::EntityUtils::FindFirstDerivedComponent<AZ::TransformInterface>(childEntity);
|
||||
|
||||
if (childTransformComponent && childTransformComponent->GetParentId() == entity->GetId())
|
||||
{
|
||||
const AZ::Transform localTm = childTransformComponent->GetLocalTM();
|
||||
childTransformComponent->SetParent(transformComponent->GetParentId());
|
||||
childTransformComponent->SetLocalTM(parentLocalTm * localTm);
|
||||
|
||||
parentToChildren[transformComponent->GetParentId()].push_back(childEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/EditorOnlyEntityHandler/EditorOnlyEntityHandler.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
/**
|
||||
* EditorOnlyEntity handler for world entities.
|
||||
* - Fixes up transform relationships so entities removed mid-hierarchy still result in valid runtime transform relationships
|
||||
* and correct relative transforms.
|
||||
* - Validates that no editor entities are referenced by non-editor entities.
|
||||
*/
|
||||
class WorldEditorOnlyEntityHandler
|
||||
: public EditorOnlyEntityHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(WorldEditorOnlyEntityHandler, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::WorldEditorOnlyEntityHandler, "{55587AE2-B583-48E4-9634-6BFACF6CBF04}", EditorOnlyEntityHandler);
|
||||
|
||||
bool IsEntityUniquelyForThisHandler(AZ::Entity* entity) const override;
|
||||
|
||||
Result HandleEditorOnlyEntities(
|
||||
const AzToolsFramework::EntityList& entities,
|
||||
const AzToolsFramework::EntityIdSet& editorOnlyEntityIds,
|
||||
AZ::SerializeContext& serializeContext) override;
|
||||
|
||||
// Adjust transform relationships to maintain integrity of the transform hierarchy at runtime, even if editor-only
|
||||
// entities were positioned within the transform hierarchy.
|
||||
static void FixTransformRelationships(
|
||||
const AzToolsFramework::EntityList& entities,
|
||||
const AzToolsFramework::EntityIdSet& editorOnlyEntityIds);
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/IO/ByteContainerStream.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
void PrefabCatchmentProcessor::Process(PrefabProcessorContext& context)
|
||||
{
|
||||
context.ListPrefabs([&context](AZStd::string_view prefabName, PrefabDom& prefab)
|
||||
{
|
||||
ProcessPrefab(context, prefabName, prefab);
|
||||
});
|
||||
}
|
||||
|
||||
void PrefabCatchmentProcessor::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
|
||||
{
|
||||
serializeContext->Class<PrefabCatchmentProcessor, PrefabProcessor>()->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabCatchmentProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab)
|
||||
{
|
||||
|
||||
AZStd::string uniqueName = prefabName;
|
||||
uniqueName += '.';
|
||||
uniqueName += AzFramework::Spawnable::FileExtension;
|
||||
|
||||
auto serializer = [](AZStd::vector<uint8_t>& output, const ProcessedObjectStore& object) -> bool
|
||||
{
|
||||
AZ::IO::ByteContainerStream stream(&output);
|
||||
return AZ::Utils::SaveObjectToStream(stream, AZ::DataStream::StreamType::ST_BINARY,
|
||||
AZStd::any_cast<void>(&object.GetObject()), object.GetObject().type());
|
||||
};
|
||||
|
||||
auto spawnable = SpawnableUtils::CreateSpawnable(prefab);
|
||||
SpawnableUtils::SortEntitiesByTransformHierarchy(spawnable);
|
||||
AZStd::any spawnableAny(AZStd::move(spawnable));
|
||||
|
||||
context.GetProcessedObjects().emplace_back(AZStd::move(uniqueName), AZStd::move(spawnableAny),
|
||||
AZStd::move(serializer), AZ::AzTypeInfo<AzFramework::Spawnable>::Uuid());
|
||||
|
||||
context.RemovePrefab(prefabName);
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessor.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class PrefabCatchmentProcessor
|
||||
: public PrefabProcessor
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabCatchmentProcessor, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor,
|
||||
"{F71E2FBA-22ED-44C7-B4C8-D2CF4B2C7B97}", PrefabProcessor);
|
||||
|
||||
~PrefabCatchmentProcessor() override = default;
|
||||
|
||||
void Process(PrefabProcessorContext& context) override;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
protected:
|
||||
static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab);
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
bool PrefabConversionPipeline::LoadStackProfile(AZStd::string_view stackProfile)
|
||||
{
|
||||
m_processors.clear();
|
||||
|
||||
AZStd::string registryKey = "/Amazon/Tools/Prefab/Processing/Stack/";
|
||||
registryKey += stackProfile;
|
||||
|
||||
auto registry = AZ::SettingsRegistry::Get();
|
||||
AZ_Assert(registry, "PrefabConversionPipeline is created before the Settings Registry is available.");
|
||||
return registry->GetObject(m_processors, registryKey);
|
||||
}
|
||||
|
||||
void PrefabConversionPipeline::ProcessPrefab(PrefabProcessorContext& context)
|
||||
{
|
||||
for (auto& processor : m_processors)
|
||||
{
|
||||
processor->Process(context);
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabConversionPipeline::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
|
||||
{
|
||||
serializeContext->Class<PrefabProcessor>()->Version(1);
|
||||
serializeContext->RegisterGenericType<PrefabProcessorList>();
|
||||
serializeContext->RegisterGenericType<PrefabProcessorListEntry>();
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessor.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class PrefabConversionPipeline final
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabConversionPipeline, AZ::SystemAllocator, 0);
|
||||
|
||||
using PrefabProcessorListEntry = AZStd::unique_ptr<PrefabProcessor>;
|
||||
using PrefabProcessorList = AZStd::vector<PrefabProcessorListEntry>;
|
||||
|
||||
bool LoadStackProfile(AZStd::string_view stackProfile);
|
||||
|
||||
void ProcessPrefab(PrefabProcessorContext& context);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
PrefabProcessorList m_processors;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class PrefabProcessor
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(PrefabProcessor, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(PrefabProcessor, "{393C95DF-C0DA-4EF0-A081-9CA899649DDD}");
|
||||
|
||||
virtual ~PrefabProcessor() = default;
|
||||
|
||||
virtual void Process(PrefabProcessorContext& context) = 0;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabProcessorContext.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
bool PrefabProcessorContext::AddPrefab(AZStd::string prefabName, PrefabDom prefab)
|
||||
{
|
||||
auto result = m_prefabs.emplace(AZStd::move(prefabName), AZStd::move(prefab));
|
||||
return result.second;
|
||||
}
|
||||
|
||||
bool PrefabProcessorContext::RemovePrefab(AZStd::string_view prefabName)
|
||||
{
|
||||
if (!m_isIterating)
|
||||
{
|
||||
return m_prefabs.erase(prefabName) > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_delayedDelete.emplace_back(prefabName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(AZStd::string_view, PrefabDom&)>& callback)
|
||||
{
|
||||
m_isIterating = true;
|
||||
for (auto& it : m_prefabs)
|
||||
{
|
||||
if (AZStd::find(m_delayedDelete.begin(), m_delayedDelete.end(), it.first) == m_delayedDelete.end())
|
||||
{
|
||||
callback(it.first, it.second);
|
||||
}
|
||||
}
|
||||
m_isIterating = false;
|
||||
|
||||
// Clear out any prefabs that have been deleted.
|
||||
for (AZStd::string& deleted : m_delayedDelete)
|
||||
{
|
||||
m_prefabs.erase(deleted);
|
||||
}
|
||||
m_delayedDelete.clear();
|
||||
}
|
||||
|
||||
void PrefabProcessorContext::ListPrefabs(const AZStd::function<void(AZStd::string_view, const PrefabDom&)>& callback) const
|
||||
{
|
||||
for (const auto& it : m_prefabs)
|
||||
{
|
||||
callback(it.first, it.second);
|
||||
}
|
||||
}
|
||||
|
||||
bool PrefabProcessorContext::HasPrefabs() const
|
||||
{
|
||||
return !m_prefabs.empty();
|
||||
}
|
||||
|
||||
PrefabProcessorContext::ProcessedObjectStoreContainer& PrefabProcessorContext::GetProcessedObjects()
|
||||
{
|
||||
return m_products;
|
||||
}
|
||||
|
||||
const PrefabProcessorContext::ProcessedObjectStoreContainer& PrefabProcessorContext::GetProcessedObjects() const
|
||||
{
|
||||
return m_products;
|
||||
}
|
||||
|
||||
const AZ::PlatformTagSet& PrefabProcessorContext::GetPlatformTags() const
|
||||
{
|
||||
return m_platformTags;
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/ComponentExport.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class PrefabProcessorContext
|
||||
{
|
||||
public:
|
||||
using ProcessedObjectStoreContainer = AZStd::vector<ProcessedObjectStore>;
|
||||
|
||||
AZ_CLASS_ALLOCATOR(PrefabProcessorContext, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(PrefabProcessorContext, "{C7D77E3A-C544-486B-B774-7C82C38FE22F}");
|
||||
|
||||
virtual ~PrefabProcessorContext() = default;
|
||||
|
||||
virtual bool AddPrefab(AZStd::string prefabName, PrefabDom prefab);
|
||||
virtual bool RemovePrefab(AZStd::string_view prefabName);
|
||||
virtual void ListPrefabs(const AZStd::function<void(AZStd::string_view, PrefabDom&)>& callback);
|
||||
virtual void ListPrefabs(const AZStd::function<void(AZStd::string_view, const PrefabDom&)>& callback) const;
|
||||
virtual bool HasPrefabs() const;
|
||||
|
||||
virtual ProcessedObjectStoreContainer& GetProcessedObjects();
|
||||
virtual const ProcessedObjectStoreContainer& GetProcessedObjects() const;
|
||||
|
||||
virtual const AZ::PlatformTagSet& GetPlatformTags() const;
|
||||
|
||||
protected:
|
||||
using NamedPrefabContainer = AZStd::unordered_map<AZStd::string, PrefabDom>;
|
||||
|
||||
NamedPrefabContainer m_prefabs;
|
||||
ProcessedObjectStoreContainer m_products;
|
||||
AZStd::vector<AZStd::string> m_delayedDelete;
|
||||
AZ::PlatformTagSet m_platformTags;
|
||||
bool m_isIterating{ false };
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
ProcessedObjectStore::ProcessedObjectStore(AZStd::string uniqueId, AZStd::any object, SerializerFunction objectSerializer,
|
||||
AZ::Data::AssetType assetType)
|
||||
: m_uniqueId(AZStd::move(uniqueId))
|
||||
, m_object(AZStd::move(object))
|
||||
, m_objectSerializer(AZStd::move(objectSerializer))
|
||||
, m_assetType(AZStd::move(assetType))
|
||||
{
|
||||
}
|
||||
|
||||
bool ProcessedObjectStore::Serialize(AZStd::vector<uint8_t>& output) const
|
||||
{
|
||||
if (m_objectSerializer)
|
||||
{
|
||||
return m_objectSerializer(output, *this);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const AZStd::any& ProcessedObjectStore::GetObject() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
AZStd::any ProcessedObjectStore::ReleaseObject()
|
||||
{
|
||||
return AZStd::move(m_object);
|
||||
}
|
||||
|
||||
uint32_t ProcessedObjectStore::BuildSubId() const
|
||||
{
|
||||
AZ::Uuid subIdHash = AZ::Uuid::CreateData(m_uniqueId.data(), m_uniqueId.size());
|
||||
return azlossy_caster(subIdHash.GetHash());
|
||||
}
|
||||
|
||||
const AZ::Data::AssetType& ProcessedObjectStore::GetAssetType() const
|
||||
{
|
||||
return m_assetType;
|
||||
}
|
||||
|
||||
const AZStd::string& ProcessedObjectStore::GetId() const
|
||||
{
|
||||
return m_uniqueId;
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
//! Storage for objects created through the Prefab processing pipeline.
|
||||
//! These typically store the created object for immediate use in the editor plus additional information
|
||||
//! to allow the Prefab Builder to convert the object into a serialized form and register it with the
|
||||
//! Asset Database.
|
||||
class ProcessedObjectStore
|
||||
{
|
||||
public:
|
||||
using SerializerFunction = AZStd::function<bool(AZStd::vector<uint8_t>&, const ProcessedObjectStore&)>;
|
||||
|
||||
//! Constructs a new instance.
|
||||
//! @param uniqueId A name for the object that's unique within the scope of the Prefab. This name will be used to generate a sub id for the product
|
||||
//! which requires that the name is stable between runs.
|
||||
//! @param object The object that generated during processing of a Prefab.
|
||||
//! @param objectSerializer The callback used to convert the provided object into a binary stream.
|
||||
//! @param assetType The asset type of the asset.
|
||||
//! @param storagePath The relative path where the asset will be stored if/when committed to disk.
|
||||
ProcessedObjectStore(AZStd::string uniqueId, AZStd::any object, SerializerFunction objectSerializer, AZ::Data::AssetType assetType);
|
||||
|
||||
bool Serialize(AZStd::vector<uint8_t>& output) const;
|
||||
uint32_t BuildSubId() const;
|
||||
|
||||
const AZStd::any& GetObject() const;
|
||||
AZStd::any ReleaseObject();
|
||||
|
||||
const AZ::Data::AssetType& GetAssetType() const;
|
||||
const AZStd::string& GetId() const;
|
||||
|
||||
private:
|
||||
AZStd::any m_object;
|
||||
SerializerFunction m_objectSerializer;
|
||||
AZ::Data::AssetType m_assetType;
|
||||
AZStd::string m_uniqueId;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/SpawnableMetaDataBuilder.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::Add(AZStd::string_view key, bool value)
|
||||
{
|
||||
return AddGeneric(key, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::Add(AZStd::string_view key, uint64_t value)
|
||||
{
|
||||
return AddGeneric(key, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::Add(AZStd::string_view key, int64_t value)
|
||||
{
|
||||
return AddGeneric(key, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::Add(AZStd::string_view key, double value)
|
||||
{
|
||||
return AddGeneric(key, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::Add(AZStd::string_view key, AZStd::string value)
|
||||
{
|
||||
return AddGeneric(key, AZStd::move(value));
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArray(AZStd::string_view arrayKey, bool value)
|
||||
{
|
||||
return AppendArrayGeneric(arrayKey, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArray(AZStd::string_view arrayKey, uint64_t value)
|
||||
{
|
||||
return AppendArrayGeneric(arrayKey, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArray(AZStd::string_view arrayKey, int64_t value)
|
||||
{
|
||||
return AppendArrayGeneric(arrayKey, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArray(AZStd::string_view arrayKey, double value)
|
||||
{
|
||||
return AppendArrayGeneric(arrayKey, value);
|
||||
}
|
||||
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArray(AZStd::string_view arrayKey, AZStd::string value)
|
||||
{
|
||||
return AppendArrayGeneric(arrayKey, AZStd::move(value));
|
||||
}
|
||||
|
||||
bool SpawnableMetaDataBuilder::Remove(AZStd::string_view key)
|
||||
{
|
||||
auto it = m_table.find(HashKey(key));
|
||||
if (it != m_table.end())
|
||||
{
|
||||
RemoveAllEntriesIfArray(key, it);
|
||||
m_table.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpawnableMetaDataBuilder::RemoveArrayEntry(AZStd::string_view arrayKey, uint64_t index)
|
||||
{
|
||||
return RemoveArrayEntry(arrayKey, aznumeric_cast<AzFramework::SpawnableMetaDataArrayIndex>(index));
|
||||
}
|
||||
|
||||
bool SpawnableMetaDataBuilder::RemoveArrayEntry(AZStd::string_view arrayKey, AzFramework::SpawnableMetaDataArrayIndex index)
|
||||
{
|
||||
auto it = m_table.find(HashKey(arrayKey));
|
||||
if (it != m_table.end())
|
||||
{
|
||||
if (AzFramework::SpawnableMetaDataArraySize* size =
|
||||
AZStd::get_if<AzFramework::SpawnableMetaDataArraySize>(&it->second); size != nullptr)
|
||||
{
|
||||
if (index < *size)
|
||||
{
|
||||
AZ::HashValue64 indexHash = HashArrayKey(arrayKey, index);
|
||||
index++;
|
||||
for (; index < *size; ++index)
|
||||
{
|
||||
AZ::HashValue64 nextIndexHash = HashArrayKey(arrayKey, index);
|
||||
m_table[indexHash] = AZStd::move(m_table[nextIndexHash]);
|
||||
indexHash = nextIndexHash;
|
||||
}
|
||||
[[maybe_unused]] size_t removedCount = m_table.erase(indexHash);
|
||||
AZ_Assert(removedCount == 1, "RemoveArrayEntry did not correctly detect an edge case.");
|
||||
|
||||
(*size)--;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SpawnableMetaDataBuilder::GetEntryCount() const
|
||||
{
|
||||
return m_table.size();
|
||||
}
|
||||
|
||||
AzFramework::SpawnableMetaData SpawnableMetaDataBuilder::BuildMetaData() const
|
||||
{
|
||||
AzFramework::SpawnableMetaData::Table readOnlyTable;
|
||||
|
||||
readOnlyTable.reserve(m_table.size());
|
||||
AZStd::transform(m_table.begin(), m_table.end(), AZStd::back_inserter(readOnlyTable),
|
||||
[](const auto& entry)
|
||||
{
|
||||
return AzFramework::SpawnableMetaData::TableEntry(entry.first, entry.second);
|
||||
});
|
||||
|
||||
AZStd::sort(readOnlyTable.begin(), readOnlyTable.end(),
|
||||
[](const auto& lhs, const auto& rhs)
|
||||
{
|
||||
return lhs.first < rhs.first;
|
||||
});
|
||||
|
||||
return AzFramework::SpawnableMetaData(AZStd::move(readOnlyTable));
|
||||
}
|
||||
|
||||
AZ::HashValue64 SpawnableMetaDataBuilder::HashKey(AZStd::string_view key) const
|
||||
{
|
||||
return AZ::TypeHash64(reinterpret_cast<const uint8_t*>(key.data()), aznumeric_cast<uint64_t>(key.length()));
|
||||
}
|
||||
|
||||
AZ::HashValue64 SpawnableMetaDataBuilder::HashArrayKey(AZStd::string_view arrayKey, uint64_t index) const
|
||||
{
|
||||
return AZ::TypeHash64(reinterpret_cast<const uint8_t*>(arrayKey.data()), aznumeric_cast<uint64_t>(arrayKey.length()),
|
||||
aznumeric_caster(AzFramework::SpawnableMetaData::ArrayKeyRoot + index));
|
||||
}
|
||||
|
||||
AZ::HashValue64 SpawnableMetaDataBuilder::HashArrayKey(AZStd::string_view arrayKey, AzFramework::SpawnableMetaDataArrayIndex index) const
|
||||
{
|
||||
return HashArrayKey(arrayKey, aznumeric_cast<uint64_t>(index));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AddGeneric(AZStd::string_view key, T&& value)
|
||||
{
|
||||
auto keyHash = HashKey(key);
|
||||
auto it = m_table.find(keyHash);
|
||||
if (it != m_table.end())
|
||||
{
|
||||
RemoveAllEntriesIfArray(key, it);
|
||||
it->second = AZStd::forward<T>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_table.emplace(keyHash, AZStd::forward<T>(value));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
SpawnableMetaDataBuilder& SpawnableMetaDataBuilder::AppendArrayGeneric(AZStd::string_view arrayKey, T&& value)
|
||||
{
|
||||
auto arrayKeyHash = HashKey(arrayKey);
|
||||
auto it = m_table.find(arrayKeyHash);
|
||||
if (it != m_table.end())
|
||||
{
|
||||
if (AzFramework::SpawnableMetaDataArraySize* storedValue =
|
||||
AZStd::get_if<AzFramework::SpawnableMetaDataArraySize>(&it->second); storedValue != nullptr)
|
||||
{
|
||||
m_table[HashArrayKey(arrayKey, (*storedValue)++)] = AZStd::forward<T>(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second = AzFramework::SpawnableMetaDataArraySize{ 1 };
|
||||
m_table[HashArrayKey(arrayKey, 0)] = AZStd::forward<T>(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_table.emplace(arrayKeyHash, AzFramework::SpawnableMetaDataArraySize{ 1 });
|
||||
m_table[HashArrayKey(arrayKey, 0)] = AZStd::forward<T>(value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void SpawnableMetaDataBuilder::RemoveAllEntriesIfArray(AZStd::string_view arrayKey, Table::iterator sizeEntry)
|
||||
{
|
||||
if (AzFramework::SpawnableMetaDataArraySize* size =
|
||||
AZStd::get_if<AzFramework::SpawnableMetaDataArraySize>(&sizeEntry->second); size != nullptr)
|
||||
{
|
||||
for (AzFramework::SpawnableMetaDataArrayIndex i{ 0 }; i < *size; ++i)
|
||||
{
|
||||
[[maybe_unused]] size_t removedCount = m_table.erase(HashArrayKey(arrayKey, i));
|
||||
AZ_Assert(removedCount == 1, "RemoveArrayEntry did not correctly detect an edge case.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Utils/TypeHash.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzFramework/Spawnable/SpawnableMetaData.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
{
|
||||
class SpawnableMetaDataBuilder final
|
||||
{
|
||||
public:
|
||||
SpawnableMetaDataBuilder& Add(AZStd::string_view key, bool value);
|
||||
SpawnableMetaDataBuilder& Add(AZStd::string_view key, uint64_t value);
|
||||
SpawnableMetaDataBuilder& Add(AZStd::string_view key, int64_t value);
|
||||
SpawnableMetaDataBuilder& Add(AZStd::string_view key, double value);
|
||||
SpawnableMetaDataBuilder& Add(AZStd::string_view key, AZStd::string value);
|
||||
|
||||
SpawnableMetaDataBuilder& AppendArray(AZStd::string_view arrayKey, bool value);
|
||||
SpawnableMetaDataBuilder& AppendArray(AZStd::string_view arrayKey, uint64_t value);
|
||||
SpawnableMetaDataBuilder& AppendArray(AZStd::string_view arrayKey, int64_t value);
|
||||
SpawnableMetaDataBuilder& AppendArray(AZStd::string_view arrayKey, double value);
|
||||
SpawnableMetaDataBuilder& AppendArray(AZStd::string_view arrayKey, AZStd::string value);
|
||||
|
||||
bool Remove(AZStd::string_view key);
|
||||
bool RemoveArrayEntry(AZStd::string_view arrayKey, uint64_t index);
|
||||
bool RemoveArrayEntry(AZStd::string_view arrayKey, AzFramework::SpawnableMetaDataArrayIndex index);
|
||||
|
||||
size_t GetEntryCount() const;
|
||||
|
||||
AzFramework::SpawnableMetaData BuildMetaData() const;
|
||||
|
||||
private:
|
||||
using Table = AZStd::unordered_map<AZ::HashValue64, AzFramework::SpawnableMetaData::TableValue>;
|
||||
|
||||
AZ::HashValue64 HashKey(AZStd::string_view key) const;
|
||||
AZ::HashValue64 HashArrayKey(AZStd::string_view arrayKey, uint64_t index) const;
|
||||
AZ::HashValue64 HashArrayKey(AZStd::string_view arrayKey, AzFramework::SpawnableMetaDataArrayIndex index) const;
|
||||
|
||||
template<typename T>
|
||||
SpawnableMetaDataBuilder& AddGeneric(AZStd::string_view key, T&& value);
|
||||
|
||||
template<typename T>
|
||||
SpawnableMetaDataBuilder& AppendArrayGeneric(AZStd::string_view arrayKey, T&& value);
|
||||
|
||||
void RemoveAllEntriesIfArray(AZStd::string_view arrayKey, Table::iterator sizeEntry);
|
||||
|
||||
Table m_table;
|
||||
};
|
||||
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/EntityUtils.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom)
|
||||
{
|
||||
AzFramework::Spawnable spawnable;
|
||||
AZStd::unique_ptr<Instance> instance(aznew Instance());
|
||||
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefabDom, false))
|
||||
{
|
||||
AZ_Assert(false,
|
||||
"Failed to Load Prefab Instance from given Prefab DOM while Spawnable creation.");
|
||||
}
|
||||
else
|
||||
{
|
||||
AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
|
||||
instance->DetachNestedEntities([&entities](AZStd::unique_ptr<AZ::Entity> entity)
|
||||
{
|
||||
entities.emplace_back(AZStd::move(entity));
|
||||
});
|
||||
}
|
||||
|
||||
return spawnable;
|
||||
}
|
||||
|
||||
void OrganizeEntitiesForSorting(
|
||||
AzFramework::Spawnable::EntityList& entities,
|
||||
AZStd::unordered_set<AZ::EntityId>& existingEntityIds,
|
||||
AZStd::unordered_map<AZ::EntityId, AzFramework::Spawnable::EntityList>& parentIdToChildren,
|
||||
AZStd::vector<AZ::EntityId>& candidateIds,
|
||||
size_t& removedEntitiesCount)
|
||||
{
|
||||
existingEntityIds.clear();
|
||||
parentIdToChildren.clear();
|
||||
candidateIds.clear();
|
||||
removedEntitiesCount = 0;
|
||||
|
||||
for (auto& entity : entities)
|
||||
{
|
||||
if (!entity)
|
||||
{
|
||||
++removedEntitiesCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
AZ::EntityId entityId = entity->GetId();
|
||||
if (!entityId.IsValid())
|
||||
{
|
||||
AZ_Warning("Entity", false, "Hierarchy sort found entity '%s' with invalid ID", entity->GetName().c_str());
|
||||
|
||||
++removedEntitiesCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!existingEntityIds.insert(entityId).second)
|
||||
{
|
||||
AZ_Warning("Entity", false, "Hierarchy sort found multiple entities using same ID as entity '%s' %s",
|
||||
entity->GetName().c_str(),
|
||||
entityId.ToString().c_str());
|
||||
|
||||
++removedEntitiesCount;
|
||||
continue;
|
||||
}
|
||||
|
||||
// search for any component that implements the TransformInterface.
|
||||
// don't use EBus because we support sorting entities that haven't been initialized or activated.
|
||||
// entities with no transform component will be treated like entities with no parent.
|
||||
AZ::EntityId parentId;
|
||||
if (AZ::TransformInterface* transformInterface =
|
||||
AZ::EntityUtils::FindFirstDerivedComponent<AZ::TransformInterface>(entity.get()))
|
||||
{
|
||||
parentId = transformInterface->GetParentId();
|
||||
if (parentId == entityId)
|
||||
{
|
||||
AZ_Warning("Entity", false, "Hierarchy sort found entity parented to itself '%s' %s",
|
||||
entity->GetName().c_str(),
|
||||
entityId.ToString().c_str());
|
||||
|
||||
parentId.SetInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
auto& children = parentIdToChildren[parentId];
|
||||
children.emplace_back(nullptr);
|
||||
children.back().swap(entity);
|
||||
}
|
||||
|
||||
// clear 'entities', we'll refill it in sorted order.
|
||||
entities.clear();
|
||||
|
||||
// the first candidates should be the parents of the roots.
|
||||
for (auto& parentChildrenPair : parentIdToChildren)
|
||||
{
|
||||
const AZ::EntityId& parentId = parentChildrenPair.first;
|
||||
|
||||
// we found a root if parent ID doesn't correspond to any entity in the list
|
||||
if (existingEntityIds.find(parentId) == existingEntityIds.end())
|
||||
{
|
||||
candidateIds.push_back(parentId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TraceParentingLoop(
|
||||
const AZ::EntityId& parentFromLoopId,
|
||||
const AZStd::unordered_map<AZ::EntityId, AzFramework::Spawnable::EntityList>& parentIdToChildren)
|
||||
{
|
||||
|
||||
// Find name to use in warning message
|
||||
AZStd::string_view parentFromLoopName;
|
||||
for (const auto& parentIdChildrenPair : parentIdToChildren)
|
||||
{
|
||||
for (const auto& entity : parentIdChildrenPair.second)
|
||||
{
|
||||
if (entity->GetId() == parentFromLoopId)
|
||||
{
|
||||
parentFromLoopName = entity->GetName();
|
||||
break;
|
||||
}
|
||||
if (!parentFromLoopName.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Warning("Entity", false, "Hierarchy sort found parenting loop involving entity '%.*s' %s",
|
||||
AZ_STRING_ARG(parentFromLoopName),
|
||||
parentFromLoopId.ToString().c_str());
|
||||
}
|
||||
|
||||
void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable)
|
||||
{
|
||||
auto& entities = spawnable.GetEntities();
|
||||
const size_t originalEntityCount = entities.size();
|
||||
|
||||
// IDs of those present in 'entities'. Does not include parent ID if parent not found in 'entities'
|
||||
AZStd::unordered_set<AZ::EntityId> existingEntityIds;
|
||||
|
||||
// map children by their parent ID (even if parent not found in 'entities')
|
||||
AZStd::unordered_map<AZ::EntityId, AzFramework::Spawnable::EntityList> parentIdToChildren;
|
||||
|
||||
// use 'candidateIds' to track the parent IDs we're going to process next.
|
||||
AZStd::vector<AZ::EntityId> candidateIds;
|
||||
candidateIds.reserve(originalEntityCount + 1);
|
||||
|
||||
size_t removedCount = 0;
|
||||
OrganizeEntitiesForSorting(entities, existingEntityIds, parentIdToChildren, candidateIds, removedCount);
|
||||
|
||||
// process candidates until everything is sorted:
|
||||
// - add candidate's children to the final sorted order
|
||||
// - add candidate's children to list of candidates, so we can process *their* children in a future loop
|
||||
// - erase parent/children entry from parentToChildrenIds
|
||||
// - continue until nothing is left in parentToChildrenIds
|
||||
for (size_t candidateIndex = 0; !parentIdToChildren.empty(); ++candidateIndex)
|
||||
{
|
||||
// if there are no more candidates, but there are still unsorted children, then we have an infinite loop.
|
||||
// pick an arbitrary parent from the loop to be the next candidate.
|
||||
if (candidateIndex == candidateIds.size())
|
||||
{
|
||||
const AZ::EntityId& parentFromLoopId = parentIdToChildren.begin()->first;
|
||||
|
||||
#ifdef AZ_ENABLE_TRACING
|
||||
TraceParentingLoop(parentFromLoopId, parentIdToChildren);
|
||||
#endif // AZ_ENABLE_TRACING
|
||||
|
||||
candidateIds.push_back(parentFromLoopId);
|
||||
}
|
||||
|
||||
const AZ::EntityId& parentId = candidateIds[candidateIndex];
|
||||
|
||||
auto foundChildren = parentIdToChildren.find(parentId);
|
||||
if (foundChildren != parentIdToChildren.end())
|
||||
{
|
||||
for (auto& child : foundChildren->second)
|
||||
{
|
||||
candidateIds.push_back(child->GetId());
|
||||
entities.emplace_back(nullptr);
|
||||
entities.back().swap(child);
|
||||
}
|
||||
|
||||
parentIdToChildren.erase(foundChildren);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AZ_Assert(entities.size() + removedCount == originalEntityCount,
|
||||
"Wrong number of entities after sort. Original entity count = %zu, Sorted entity count = %zu, Removed entity count = %zu",
|
||||
originalEntityCount,
|
||||
entities.size(),
|
||||
removedCount
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
|
||||
namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom);
|
||||
|
||||
void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable);
|
||||
} // namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
+6
@@ -217,10 +217,16 @@ namespace AzToolsFramework
|
||||
ComponentEntityEditorRequestBus::Event(descendant, &ComponentEntityEditorRequestBus::Events::RefreshVisibilityAndLock);
|
||||
}
|
||||
}
|
||||
|
||||
AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Broadcast(
|
||||
&AzToolsFramework::Layers::EditorLayerComponentNotifications::OnLayerComponentActivated, GetEntityId());
|
||||
}
|
||||
|
||||
void EditorLayerComponent::Deactivate()
|
||||
{
|
||||
AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Broadcast(
|
||||
&AzToolsFramework::Layers::EditorLayerComponentNotifications::OnLayerComponentDeactivated, GetEntityId());
|
||||
|
||||
AZ::TransformNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
+23
@@ -207,5 +207,28 @@ namespace AzToolsFramework
|
||||
virtual void OnNewLayerEntity(const AZ::EntityId& entityId, AZStd::vector<AZ::Component*>& componentsToAdd) = 0;
|
||||
};
|
||||
using EditorLayerCreationBus = AZ::EBus<EditorLayerCreationNotification>;
|
||||
|
||||
/**
|
||||
* This is a single bus with multiple listeners, for allowing systems to listen when specific layer component events occur.
|
||||
*/
|
||||
class EditorLayerComponentNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; // multi listener
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; //single bus
|
||||
|
||||
/**
|
||||
* Called when a layer component is activated on a layer entity
|
||||
* \param entityId The id of the entity whose layer component has been activated.
|
||||
*/
|
||||
virtual void OnLayerComponentActivated(AZ::EntityId entityId) = 0;
|
||||
/**
|
||||
* Called when a layer component is deactivated on a layer entity
|
||||
* \param entityId The id of the entity whose layer component has been deactivated.
|
||||
*/
|
||||
virtual void OnLayerComponentDeactivated(AZ::EntityId entityId) = 0;
|
||||
};
|
||||
using EditorLayerComponentNotificationBus = AZ::EBus<EditorLayerComponentNotifications>;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-7
@@ -13,6 +13,7 @@
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
@@ -43,6 +44,7 @@ namespace AzToolsFramework
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_scale, "Non-uniform Scale",
|
||||
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
|
||||
->Attribute(AZ::Edit::Attributes::Min, AZ::MinNonUniformScale)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNonUniformScaleComponent::OnScaleChanged)
|
||||
;
|
||||
}
|
||||
@@ -56,7 +58,6 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorNonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("SkyCloudService"));
|
||||
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
|
||||
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
|
||||
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
|
||||
@@ -72,8 +73,6 @@ namespace AzToolsFramework
|
||||
incompatible.push_back(AZ_CRC_CE("PhysXShapeColliderService"));
|
||||
incompatible.push_back(AZ_CRC_CE("PhysXCharacterControllerService"));
|
||||
incompatible.push_back(AZ_CRC_CE("PhysXRagdollService"));
|
||||
incompatible.push_back(AZ_CRC_CE("TouchBendingPhysicsService"));
|
||||
incompatible.push_back(AZ_CRC_CE("WaterVolumeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("WhiteBoxService"));
|
||||
incompatible.push_back(AZ_CRC_CE("NavigationAreaService"));
|
||||
incompatible.push_back(AZ_CRC_CE("GeometryService"));
|
||||
@@ -81,12 +80,9 @@ namespace AzToolsFramework
|
||||
incompatible.push_back(AZ_CRC_CE("CompoundShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("CylinderShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("DiskShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("FixedVertexContainerService"));
|
||||
incompatible.push_back(AZ_CRC_CE("PolygonPrismShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("SphereShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("SplineService"));
|
||||
incompatible.push_back(AZ_CRC_CE("TubeShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("VariableVertexContainerService"));
|
||||
}
|
||||
|
||||
void EditorNonUniformScaleComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
@@ -113,7 +109,18 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorNonUniformScaleComponent::SetScale(const AZ::Vector3& scale)
|
||||
{
|
||||
m_scale = scale;
|
||||
if (scale.GetMinElement() >= AZ::MinNonUniformScale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::Vector3 clampedScale = scale.GetMax(AZ::Vector3(AZ::MinNonUniformScale));
|
||||
AZ_Warning("Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
|
||||
AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str());
|
||||
m_scale = clampedScale;
|
||||
}
|
||||
m_scaleChangedEvent.Signal(m_scale);
|
||||
}
|
||||
|
||||
void EditorNonUniformScaleComponent::RegisterScaleChangedEvent(AZ::NonUniformScaleChangedEvent::Handler& handler)
|
||||
|
||||
+23
-13
@@ -27,6 +27,7 @@
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformScalePropertyHandler.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
@@ -163,7 +164,6 @@ namespace AzToolsFramework
|
||||
, m_parentActivationTransformMode(AZ::TransformConfig::ParentActivationTransformMode::MaintainOriginalRelativeTransform)
|
||||
, m_cachedWorldTransform(AZ::Transform::Identity())
|
||||
, m_suppressTransformChangedEvent(false)
|
||||
, m_netSyncEnabled(false)
|
||||
, m_interpolatePosition(AZ::InterpolationMode::NoInterpolation)
|
||||
, m_interpolateRotation(AZ::InterpolationMode::NoInterpolation)
|
||||
{
|
||||
@@ -221,6 +221,26 @@ namespace AzToolsFramework
|
||||
EditorComponentBase::Deactivate();
|
||||
}
|
||||
|
||||
void TransformComponent::BindTransformChangedEventHandler(AZ::TransformChangedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_transformChangedEvent);
|
||||
}
|
||||
|
||||
void TransformComponent::BindParentChangedEventHandler(AZ::ParentChangedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_parentChangedEvent);
|
||||
}
|
||||
|
||||
void TransformComponent::BindChildChangedEventHandler(AZ::ChildChangedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_childChangedEvent);
|
||||
}
|
||||
|
||||
void TransformComponent::NotifyChildChangedEvent(AZ::ChildChangeType changeType, AZ::EntityId entityId)
|
||||
{
|
||||
m_childChangedEvent.Signal(changeType, entityId);
|
||||
}
|
||||
|
||||
// This is called when our transform changes directly, or our parent's has changed.
|
||||
void TransformComponent::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
|
||||
{
|
||||
@@ -278,16 +298,6 @@ namespace AzToolsFramework
|
||||
m_cachedWorldTransformParent = AZ::EntityId();
|
||||
}
|
||||
|
||||
bool TransformComponent::IsPositionInterpolated()
|
||||
{
|
||||
return m_interpolatePosition != AZ::InterpolationMode::NoInterpolation;
|
||||
}
|
||||
|
||||
bool TransformComponent::IsRotationInterpolated()
|
||||
{
|
||||
return m_interpolateRotation != AZ::InterpolationMode::NoInterpolation;
|
||||
}
|
||||
|
||||
void TransformComponent::CheckApplyCachedWorldTransform(const AZ::Transform& parentWorld)
|
||||
{
|
||||
if (m_parentEntityId != m_cachedWorldTransformParent)
|
||||
@@ -835,6 +845,7 @@ namespace AzToolsFramework
|
||||
// This is for Create Entity as child / Drag+drop parent update / add component
|
||||
EBUS_EVENT(AzToolsFramework::ToolsApplicationEvents::Bus, EntityParentChanged, GetEntityId(), parentId, oldParentId);
|
||||
EBUS_EVENT_ID(GetEntityId(), AZ::TransformNotificationBus, OnParentChanged, oldParentId, parentId);
|
||||
m_parentChangedEvent.Signal(oldParentId, parentId);
|
||||
|
||||
TransformChanged();
|
||||
}
|
||||
@@ -1136,7 +1147,6 @@ namespace AzToolsFramework
|
||||
{
|
||||
AZ::TransformConfig configuration;
|
||||
configuration.m_parentId = m_parentEntityId;
|
||||
configuration.m_netSyncEnabled = m_netSyncEnabled;
|
||||
configuration.m_worldTransform = GetWorldTM();
|
||||
configuration.m_localTransform = GetLocalTM();
|
||||
configuration.m_parentActivationTransformMode = m_parentActivationTransformMode;
|
||||
@@ -1241,7 +1251,7 @@ namespace AzToolsFramework
|
||||
Attribute(AZ::Edit::Attributes::Suffix, " deg")->
|
||||
Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)->
|
||||
Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
|
||||
DataElement(AZ::Edit::UIHandlers::Default, &EditorTransform::m_scale, "Scale", "Local Scale")->
|
||||
DataElement(TransformScaleHandler, &EditorTransform::m_scale, "Scale", "Local Scale")->
|
||||
Attribute(AZ::Edit::Attributes::Step, 0.1f)->
|
||||
Attribute(AZ::Edit::Attributes::Min, 0.01f)->
|
||||
Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user