diff --git a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
index 1b7dfdf40d..b82c482c4f 100644
--- a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
+++ b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
@@ -145,7 +145,7 @@
-
+
diff --git a/Assets/Engine/Entities/GeomCache.ent b/Assets/Engine/Entities/GeomCache.ent
deleted file mode 100644
index e7a63190c3..0000000000
--- a/Assets/Engine/Entities/GeomCache.ent
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cf441215a769562f88aa20711aee68dadcbf02597d1e2270547055e8e6aec6a3
-size 77
diff --git a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua b/Assets/Engine/Scripts/Entities/Render/GeomCache.lua
deleted file mode 100644
index b496aecd8d..0000000000
--- a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua
+++ /dev/null
@@ -1,178 +0,0 @@
-----------------------------------------------------------------------------------------------------
---
--- Copyright (c) Contributors to the Open 3D Engine Project.
--- For complete copyright and license terms please see the LICENSE at the root of this distribution.
---
--- SPDX-License-Identifier: Apache-2.0 OR MIT
---
---
---
-----------------------------------------------------------------------------------------------------
-Script.ReloadScript("scripts/Utils/EntityUtils.lua")
-
-GeomCache =
-{
- Properties = {
- geomcacheFile = "EngineAssets/GeomCaches/defaultGeomCache.cax",
- bPlaying = 0,
- fStartTime = 0,
- bLooping = 0,
- objectStandIn = "",
- materialStandInMaterial = "",
- objectFirstFrameStandIn = "",
- materialFirstFrameStandInMaterial = "",
- objectLastFrameStandIn = "",
- materialLastFrameStandInMaterial = "",
- fStandInDistance = 0,
- fStreamInDistance = 0,
- Physics = {
- bPhysicalize = 0,
- }
- },
-
- Editor={
- Icon = "animobject.bmp",
- IconOnTop = 1,
- },
-
- bPlaying = 0,
- currentTime = 0,
- precacheTime = 0,
- bPrecachedOutputTriggered = false,
-}
-
-function GeomCache:OnLoad(table)
- self.currentTime = table.currentTime;
-end
-
-function GeomCache:OnSave(table)
- table.currentTime = self.currentTime;
-end
-
-function GeomCache:OnSpawn()
- self.currentTime = self.Properties.fStartTime;
- self:SetFromProperties();
-end
-
-function GeomCache:OnReset()
- self.currentTime = self.Properties.fStartTime;
- self.bPrecachedOutputTriggered = true;
- self:SetFromProperties();
-end
-
-function GeomCache:SetFromProperties()
- local Properties = self.Properties;
-
- if (Properties.geomcacheFile == "") then
- do return end;
- end
-
- self:LoadGeomCache(0, Properties.geomcacheFile);
-
- self.bPlaying = Properties.bPlaying;
- if (self.bPlaying == 0) then
- self.currentTime = Properties.fStartTime;
- end
-
- self:SetGeomCachePlaybackTime(self.currentTime);
- self:SetGeomCacheParams(Properties.bLooping, Properties.objectStandIn, Properties.materialStandInMaterial, Properties.objectFirstFrameStandIn,
- Properties.materialFirstFrameStandInMaterial, Properties.objectLastFrameStandIn, Properties.materialLastFrameStandInMaterial,
- Properties.fStandInDistance, Properties.fStreamInDistance);
- self:SetGeomCacheStreaming(false, 0);
-
- if (Properties.Physics.bPhysicalize == 1) then
- local tempPhysParams = EntityCommon.TempPhysParams;
- self:Physicalize(0, PE_ARTICULATED, tempPhysParams);
- end
-
- self:Activate(1);
-end
-
-function GeomCache:PhysicalizeThis()
- local Physics = self.Properties.Physics;
- EntityCommon.PhysicalizeRigid(self, 0, Physics, false);
-end
-
-function GeomCache:OnUpdate(dt)
- if (self.bPlaying == 1) then
- self:SetGeomCachePlaybackTime(self.currentTime);
- end
-
- if (self:IsGeomCacheStreaming() and not self.bPrecachedOutputTriggered) then
- local precachedTime = self:GetGeomCachePrecachedTime();
- if (precachedTime >= self.precacheTime) then
- self:ActivateOutput("Precached", true);
- self.bPrecachedOutputTriggered = true;
- end
- end
-
- if (self.bPlaying == 1) then
- self.currentTime = self.currentTime + dt;
- end
-end
-
-function GeomCache:OnPropertyChange()
- self:SetFromProperties();
-end
-
-function GeomCache:Event_Start(sender, val)
- self.bPlaying = 1;
-end
-
-function GeomCache:Event_Stop(sender, value)
- self.bPlaying = 0;
-end
-
-function GeomCache:Event_SetTime(sender, value)
- self.currentTime = value;
-end
-
-function GeomCache:Event_StartStreaming(sender, value)
- self.bPrecachedOutputTriggered = false;
- self:SetGeomCacheStreaming(true, self.currentTime);
-end
-
-function GeomCache:Event_StopStreaming(sender, value)
- self:SetGeomCacheStreaming(false, 0);
-end
-
-function GeomCache:Event_PrecacheTime(sender, value)
- self.precacheTime = value;
-end
-
-function GeomCache:Event_Hide(sender, value)
- self:Hide(1);
-end
-
-function GeomCache:Event_Unhide(sender, value)
- self:Hide(0);
-end
-
-function GeomCache:Event_StopDrawing(sender, value)
- self:SetGeomCacheDrawing(false);
-end
-
-function GeomCache:Event_StartDrawing(sender, value)
- self:SetGeomCacheDrawing(true);
-end
-
-GeomCache.FlowEvents =
-{
- Inputs =
- {
- Start = { GeomCache.Event_Start, "any" },
- Stop = { GeomCache.Event_Stop, "any" },
- SetTime = { GeomCache.Event_SetTime, "float" },
- StartStreaming = { GeomCache.Event_StartStreaming, "any" },
- StopStreaming = { GeomCache.Event_StopStreaming, "any" },
- PrecacheTime = { GeomCache.Event_PrecacheTime, "float" },
- Hide = { GeomCache.Event_Hide, "any" },
- Unhide = { GeomCache.Event_Unhide, "any" },
- StopDrawing = { GeomCache.Event_StopDrawing, "any" },
- StartDrawing = { GeomCache.Event_StartDrawing, "any" },
- },
- Outputs =
- {
- Precached = "bool",
- },
-}
diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo
rename to AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo
diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo
rename to AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index 0ea22e8ce3..0b40390a18 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -1362,16 +1362,6 @@ void CCryEditApp::CompileCriticalAssets() const
assetsInQueueNotifcation.BusDisconnect();
CCryEditApp::OutputStartupMessage(QString("Asset Processor is now ready."));
- // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others,
- // so that by the time we ask for them there is a greater likelihood that they're already good to go.
- // these can be loaded later but are still important:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects");
-
- // some are specifically extra important and will cause issues if missing completely:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf");
}
bool CCryEditApp::ConnectToAssetProcessor() const
diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h
index 4d5f6e23c4..036a0bc5ee 100644
--- a/Code/Editor/Include/IFileUtil.h
+++ b/Code/Editor/Include/IFileUtil.h
@@ -60,7 +60,6 @@ struct IFileUtil
EFILE_TYPE_GEOMETRY,
EFILE_TYPE_TEXTURE,
EFILE_TYPE_SOUND,
- EFILE_TYPE_GEOMCACHE,
EFILE_TYPE_LAST,
};
diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp
index 6e2354998c..b2dfc04102 100644
--- a/Code/Editor/Objects/EntityObject.cpp
+++ b/Code/Editor/Objects/EntityObject.cpp
@@ -956,11 +956,7 @@ void CEntityObject::Serialize(CObjectArchive& ar)
QString attachmentType;
xmlNode->getAttr("AttachmentType", attachmentType);
- if (attachmentType == "GeomCacheNode")
- {
- m_attachmentType = eAT_GeomCacheNode;
- }
- else if (attachmentType == "CharacterBone")
+ if (attachmentType == "CharacterBone")
{
m_attachmentType = eAT_CharacterBone;
}
@@ -987,11 +983,7 @@ void CEntityObject::Serialize(CObjectArchive& ar)
{
if (m_attachmentType != eAT_Pivot)
{
- if (m_attachmentType == eAT_GeomCacheNode)
- {
- xmlNode->setAttr("AttachmentType", "GeomCacheNode");
- }
- else if (m_attachmentType == eAT_CharacterBone)
+ if (m_attachmentType == eAT_CharacterBone)
{
xmlNode->setAttr("AttachmentType", "CharacterBone");
}
@@ -1091,11 +1083,7 @@ XmlNodeRef CEntityObject::Export([[maybe_unused]] const QString& levelPath, XmlN
objNode->setAttr("ParentId", parentEntity->GetEntityId());
if (m_attachmentType != eAT_Pivot)
{
- if (m_attachmentType == eAT_GeomCacheNode)
- {
- objNode->setAttr("AttachmentType", "GeomCacheNode");
- }
- else if (m_attachmentType == eAT_CharacterBone)
+ if (m_attachmentType == eAT_CharacterBone)
{
objNode->setAttr("AttachmentType", "CharacterBone");
}
diff --git a/Code/Editor/Objects/EntityObject.h b/Code/Editor/Objects/EntityObject.h
index dcc6ff7b22..a4f4752b75 100644
--- a/Code/Editor/Objects/EntityObject.h
+++ b/Code/Editor/Objects/EntityObject.h
@@ -131,7 +131,6 @@ public:
enum EAttachmentType
{
eAT_Pivot,
- eAT_GeomCacheNode,
eAT_CharacterBone,
};
diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp
index ee7e9a8e96..265d828481 100644
--- a/Code/Editor/Objects/ObjectManager.cpp
+++ b/Code/Editor/Objects/ObjectManager.cpp
@@ -608,7 +608,7 @@ bool CObjectManager::AddObject(CBaseObject* obj)
if (CEntityObject* entityObj = qobject_cast(obj))
{
CEntityObject::EAttachmentType attachType = entityObj->GetAttachType();
- if (attachType == CEntityObject::EAttachmentType::eAT_GeomCacheNode || attachType == CEntityObject::EAttachmentType::eAT_CharacterBone)
+ if (attachType == CEntityObject::EAttachmentType::eAT_CharacterBone)
{
m_animatedAttachedEntities.insert(entityObj);
}
diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
index 94451e6914..5943e3c2d7 100644
--- a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
+++ b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -47,18 +48,42 @@ namespace TrackView
AZ::Name viewName = AZ::Name("MainCamera");
m_view = AZ::RPI::View::CreateView(viewName, AZ::RPI::View::UsageCamera);
m_renderPipeline->SetDefaultView(m_view);
+ m_targetView = scene.GetDefaultRenderPipeline()->GetDefaultView();
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor())
+ {
+ // This will be set again to mimic the active camera in UpdateView
+ fp->SetViewAlias(m_view, m_targetView);
+ }
}
void AtomOutputFrameCapture::DestroyPipeline(AZ::RPI::Scene& scene)
{
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor())
+ {
+ // Remove view alias introduced in CreatePipeline and UpdateView
+ fp->RemoveViewAlias(m_view);
+ }
scene.RemoveRenderPipeline(m_renderPipeline->GetId());
m_passHierarchy.clear();
m_renderPipeline.reset();
m_view.reset();
+ m_targetView.reset();
}
- void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection)
+ void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView)
{
+ if (targetView && targetView != m_targetView)
+ {
+ if (AZ::RPI::Scene* scene = SceneFromGameEntityContext())
+ {
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor())
+ {
+ fp->SetViewAlias(m_view, targetView);
+ m_targetView = targetView;
+ }
+ }
+ }
+
m_view->SetCameraTransform(cameraTransform);
m_view->SetViewToClipMatrix(cameraProjection);
}
diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.h b/Code/Editor/TrackView/AtomOutputFrameCapture.h
index 2686a81c99..4719ab08e5 100644
--- a/Code/Editor/TrackView/AtomOutputFrameCapture.h
+++ b/Code/Editor/TrackView/AtomOutputFrameCapture.h
@@ -39,11 +39,12 @@ namespace TrackView
CaptureFinishedCallback captureFinishedCallback);
//! Update the internal view that is associated with the created pipeline.
- void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection);
+ void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView = nullptr);
private:
AZ::RPI::RenderPipelinePtr m_renderPipeline; //!< The internal render pipeline.
AZ::RPI::ViewPtr m_view; //!< The view associated with the render pipeline.
+ AZ::RPI::ViewPtr m_targetView; //!< The view that this render pipeline will mimic.
AZStd::vector m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain).
CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished.
diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
index d7901e338a..a796a8ce37 100644
--- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
+++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include
// Qt
#include
@@ -91,9 +92,12 @@ namespace
static void UpdateAtomOutputFrameCaptureView(TrackView::AtomOutputFrameCapture& atomOutputFrameCapture, const int width, const int height)
{
const AZ::EntityId activeCameraEntityId = TrackView::ActiveCameraEntityId();
+ AZ::RPI::ViewPtr view = nullptr;
+ AZ::RPI::ViewProviderBus::EventResult(view, activeCameraEntityId, &AZ::RPI::ViewProvider::GetView);
atomOutputFrameCapture.UpdateView(
TrackView::TransformFromEntityId(activeCameraEntityId),
- TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, static_cast(width), static_cast(height)));
+ TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, aznumeric_cast(width), aznumeric_cast(height)),
+ view);
}
CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pParent /* = nullptr */)
diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp
index 36c1879407..9f96d45381 100644
--- a/Code/Editor/Util/FileUtil.cpp
+++ b/Code/Editor/Util/FileUtil.cpp
@@ -54,8 +54,8 @@
#include
#endif
-bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true };
-bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true };
+bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true };
+bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true };
CAutoRestorePrimaryCDRoot::~CAutoRestorePrimaryCDRoot()
{
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.h b/Code/Framework/AzCore/AzCore/Math/Vector3.h
index 821dc8292c..6b7c53266d 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.h
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.h
@@ -100,7 +100,7 @@ namespace AZ
void Set(float x, float y, float z);
//! Sets components from an array of 3 floats in xyz order.
- void Set(float values[]);
+ void Set(const float values[]);
//! Indexed access using operator(), just for convenience.
float operator()(int32_t index) const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.inl b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
index 879ade38cf..6371c688b8 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
@@ -186,7 +186,7 @@ namespace AZ
}
- AZ_MATH_INLINE void Vector3::Set(float values[])
+ AZ_MATH_INLINE void Vector3::Set(const float values[])
{
m_value = Simd::Vec3::LoadImmediate(values[0], values[1], values[2]);
}
diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
index 3047a2894e..6cba54a17f 100644
--- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
+++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
@@ -50,7 +50,12 @@ namespace AZ
if (!s_instance)
{
- s_instance = Environment::FindVariable(NameDictionaryInstanceName);
+ // Because the NameDictionary allocates memory using the AZ::Allocator and it is created
+ // in the executable memory space, it's ownership cannot be transferred to other module memory spaces
+ // Otherwise this could cause the the NameDictionary to be destroyed in static de-init
+ // after the AZ::Allocators have been destroyed
+ // Therefore we supply the isTransferOwnership value of false using CreateVariableEx
+ s_instance = AZ::Environment::CreateVariableEx(NameDictionaryInstanceName, true, false);
}
return s_instance.IsConstructed();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
index 8098727177..5b51944a75 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
@@ -175,20 +175,14 @@ namespace AzToolsFramework::Prefab
m_focusedInstance = focusedInstance;
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
- AZ::EntityId containerEntityId;
-
- if (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
- {
- containerEntityId = focusedInstance->get().GetContainerEntityId();
- }
- else
- {
- containerEntityId = AZ::EntityId();
- }
-
// Focus on the descendants of the container entity in the Editor, if the interface is initialized.
if (m_focusModeInterface)
{
+ const AZ::EntityId containerEntityId =
+ (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
+ ? focusedInstance->get().GetContainerEntityId()
+ : AZ::EntityId();
+
m_focusModeInterface->SetFocusRoot(containerEntityId);
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
index a449fa0055..29bc106eed 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
#include
#include
#include
+#include
#include
#include
#include
@@ -894,25 +895,51 @@ namespace AzToolsFramework
{
if (!m_prefabsAreEnabled)
{
- return m_isLevelEntityEditor ? InspectorLayout::LEVEL : InspectorLayout::ENTITY;
+ return m_isLevelEntityEditor ? InspectorLayout::Level : InspectorLayout::Entity;
}
+ // Prefabs layout logic
+
+ // If this is the container entity for the root instance, treat it like a level entity.
AZ::EntityId levelContainerEntityId = m_prefabPublicInterface->GetLevelInstanceContainerEntityId();
if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), levelContainerEntityId) != m_selectedEntityIds.end())
{
if (m_selectedEntityIds.size() > 1)
{
- return InspectorLayout::INVALID;
+ return InspectorLayout::Invalid;
}
else
{
- return InspectorLayout::LEVEL;
+ return InspectorLayout::Level;
}
}
else
{
- return InspectorLayout::ENTITY;
+ // If this is the container entity for the currently focused prefab, utilize a separate layout.
+ if (auto prefabFocusPublicInterface = AZ::Interface::Get())
+ {
+ AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+ EditorEntityContextRequestBus::BroadcastResult(
+ editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
+
+ AZ::EntityId focusedPrefabContainerEntityId =
+ prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
+ if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), focusedPrefabContainerEntityId) !=
+ m_selectedEntityIds.end())
+ {
+ if (m_selectedEntityIds.size() > 1)
+ {
+ return InspectorLayout::Invalid;
+ }
+ else
+ {
+ return InspectorLayout::ContainerEntityOfFocusedPrefab;
+ }
+ }
+ }
}
+
+ return InspectorLayout::Entity;
}
void EntityPropertyEditor::UpdateEntityDisplay()
@@ -921,7 +948,7 @@ namespace AzToolsFramework
InspectorLayout layout = GetCurrentInspectorLayout();
- if (layout == InspectorLayout::LEVEL)
+ if (!m_prefabsAreEnabled && layout == InspectorLayout::Level)
{
AZStd::string levelName;
AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName);
@@ -963,14 +990,19 @@ namespace AzToolsFramework
InspectorLayout layout = GetCurrentInspectorLayout();
- if (layout == InspectorLayout::LEVEL)
+ if (layout == InspectorLayout::Level)
{
// The Level Inspector should only have a list of selectable components after the
// level entity itself is valid (i.e. "selected").
return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::LevelEntity;
}
- if (layout == InspectorLayout::INVALID)
+ if (layout == InspectorLayout::ContainerEntityOfFocusedPrefab)
+ {
+ return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab;
+ }
+
+ if (layout == InspectorLayout::Invalid)
{
return SelectionEntityTypeInfo::Mixed;
}
@@ -1140,7 +1172,8 @@ namespace AzToolsFramework
}
}
- bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::LEVEL;
+ bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::Level;
+ bool isContainerOfFocusedPrefabLayout = GetCurrentInspectorLayout() == InspectorLayout::ContainerEntityOfFocusedPrefab;
m_gui->m_entityDetailsLabel->setText(entityDetailsLabelText);
m_gui->m_entityDetailsLabel->setVisible(entityDetailsVisible);
@@ -1148,10 +1181,14 @@ namespace AzToolsFramework
m_gui->m_entityNameLabel->setVisible(hasEntitiesDisplayed);
m_gui->m_entityIcon->setVisible(hasEntitiesDisplayed);
m_gui->m_pinButton->setVisible(m_overrideSelectedEntityIds.empty() && hasEntitiesDisplayed && !m_isSystemEntityEditor);
- m_gui->m_statusLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_statusComboBox->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_entityIdLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_entityIdText->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_statusLabel->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_statusComboBox->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_entityIdLabel->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_entityIdText->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
bool displayComponentSearchBox = hasEntitiesDisplayed;
if (hasEntitiesDisplayed)
@@ -1159,7 +1196,9 @@ namespace AzToolsFramework
// Build up components to display
SharedComponentArray sharedComponentArray;
BuildSharedComponentArray(sharedComponentArray,
- !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities || selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities));
+ !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities ||
+ selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities) ||
+ selectionEntityTypeInfo == SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab);
if (sharedComponentArray.size() == 0)
{
@@ -1175,7 +1214,8 @@ namespace AzToolsFramework
UpdateEntityDisplay();
}
- m_gui->m_darkBox->setVisible(displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_darkBox->setVisible(
+ displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout && !isContainerOfFocusedPrefabLayout);
m_gui->m_entitySearchBox->setVisible(displayComponentSearchBox);
bool displayAddComponentMenu = CanAddComponentsToSelection(selectionEntityTypeInfo);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
index 5279cefa9f..8dd0ffc4ee 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
@@ -354,7 +354,8 @@ namespace AzToolsFramework
OnlyLayerEntities,
OnlyPrefabEntities,
Mixed,
- LevelEntity
+ LevelEntity,
+ ContainerEntityOfFocusedPrefab
};
/**
* Returns what kinds of entities are in the current selection. This is used because mixed selection
@@ -364,7 +365,7 @@ namespace AzToolsFramework
SelectionEntityTypeInfo GetSelectionEntityTypeInfo(const EntityIdList& selection) const;
/**
- * Returns true if a selection matching the passed in selection informatation allows components to be added.
+ * Returns true if a selection matching the passed in selection information allows components to be added.
*/
bool CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const;
@@ -581,9 +582,10 @@ namespace AzToolsFramework
enum class InspectorLayout
{
- ENTITY = 0, // All selected entities are regular entities
- LEVEL, // The selected entity is the level prefab container entity
- INVALID // Other entities are selected alongside the level prefab container entity
+ Entity = 0, // All selected entities are regular entities.
+ Level, // The selected entity is the prefab container entity for the level prefab, or the slice level entity.
+ ContainerEntityOfFocusedPrefab, // The selected entity is the prefab container entity for the focused prefab.
+ Invalid // Other entities are selected alongside the level prefab container entity.
};
InspectorLayout GetCurrentInspectorLayout() const;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
index 39c882b766..c16a458be7 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1177,8 +1178,10 @@ namespace AzToolsFramework
continue;
}
- const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo);
- debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax());
+ if (const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); bound.IsValid())
+ {
+ debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax());
+ }
}
debugDisplay.DepthTestOn();
@@ -1334,39 +1337,6 @@ namespace AzToolsFramework
EndRecordManipulatorCommand();
});
- // surface
- translationManipulators->InstallSurfaceManipulatorMouseDownCallback(
- [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
- {
- BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
-
- InitializeTranslationLookup(m_entityIdManipulators);
-
- m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
- m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
-
- // [ref 1.]
- BeginRecordManipulatorCommand();
- });
-
- translationManipulators->InstallSurfaceManipulatorMouseMoveCallback(
- [this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable
- {
- UpdateTranslationManipulator(
- action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
- m_transformChangedInternally, m_spaceCluster.m_spaceLock);
- });
-
- translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
- [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
- {
- AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
- &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
- manipulatorEntityIds->m_entityIds);
-
- EndRecordManipulatorCommand();
- });
-
// transfer ownership
m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators);
}
@@ -3604,6 +3574,16 @@ namespace AzToolsFramework
m_selectedEntityIds.clear();
m_selectedEntityIds.reserve(selectedEntityIds.size());
AZStd::copy(selectedEntityIds.begin(), selectedEntityIds.end(), AZStd::inserter(m_selectedEntityIds, m_selectedEntityIds.end()));
+
+ // Do not create manipulators for the container entity of the focused prefab.
+ if (auto prefabFocusPublicInterface = AZ::Interface::Get())
+ {
+ AzFramework::EntityContextId editorEntityContextId = GetEntityContextId();
+ if (AZ::EntityId focusRoot = prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); focusRoot.IsValid())
+ {
+ m_selectedEntityIds.erase(focusRoot);
+ }
+ }
}
void EditorTransformComponentSelection::OnTransformChanged(
diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp
index 0f832ff1a5..97859a604b 100644
--- a/Code/LauncherUnified/Launcher.cpp
+++ b/Code/LauncherUnified/Launcher.cpp
@@ -369,7 +369,6 @@ namespace O3DELauncher
}
}
- void CompileCriticalAssets();
void CreateRemoteFileIO();
bool ConnectToAssetProcessor()
@@ -397,29 +396,11 @@ namespace O3DELauncher
{
AZ_TracePrintf("Launcher", "Connected to Asset Processor\n");
CreateRemoteFileIO();
- CompileCriticalAssets();
}
return connectedToAssetProcessor;
}
- //! Compiles the critical assets that are within the Engine directory of Open 3D Engine
- //! This code should be in a centralized location, but doesn't belong in AzFramework
- //! since it is specific to how Open 3D Engine projects has assets setup
- void CompileCriticalAssets()
- {
- // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others,
- // so that by the time we ask for them there is a greater likelihood that they're already good to go.
- // these can be loaded later but are still important:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects");
-
- // some are specifically extra important and will cause issues if missing completely:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf");
- }
-
//! Remote FileIO to use as a Virtual File System
//! Communication of FileIOBase operations occur through an AssetProcessor connection
void CreateRemoteFileIO()
diff --git a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
index 45d01b9b5b..8def0a698c 100644
--- a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
+++ b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
@@ -61,8 +61,12 @@ namespace AssetBundler
{
AZStd::string absolutePath = filePath.toUtf8().data();
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str()))
- {
- AZStd::string projectName = pathToProjectNameMap.at(absolutePath);
+ {
+ AZStd::string projectName;
+ if (pathToProjectNameMap.contains(absolutePath))
+ {
+ projectName = pathToProjectNameMap.at(absolutePath);
+ }
// If a project name is already specified, then the associated file is a default file
LoadFile(absolutePath, projectName, !projectName.empty());
diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
index 62b063c83b..a02eef8b75 100644
--- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
+++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
@@ -699,7 +699,6 @@ namespace AssetBuilderSDK
// XML files may contain generic data (avoid this in new builders - use a custom extension!)
static const char* xmlExtensions = ".xml";
- static const char* geomCacheExtensions = ".cax";
static const char* skeletonExtensions = ".chr";
static AZ::Data::AssetType unknownAssetType = AZ::Data::AssetType::CreateNull();
@@ -710,7 +709,6 @@ namespace AssetBuilderSDK
static AZ::Data::AssetType textureMipsAssetType("{3918728C-D3CA-4D9E-813E-A5ED20C6821E}");
static AZ::Data::AssetType skinnedMeshLodsAssetType("{58E5824F-C27B-46FD-AD48-865BA41B7A51}");
static AZ::Data::AssetType staticMeshLodsAssetType("{9AAE4926-CB6A-4C60-9948-A1A22F51DB23}");
- static AZ::Data::AssetType geomCacheAssetType("{EBC96071-E960-41B6-B3E3-328F515AE5DA}");
static AZ::Data::AssetType skeletonAssetType("{60161B46-21F0-4396-A4F0-F2CCF0664CDE}");
static AZ::Data::AssetType entityIconAssetType("{3436C30E-E2C5-4C3B-A7B9-66C94A28701B}");
@@ -822,11 +820,6 @@ namespace AssetBuilderSDK
return skinnedMeshAssetType;
}
- if (AzFramework::StringFunc::Find(geomCacheExtensions, extension.c_str()) != AZStd::string::npos)
- {
- return geomCacheAssetType;
- }
-
if (AzFramework::StringFunc::Find(skeletonExtensions, extension.c_str()) != AZStd::string::npos)
{
return skeletonAssetType;
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 8dd7e4c9b5..2260ae62b9 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -41,5 +41,6 @@
Download.svg
in_progress.gif
gem.svg
+ checkmark.svg
diff --git a/Code/Tools/ProjectManager/Resources/checkmark.svg b/Code/Tools/ProjectManager/Resources/checkmark.svg
new file mode 100644
index 0000000000..d612b35370
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/checkmark.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp
index 6326b2fc11..06e51b5116 100644
--- a/Code/Tools/ProjectManager/Source/DownloadController.cpp
+++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp
@@ -18,7 +18,6 @@ namespace O3DE::ProjectManager
{
DownloadController::DownloadController(QWidget* parent)
: QObject()
- , m_lastProgress(0)
, m_parent(parent)
{
m_worker = new DownloadWorker();
@@ -69,10 +68,9 @@ namespace O3DE::ProjectManager
}
}
- void DownloadController::UpdateUIProgress(int progress)
+ void DownloadController::UpdateUIProgress(int bytesDownloaded, int totalBytes)
{
- m_lastProgress = progress;
- emit GemDownloadProgress(m_gemNames.front(), progress);
+ emit GemDownloadProgress(m_gemNames.front(), bytesDownloaded, totalBytes);
}
void DownloadController::HandleResults(const QString& result)
@@ -88,6 +86,7 @@ namespace O3DE::ProjectManager
QString gemName = m_gemNames.front();
m_gemNames.erase(m_gemNames.begin());
emit Done(gemName, succeeded);
+ emit GemDownloadRemoved(gemName);
if (!m_gemNames.empty())
{
diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h
index 0bf0ae473c..211d9b48bc 100644
--- a/Code/Tools/ProjectManager/Source/DownloadController.h
+++ b/Code/Tools/ProjectManager/Source/DownloadController.h
@@ -53,7 +53,7 @@ namespace O3DE::ProjectManager
}
}
public slots:
- void UpdateUIProgress(int progress);
+ void UpdateUIProgress(int bytesDownloaded, int totalBytes);
void HandleResults(const QString& result);
signals:
@@ -61,14 +61,12 @@ namespace O3DE::ProjectManager
void Done(const QString& gemName, bool success = true);
void GemDownloadAdded(const QString& gemName);
void GemDownloadRemoved(const QString& gemName);
- void GemDownloadProgress(const QString& gemName, int percentage);
+ void GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes);
private:
DownloadWorker* m_worker;
QThread m_workerThread;
QWidget* m_parent;
AZStd::vector m_gemNames;
-
- int m_lastProgress;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/DownloadWorker.cpp b/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
index a71a8dd486..560bfe05de 100644
--- a/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
+++ b/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
@@ -20,10 +20,9 @@ namespace O3DE::ProjectManager
void DownloadWorker::StartDownload()
{
- auto gemDownloadProgress = [=](int downloadProgress)
+ auto gemDownloadProgress = [=](int bytesDownloaded, int totalBytes)
{
- m_downloadProgress = downloadProgress;
- emit UpdateProgress(downloadProgress);
+ emit UpdateProgress(bytesDownloaded, totalBytes);
};
AZ::Outcome gemInfoResult =
PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress, /*force*/true);
diff --git a/Code/Tools/ProjectManager/Source/DownloadWorker.h b/Code/Tools/ProjectManager/Source/DownloadWorker.h
index 316a730a78..4084080ff7 100644
--- a/Code/Tools/ProjectManager/Source/DownloadWorker.h
+++ b/Code/Tools/ProjectManager/Source/DownloadWorker.h
@@ -31,12 +31,11 @@ namespace O3DE::ProjectManager
void SetGemToDownload(const QString& gemName, bool downloadNow = true);
signals:
- void UpdateProgress(int progress);
+ void UpdateProgress(int bytesDownloaded, int totalBytes);
void Done(QString result = "");
private:
QString m_gemName;
- int m_downloadProgress;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
index a05d32a76e..e676ba73d3 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
@@ -15,6 +15,8 @@
#include
#include
#include
+#include
+#include
namespace O3DE::ProjectManager
{
@@ -224,7 +226,6 @@ namespace O3DE::ProjectManager
connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded);
connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved);
connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress);
- connect(m_downloadController, &DownloadController::Done, this, &CartOverlayWidget::GemDownloadComplete);
}
void CartOverlayWidget::GemDownloadAdded(const QString& gemName)
@@ -288,29 +289,41 @@ namespace O3DE::ProjectManager
}
}
- void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int percentage)
+ void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes)
{
QWidget* gemToUpdate = m_downloadingListWidget->findChild(gemName);
if (gemToUpdate)
{
QLabel* progressLabel = gemToUpdate->findChild("DownloadProgressLabel");
- if (progressLabel)
- {
- progressLabel->setText(QString("%1%").arg(percentage));
- }
QProgressBar* progressBar = gemToUpdate->findChild("DownloadProgressBar");
- if (progressBar)
+
+ // totalBytes can be 0 if the server does not return a content-length for the object
+ if (totalBytes != 0)
{
- progressBar->setValue(percentage);
+ int downloadPercentage = static_cast((bytesDownloaded / static_cast(totalBytes)) * 100);
+ if (progressLabel)
+ {
+ progressLabel->setText(QString("%1%").arg(downloadPercentage));
+ }
+ if (progressBar)
+ {
+ progressBar->setValue(downloadPercentage);
+ }
+ }
+ else
+ {
+ if (progressLabel)
+ {
+ progressLabel->setText(QLocale::system().formattedDataSize(bytesDownloaded));
+ }
+ if (progressBar)
+ {
+ progressBar->setRange(0, 0);
+ }
}
}
}
- void CartOverlayWidget::GemDownloadComplete(const QString& gemName, bool /*success*/)
- {
- GemDownloadRemoved(gemName); // update the list to remove the gem that has finished
- }
-
QVector CartOverlayWidget::GetTagsFromModelIndices(const QVector& gems) const
{
QVector tags;
@@ -389,7 +402,7 @@ namespace O3DE::ProjectManager
{
const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
- if (toBeAdded.isEmpty() && toBeRemoved.isEmpty())
+ if (toBeAdded.isEmpty() && toBeRemoved.isEmpty() && m_downloadController->IsDownloadQueueEmpty())
{
return;
}
@@ -430,6 +443,7 @@ namespace O3DE::ProjectManager
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, DownloadController* downloadController, QWidget* parent)
: QFrame(parent)
+ , m_downloadController(downloadController)
{
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setAlignment(Qt::AlignLeft);
@@ -456,8 +470,25 @@ namespace O3DE::ProjectManager
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
hLayout->addSpacerItem(new QSpacerItem(75, 0, QSizePolicy::Fixed));
- CartButton* cartButton = new CartButton(gemModel, downloadController);
- hLayout->addWidget(cartButton);
+ // spinner
+ m_downloadSpinnerMovie = new QMovie(":/in_progress.gif");
+ m_downloadSpinner = new QLabel(this);
+ m_downloadSpinner->setScaledContents(true);
+ m_downloadSpinner->setMaximumSize(16, 16);
+ m_downloadSpinner->setMovie(m_downloadSpinnerMovie);
+ hLayout->addWidget(m_downloadSpinner);
+ hLayout->addSpacing(8);
+
+ // downloading label
+ m_downloadLabel = new QLabel(tr("Downloading"));
+ hLayout->addWidget(m_downloadLabel);
+ m_downloadSpinner->hide();
+ m_downloadLabel->hide();
+
+ hLayout->addSpacing(16);
+
+ m_cartButton = new CartButton(gemModel, downloadController);
+ hLayout->addWidget(m_cartButton);
hLayout->addSpacing(16);
// Separating line
@@ -480,6 +511,27 @@ namespace O3DE::ProjectManager
gemMenuButton->setIcon(QIcon(":/menu.svg"));
gemMenuButton->setIconSize(QSize(36, 24));
hLayout->addWidget(gemMenuButton);
+
+ connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &GemCatalogHeaderWidget::GemDownloadAdded);
+ connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &GemCatalogHeaderWidget::GemDownloadRemoved);
+ }
+
+ void GemCatalogHeaderWidget::GemDownloadAdded(const QString& /*gemName*/)
+ {
+ m_downloadSpinner->show();
+ m_downloadLabel->show();
+ m_downloadSpinnerMovie->start();
+ m_cartButton->ShowOverlay();
+ }
+
+ void GemCatalogHeaderWidget::GemDownloadRemoved(const QString& /*gemName*/)
+ {
+ if (m_downloadController->IsDownloadQueueEmpty())
+ {
+ m_downloadSpinner->hide();
+ m_downloadLabel->hide();
+ m_downloadSpinnerMovie->stop();
+ }
}
void GemCatalogHeaderWidget::ReinitForProject()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
index fb833b85ca..5174fde57d 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
@@ -24,6 +24,7 @@ QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
QT_FORWARD_DECLARE_CLASS(QHideEvent)
QT_FORWARD_DECLARE_CLASS(QMoveEvent)
+QT_FORWARD_DECLARE_CLASS(QMovie)
namespace O3DE::ProjectManager
{
@@ -39,8 +40,7 @@ namespace O3DE::ProjectManager
public slots:
void GemDownloadAdded(const QString& gemName);
void GemDownloadRemoved(const QString& gemName);
- void GemDownloadProgress(const QString& gemName, int percentage);
- void GemDownloadComplete(const QString& gemName, bool success);
+ void GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes);
private:
QVector GetTagsFromModelIndices(const QVector& gems) const;
@@ -96,6 +96,10 @@ namespace O3DE::ProjectManager
void ReinitForProject();
+ public slots:
+ void GemDownloadAdded(const QString& gemName);
+ void GemDownloadRemoved(const QString& gemName);
+
signals:
void AddGem();
void OpenGemsRepo();
@@ -104,5 +108,10 @@ namespace O3DE::ProjectManager
private:
AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr;
inline constexpr static int s_height = 60;
+ DownloadController* m_downloadController = nullptr;
+ QLabel* m_downloadSpinner = nullptr;
+ QLabel* m_downloadLabel = nullptr;
+ QMovie* m_downloadSpinnerMovie = nullptr;
+ CartButton* m_cartButton = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
index 7004fe24d4..6abbfe16ba 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
@@ -575,7 +575,7 @@ namespace O3DE::ProjectManager
QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
if (index.isValid())
{
- m_gemModel->setData(index, GemInfo::Downloaded, GemModel::RoleDownloadStatus);
+ m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus);
m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath);
m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink);
}
@@ -585,6 +585,14 @@ namespace O3DE::ProjectManager
}
}
}
+ else
+ {
+ QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
+ if (index.isValid())
+ {
+ m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus);
+ }
+ }
}
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
index b3b29d6ee6..5c1bc90c6e 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
@@ -57,6 +57,8 @@ namespace O3DE::ProjectManager
UnknownDownloadStatus = -1,
NotDownloaded,
Downloading,
+ DownloadSuccessful,
+ DownloadFailed,
Downloaded
};
static QString GetDownloadStatusString(DownloadStatus status);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
index e15c4b3b39..dd94e42fc4 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
@@ -37,6 +37,8 @@ namespace O3DE::ProjectManager
SetStatusIcon(m_notDownloadedPixmap, ":/Download.svg");
SetStatusIcon(m_unknownStatusPixmap, ":/X.svg");
+ SetStatusIcon(m_downloadSuccessfulPixmap, ":/checkmark.svg");
+ SetStatusIcon(m_downloadFailedPixmap, ":/Warning.svg");
m_downloadingMovie = new QMovie(":/in_progress.gif");
}
@@ -480,6 +482,14 @@ namespace O3DE::ProjectManager
currentFrame = currentFrame.scaled(s_statusIconSize, s_statusIconSize);
statusPixmap = ¤tFrame;
}
+ else if (downloadStatus == GemInfo::DownloadStatus::DownloadSuccessful)
+ {
+ statusPixmap = &m_downloadSuccessfulPixmap;
+ }
+ else if (downloadStatus == GemInfo::DownloadStatus::DownloadFailed)
+ {
+ statusPixmap = &m_downloadFailedPixmap;
+ }
else if (downloadStatus == GemInfo::DownloadStatus::NotDownloaded)
{
statusPixmap = &m_notDownloadedPixmap;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
index c013be0d9e..107de6de15 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
@@ -97,6 +97,8 @@ namespace O3DE::ProjectManager
QPixmap m_unknownStatusPixmap;
QPixmap m_notDownloadedPixmap;
+ QPixmap m_downloadSuccessfulPixmap;
+ QPixmap m_downloadFailedPixmap;
QMovie* m_downloadingMovie = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index e0208a266c..d1dedaaec4 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -1215,7 +1215,8 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemInfos));
}
- AZ::Outcome PythonBindings::DownloadGem(const QString& gemName, std::function gemProgressCallback, bool force)
+ AZ::Outcome PythonBindings::DownloadGem(
+ const QString& gemName, std::function gemProgressCallback, bool force)
{
// This process is currently limited to download a single gem at a time.
bool downloadSucceeded = false;
@@ -1230,9 +1231,9 @@ namespace O3DE::ProjectManager
false, // skip auto register
force, // force overwrite
pybind11::cpp_function(
- [this, gemProgressCallback](int progress)
+ [this, gemProgressCallback](int bytesDownloaded, int totalBytes)
{
- gemProgressCallback(progress);
+ gemProgressCallback(bytesDownloaded, totalBytes);
return m_requestCancelDownload;
}) // Callback for download progress and cancelling
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h
index d258898fae..ecc6f65dc3 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.h
@@ -66,7 +66,7 @@ namespace O3DE::ProjectManager
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override;
AZ::Outcome, AZStd::string> GetAllGemRepoGemsInfos() override;
- AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback, bool force = false) override;
+ AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback, bool force = false) override;
void CancelDownload() override;
bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override;
diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
index 6c8b0c89a6..65337869fd 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
@@ -231,7 +231,7 @@ namespace O3DE::ProjectManager
* @return an outcome with a string error message on failure.
*/
virtual AZ::Outcome DownloadGem(
- const QString& gemName, std::function gemProgressCallback, bool force = false) = 0;
+ const QString& gemName, std::function gemProgressCallback, bool force = false) = 0;
/**
* Cancels the current download.
diff --git a/Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h b/Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h
similarity index 100%
rename from Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h
rename to Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h
diff --git a/Gems/AWSMetrics/Code/awsmetrics_files.cmake b/Gems/AWSMetrics/Code/awsmetrics_files.cmake
index b51235c957..b1a3a647df 100644
--- a/Gems/AWSMetrics/Code/awsmetrics_files.cmake
+++ b/Gems/AWSMetrics/Code/awsmetrics_files.cmake
@@ -8,6 +8,7 @@
set(FILES
Include/Public/AWSMetricsBus.h
+ Include/Public/MetricsAttribute.h
Include/Private/AWSMetricsConstant.h
Include/Private/AWSMetricsServiceApi.h
Include/Private/AWSMetricsSystemComponent.h
@@ -15,7 +16,6 @@ set(FILES
Include/Private/DefaultClientIdProvider.h
Include/Private/GlobalStatistics.h
Include/Private/IdentityProvider.h
- Include/Private/MetricsAttribute.h
Include/Private/MetricsEvent.h
Include/Private/MetricsEventBuilder.h
Include/Private/MetricsManager.h
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
index 2ac184e2e0..23cd76ca20 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
@@ -30,7 +30,7 @@ namespace AZ
class TransformServiceFeatureProcessor;
class RayTracingFeatureProcessor;
- class MeshDataInstance
+ class ModelDataInstance
{
friend class MeshFeatureProcessor;
friend class MeshLoader;
@@ -47,7 +47,7 @@ namespace AZ
public:
using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent;
- MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent);
+ MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent);
~MeshLoader();
ModelChangedEvent& GetModelChangedEvent();
@@ -68,7 +68,7 @@ namespace AZ
} };
MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent;
Data::Asset m_modelAsset;
- MeshDataInstance* m_parent = nullptr;
+ ModelDataInstance* m_parent = nullptr;
};
void DeInit();
@@ -99,7 +99,8 @@ namespace AZ
//! A reference to the original model asset in case it got cloned before creating the model instance.
Data::Asset m_originalModelAsset;
- Data::Instance m_shaderResourceGroup;
+ //! List of object SRGs used by meshes in this model
+ AZStd::vector> m_objectSrgList;
AZStd::unique_ptr m_meshLoader;
RPI::Scene* m_scene = nullptr;
RHI::DrawItemSortKey m_sortKey;
@@ -152,7 +153,7 @@ namespace AZ
Data::Instance GetModel(const MeshHandle& meshHandle) const override;
Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override;
- Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const override;
+ const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override;
void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override;
@@ -195,7 +196,7 @@ namespace AZ
void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override;
AZStd::concurrency_checker m_meshDataChecker;
- StableDynamicArray m_meshData;
+ StableDynamicArray m_modelData;
TransformServiceFeatureProcessor* m_transformService;
RayTracingFeatureProcessor* m_rayTracingFeatureProcessor = nullptr;
AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate;
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
index cffbe5c3c5..356b1936ca 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
@@ -20,7 +20,7 @@ namespace AZ
{
namespace Render
{
- class MeshDataInstance;
+ class ModelDataInstance;
//! Settings to apply to a mesh handle when acquiring it for the first time
struct MeshHandleDescriptor
@@ -40,7 +40,7 @@ namespace AZ
public:
AZ_RTTI(AZ::Render::MeshFeatureProcessorInterface, "{975D7F0C-2E7E-4819-94D0-D3C4E2024721}", FeatureProcessor);
- using MeshHandle = StableDynamicArrayHandle;
+ using MeshHandle = StableDynamicArrayHandle;
using ModelChangedEvent = Event>;
//! Acquires a model with an optional collection of material assignments.
@@ -61,12 +61,15 @@ namespace AZ
virtual Data::Instance GetModel(const MeshHandle& meshHandle) const = 0;
//! Gets the underlying RPI::ModelAsset for a meshHandle.
virtual Data::Asset GetModelAsset(const MeshHandle& meshHandle) const = 0;
- //! Gets the ObjectSrg for a meshHandle.
- //! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile,
- //! instead of compiling the srg directly. This way, if the srg has already been queued for compile,
- //! it will not be queued twice in the same frame. The ObjectSrg should not be updated during
+
+ //! Gets the ObjectSrgs for a meshHandle.
+ //! Updating the ObjectSrgs should be followed by a call to QueueObjectSrgForCompile,
+ //! instead of compiling the srgs directly. This way, if the srgs have already been queued for compile,
+ //! they will not be queued twice in the same frame. The ObjectSrgs should not be updated during
//! Simulate, or it will create a race between updating the data and the call to Compile
- virtual Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const = 0;
+ //! Cases where there may be multiple ObjectSrgs: if a model has multiple submeshes and those submeshes use different
+ //! materials with different object SRGs.
+ virtual const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0;
//! Queues the object srg for compile.
virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0;
//! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId.
diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
index 35e399997f..2c818d3c9b 100644
--- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
@@ -19,7 +19,7 @@ namespace UnitTest
MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&));
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&));
MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&));
- MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr(const MeshHandle&));
+ MOCK_CONST_METHOD1(GetObjectSrgs, const AZStd::vector>&(const MeshHandle&));
MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
index b6c6910fd3..410c80dbdc 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
@@ -1056,7 +1056,7 @@ namespace AZ
// if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view,
// to filter out shadows from objects that are excluded from the cubemap
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass();
- passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene
+ passFilter.SetOwnerScene(GetParentScene()); // only handles passes for this scene
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
usageFlags |= RPI::View::UsageReflectiveCubeMap;
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index 99f01ea630..112eff64a8 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -67,7 +67,7 @@ namespace AZ
m_handleGlobalShaderOptionUpdate.Disconnect();
DisableSceneNotification();
- AZ_Warning("MeshFeatureProcessor", m_meshData.size() == 0,
+ AZ_Warning("MeshFeatureProcessor", m_modelData.size() == 0,
"Deactivaing the MeshFeatureProcessor, but there are still outstanding mesh handles.\n"
);
m_transformService = nullptr;
@@ -81,7 +81,7 @@ namespace AZ
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
- const auto iteratorRanges = m_meshData.GetParallelRanges();
+ const auto iteratorRanges = m_modelData.GetParallelRanges();
AZ::JobCompletion jobCompletion;
for (const auto& iteratorRange : iteratorRanges)
{
@@ -125,11 +125,11 @@ namespace AZ
m_forceRebuildDrawPackets = false;
// CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread
- for (MeshDataInstance& meshDataInstance : m_meshData)
+ for (ModelDataInstance& modelDataInstance : m_modelData)
{
- if (meshDataInstance.m_model && meshDataInstance.m_cullBoundsNeedsUpdate)
+ if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate)
{
- meshDataInstance.UpdateCullBounds(m_transformService);
+ modelDataInstance.UpdateCullBounds(m_transformService);
}
}
}
@@ -151,14 +151,14 @@ namespace AZ
AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh");
// don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion
- MeshHandle meshDataHandle = m_meshData.emplace();
+ MeshHandle meshDataHandle = m_modelData.emplace();
meshDataHandle->m_descriptor = descriptor;
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset;
- meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle);
+ meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle);
return meshDataHandle;
}
@@ -183,7 +183,7 @@ namespace AZ
m_transformService->ReleaseObjectId(meshHandle->m_objectId);
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
- m_meshData.erase(meshHandle);
+ m_modelData.erase(meshHandle);
return true;
}
@@ -215,9 +215,10 @@ namespace AZ
return {};
}
- Data::Instance MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const
+ const AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const
{
- return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr;
+ static AZStd::vector> staticEmptyList;
+ return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList;
}
void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
@@ -274,9 +275,9 @@ namespace AZ
{
if (meshHandle.IsValid())
{
- MeshDataInstance& meshData = *meshHandle;
- meshData.m_cullBoundsNeedsUpdate = true;
- meshData.m_objectSrgNeedsUpdate = true;
+ ModelDataInstance& modelData = *meshHandle;
+ modelData.m_cullBoundsNeedsUpdate = true;
+ modelData.m_objectSrgNeedsUpdate = true;
m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale);
@@ -292,10 +293,10 @@ namespace AZ
{
if (meshHandle.IsValid())
{
- MeshDataInstance& meshData = *meshHandle;
- meshData.m_aabb = localAabb;
- meshData.m_cullBoundsNeedsUpdate = true;
- meshData.m_objectSrgNeedsUpdate = true;
+ ModelDataInstance& modelData = *meshHandle;
+ modelData.m_aabb = localAabb;
+ modelData.m_cullBoundsNeedsUpdate = true;
+ modelData.m_objectSrgNeedsUpdate = true;
}
};
@@ -465,7 +466,7 @@ namespace AZ
void MeshFeatureProcessor::UpdateMeshReflectionProbes()
{
// we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option
- for (auto& meshInstance : m_meshData)
+ for (auto& meshInstance : m_modelData)
{
if (meshInstance.m_descriptor.m_useForwardPassIblSpecular)
{
@@ -474,14 +475,14 @@ namespace AZ
}
}
- // MeshDataInstance::MeshLoader...
- MeshDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent)
+ // ModelDataInstance::MeshLoader...
+ ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent)
: m_modelAsset(modelAsset)
, m_parent(parent)
{
if (!m_modelAsset.GetId().IsValid())
{
- AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
+ AZ_Error("ModelDataInstance::MeshLoader", false, "Invalid model asset Id.");
return;
}
@@ -494,19 +495,19 @@ namespace AZ
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
- MeshDataInstance::MeshLoader::~MeshLoader()
+ ModelDataInstance::MeshLoader::~MeshLoader()
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
Data::AssetBus::Handler::BusDisconnect();
}
- MeshFeatureProcessorInterface::ModelChangedEvent& MeshDataInstance::MeshLoader::GetModelChangedEvent()
+ MeshFeatureProcessorInterface::ModelChangedEvent& ModelDataInstance::MeshLoader::GetModelChangedEvent()
{
return m_modelChangedEvent;
}
//! AssetBus::Handler overrides...
- void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset asset)
{
Data::Asset modelAsset = asset;
@@ -527,7 +528,7 @@ namespace AZ
}
else
{
- AZ_Error("MeshDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
+ AZ_Error("ModelDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
model = RPI::Model::FindOrCreate(modelAsset);
}
}
@@ -547,29 +548,29 @@ namespace AZ
{
//when running with null renderer, the RPI::Model::FindOrCreate(...) is expected to return nullptr, so suppress this error.
AZ_Error(
- "MeshDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
+ "ModelDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
asset.GetHint().c_str());
}
}
- void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset)
{
OnAssetReady(asset);
}
- void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset asset)
{
// Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization
AZ_Error(
- "MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
+ "ModelDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
m_modelAsset.GetHint().c_str());
AzFramework::AssetSystemRequestBus::Broadcast(
&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid);
}
- void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
+ void ModelDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -584,7 +585,7 @@ namespace AZ
}
}
- void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
+ void ModelDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -599,9 +600,9 @@ namespace AZ
}
}
- // MeshDataInstance...
+ // ModelDataInstance...
- void MeshDataInstance::DeInit()
+ void ModelDataInstance::DeInit()
{
m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
@@ -609,11 +610,11 @@ namespace AZ
m_drawPacketListsByLod.clear();
m_materialAssignments.clear();
- m_shaderResourceGroup = {};
+ m_objectSrgList = {};
m_model = {};
}
- void MeshDataInstance::Init(Data::Instance model)
+ void ModelDataInstance::Init(Data::Instance model)
{
m_model = model;
const size_t modelLodCount = m_model->GetLodCount();
@@ -623,11 +624,11 @@ namespace AZ
BuildDrawPacketList(modelLodIndex);
}
- if (m_shaderResourceGroup)
+ for(auto& objectSrg : m_objectSrgList)
{
// Set object Id once since it never changes
RHI::ShaderInputNameIndex objectIdIndex = "m_objectId";
- m_shaderResourceGroup->SetConstant(objectIdIndex, m_objectId.GetIndex());
+ objectSrg->SetConstant(objectIdIndex, m_objectId.GetIndex());
objectIdIndex.AssertValid();
}
@@ -643,12 +644,12 @@ namespace AZ
m_objectSrgNeedsUpdate = true;
}
- void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
+ void ModelDataInstance::BuildDrawPacketList(size_t modelLodIndex)
{
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
const size_t meshCount = modelLod.GetMeshes().size();
- MeshDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
+ ModelDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
drawPacketListOut.clear();
drawPacketListOut.reserve(meshCount);
@@ -682,27 +683,32 @@ namespace AZ
continue;
}
- if (m_shaderResourceGroup && m_shaderResourceGroup->GetLayout()->GetHash() != objectSrgLayout->GetHash())
+ Data::Instance meshObjectSrg;
+
+ // See if the object SRG for this mesh is already in our list of object SRGs
+ for (auto& objectSrgIter : m_objectSrgList)
{
- AZ_Warning("MeshFeatureProcessor", false, "All materials on a model must use the same per-object ShaderResourceGroup. Skipping.");
- continue;
+ if (objectSrgIter->GetLayout()->GetHash() == objectSrgLayout->GetHash())
+ {
+ meshObjectSrg = objectSrgIter;
+ }
}
- // The first time we find the per-surface SRG asset we create an instance and store it
- // in shaderResourceGroupInOut. All of the Model's draw packets will use this same instance.
- if (!m_shaderResourceGroup)
+ // If the object SRG for this mesh was not already in the list, create it and add it to the list
+ if (!meshObjectSrg)
{
auto& shaderAsset = material->GetAsset()->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg();
- m_shaderResourceGroup = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
- if (!m_shaderResourceGroup)
+ meshObjectSrg = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
+ if (!meshObjectSrg)
{
AZ_Warning("MeshFeatureProcessor", false, "Failed to create a new shader resource group, skipping.");
continue;
}
+ m_objectSrgList.push_back(meshObjectSrg);
}
// setup the mesh draw packet
- RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides);
+ RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, materialAssignment.m_matModUvOverrides);
// set the shader option to select forward pass IBL specular if necessary
if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular }))
@@ -726,7 +732,7 @@ namespace AZ
}
}
- void MeshDataInstance::SetRayTracingData()
+ void ModelDataInstance::SetRayTracingData()
{
if (!m_model)
{
@@ -993,7 +999,7 @@ namespace AZ
rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes);
}
- void MeshDataInstance::RemoveRayTracingData()
+ void ModelDataInstance::RemoveRayTracingData()
{
// remove from ray tracing
RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor();
@@ -1003,7 +1009,7 @@ namespace AZ
}
}
- void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
+ void ModelDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
{
m_sortKey = sortKey;
for (auto& drawPacketList : m_drawPacketListsByLod)
@@ -1015,24 +1021,24 @@ namespace AZ
}
}
- RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const
+ RHI::DrawItemSortKey ModelDataInstance::GetSortKey() const
{
return m_sortKey;
}
- void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
+ void ModelDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
{
m_cullable.m_lodData.m_lodConfiguration = meshLodConfig;
}
- RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const
+ RPI::Cullable::LodConfiguration ModelDataInstance::GetMeshLodConfiguration() const
{
return m_cullable.m_lodData.m_lodConfiguration;
}
- void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
+ void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance:: UpdateDrawPackets");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets");
for (auto& drawPacketList : m_drawPacketListsByLod)
{
for (auto& drawPacket : drawPacketList)
@@ -1045,9 +1051,9 @@ namespace AZ
}
}
- void MeshDataInstance::BuildCullable()
+ void ModelDataInstance::BuildCullable()
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: BuildCullable");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable");
AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1122,9 +1128,9 @@ namespace AZ
m_cullBoundsNeedsUpdate = true;
}
- void MeshDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
+ void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: UpdateCullBounds");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds");
AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1148,74 +1154,74 @@ namespace AZ
m_cullBoundsNeedsUpdate = false;
}
- void MeshDataInstance::UpdateObjectSrg()
+ void ModelDataInstance::UpdateObjectSrg()
{
- if (!m_shaderResourceGroup)
+ for (auto& objectSrg : m_objectSrgList)
{
- return;
+ ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor();
+
+ if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
+ {
+ // retrieve probe constant indices
+ AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld"));
+ AZ_Error("ModelDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse"));
+ AZ_Error("ModelDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths"));
+ AZ_Error("ModelDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths"));
+ AZ_Error("ModelDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe"));
+ AZ_Error("ModelDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
+ AZ_Error("ModelDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
+ AZ_Error("ModelDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
+
+ // retrieve probe cubemap index
+ Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
+ RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = objectSrg->FindShaderInputImageIndex(reflectionCubeMapImageName);
+ AZ_Error("ModelDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr());
+
+ // retrieve the list of probes that contain the centerpoint of the mesh
+ TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor();
+ Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
+
+ ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes;
+ reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes);
+
+ if (!reflectionProbes.empty() && reflectionProbes[0])
+ {
+ objectSrg->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform());
+ objectSrg->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull());
+ objectSrg->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths());
+ objectSrg->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths());
+ objectSrg->SetConstant(useReflectionProbeConstantIndex, true);
+ objectSrg->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection());
+ objectSrg->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure());
+
+ objectSrg->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage());
+ }
+ else
+ {
+ objectSrg->SetConstant(useReflectionProbeConstantIndex, false);
+ }
+ }
+
+ objectSrg->Compile();
}
- ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor();
-
- if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_hasForwardPassIblSpecularMaterial))
- {
- // retrieve probe constant indices
- AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld"));
- AZ_Error("MeshDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse"));
- AZ_Error("MeshDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths"));
- AZ_Error("MeshDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths"));
- AZ_Error("MeshDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe"));
- AZ_Error("MeshDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
- AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
- AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
-
- // retrieve probe cubemap index
- Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
- RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName);
- AZ_Error("MeshDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr());
-
- // retrieve the list of probes that contain the centerpoint of the mesh
- TransformServiceFeatureProcessor* transformServiceFeatureProcessor = m_scene->GetFeatureProcessor();
- Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
-
- ReflectionProbeFeatureProcessor::ReflectionProbeVector reflectionProbes;
- reflectionProbeFeatureProcessor->FindReflectionProbes(transform.GetTranslation(), reflectionProbes);
-
- if (!reflectionProbes.empty() && reflectionProbes[0])
- {
- m_shaderResourceGroup->SetConstant(modelToWorldConstantIndex, reflectionProbes[0]->GetTransform());
- m_shaderResourceGroup->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbes[0]->GetTransform()).GetInverseFull());
- m_shaderResourceGroup->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetOuterObbWs().GetHalfLengths());
- m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths());
- m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true);
- m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection());
- m_shaderResourceGroup->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure());
-
- m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage());
- }
- else
- {
- m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, false);
- }
- }
-
- m_shaderResourceGroup->Compile();
- m_objectSrgNeedsUpdate = false;
+ // Set m_objectSrgNeedsUpdate to false if there are object SRGs in the list
+ m_objectSrgNeedsUpdate = m_objectSrgNeedsUpdate && (m_objectSrgList.size() == 0);
}
- bool MeshDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance material) const
+ bool ModelDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance material) const
{
// look for a shader that has the o_materialUseForwardPassIBLSpecular option set
// Note: this should be changed to have the material automatically set the forwardPassIBLSpecular
@@ -1241,7 +1247,7 @@ namespace AZ
return false;
}
- void MeshDataInstance::SetVisible(bool isVisible)
+ void ModelDataInstance::SetVisible(bool isVisible)
{
m_visible = isVisible;
m_cullable.m_isHidden = !isVisible;
diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
index a9d8d5105f..c8e683e1d1 100644
--- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.cpp
@@ -37,6 +37,11 @@ namespace AZ
m_currentTime = AZStd::chrono::system_clock::now();
}
+ void PostProcessFeatureProcessor::Deactivate()
+ {
+ m_viewAliasMap.clear();
+ }
+
void PostProcessFeatureProcessor::UpdateTime()
{
AZStd::chrono::system_clock::time_point now = AZStd::chrono::system_clock::now();
@@ -45,6 +50,16 @@ namespace AZ
m_deltaTime = deltaTime.count();
}
+ void PostProcessFeatureProcessor::SetViewAlias(const AZ::RPI::ViewPtr sourceView, const AZ::RPI::ViewPtr targetView)
+ {
+ m_viewAliasMap[sourceView.get()] = targetView.get();
+ }
+
+ void PostProcessFeatureProcessor::RemoveViewAlias(const AZ::RPI::ViewPtr sourceView)
+ {
+ m_viewAliasMap.erase(sourceView.get());
+ }
+
void PostProcessFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
AZ_PROFILE_SCOPE(RPI, "PostProcessFeatureProcessor: Simulate");
@@ -200,8 +215,12 @@ namespace AZ
AZ::Render::PostProcessSettings* PostProcessFeatureProcessor::GetLevelSettingsFromView(AZ::RPI::ViewPtr view)
{
+ // check for view aliases first
+ auto viewAliasiterator = m_viewAliasMap.find(view.get());
+
+ // Use the view alias if it exists
+ auto settingsIterator = m_blendedPerViewSettings.find(viewAliasiterator != m_viewAliasMap.end() ? viewAliasiterator->second : view.get());
// If no settings for the view is found, the global settings is returned.
- auto settingsIterator = m_blendedPerViewSettings.find(view.get());
return settingsIterator != m_blendedPerViewSettings.end()
? &settingsIterator->second
: m_globalAggregateLevelSettings.get();
diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h
index 2c1cc98449..10af993d9d 100644
--- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/PostProcessFeatureProcessor.h
@@ -34,6 +34,7 @@ namespace AZ
//! FeatureProcessor overrides...
void Activate() override;
+ void Deactivate() override;
void Simulate(const FeatureProcessor::SimulatePacket& packet) override;
//! PostProcessFeatureProcessorInterface...
@@ -43,6 +44,9 @@ namespace AZ
void OnPostProcessSettingsChanged() override;
PostProcessSettings* GetLevelSettingsFromView(AZ::RPI::ViewPtr view);
+ void SetViewAlias(const AZ::RPI::ViewPtr sourceView, const AZ::RPI::ViewPtr targetView);
+ void RemoveViewAlias(const AZ::RPI::ViewPtr sourceView);
+
private:
PostProcessFeatureProcessor(const PostProcessFeatureProcessor&) = delete;
@@ -83,6 +87,8 @@ namespace AZ
// Each camera/view will have its own PostProcessSettings
AZStd::unordered_map m_blendedPerViewSettings;
+ // This is used for mimicking a postfx setting of a different view
+ AZStd::unordered_map m_viewAliasMap;
};
} // namespace Render
} // namespace AZ
diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp
index 862892ad1b..5683241693 100644
--- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/EyeAdaptationPass.cpp
@@ -81,7 +81,7 @@ namespace AZ
if (scene)
{
PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor();
- AZ::RPI::ViewPtr view = GetView();
+ AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView();
if (fp)
{
PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
@@ -110,7 +110,7 @@ namespace AZ
PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor();
if (fp)
{
- AZ::RPI::ViewPtr view = GetView();
+ AZ::RPI::ViewPtr view = GetRenderPipeline()->GetDefaultView();
PostProcessSettings* postProcessSettings = fp->GetLevelSettingsFromView(view);
if (postProcessSettings)
{
diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
index 4c379c4239..c135b017fa 100644
--- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp
@@ -95,13 +95,13 @@ namespace AZ
renderProxy.m_instance->m_model->WaitForUpload();
}
- //Note: we are creating pointers to the meshDataInstance cullpacket and lod packet here,
+ //Note: we are creating pointers to the modelDataInstance cullpacket and lod packet here,
//and holding them until the skinnedMeshDispatchItems are dispatched. There is an assumption that the underlying
//data will not move during this phase.
- MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle;
- m_workgroup.m_cullPackets.push_back(&meshDataInstance.GetCullPacket());
- m_workgroup.m_drawListMask |= meshDataInstance.GetCullPacket().m_drawListMask;
- m_lodPackets.push_back(&meshDataInstance.GetLodPacket());
+ ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle;
+ m_workgroup.m_cullPackets.push_back(&modelDataInstance.GetCullPacket());
+ m_workgroup.m_drawListMask |= modelDataInstance.GetCullPacket().m_drawListMask;
+ m_lodPackets.push_back(&modelDataInstance.GetLodPacket());
m_potentiallyVisibleProxies.push_back(&renderProxy);
}
}
@@ -187,8 +187,8 @@ namespace AZ
renderProxy.m_instance->m_model->WaitForUpload();
}
- MeshDataInstance& meshDataInstance = **renderProxy.m_meshHandle;
- const RPI::Cullable& cullable = meshDataInstance.GetCullable();
+ ModelDataInstance& modelDataInstance = **renderProxy.m_meshHandle;
+ const RPI::Cullable& cullable = modelDataInstance.GetCullable();
for (const RPI::ViewPtr& viewPtr : packet.m_views)
{
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
index 19c88ec34f..47c92d97fb 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp
@@ -78,8 +78,7 @@ namespace AZ
{
// The presentation mode may change when transitioning to or from a vsynced presentation mode
// In this case, the swapchain must be recreated.
- InvalidateNativeSwapChain();
- CreateSwapchain();
+ m_pendingRecreation = true;
}
}
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h
index c42991725e..b93458113b 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h
@@ -56,8 +56,8 @@ namespace AZ
OwnerRenderPipeline = AZ_BIT(5)
};
- void SetOwenrScene(const Scene* scene);
- void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline);
+ void SetOwnerScene(const Scene* scene);
+ void SetOwnerRenderPipeline(const RenderPipeline* renderPipeline);
void SetPassName(Name passName);
void SetTemplateName(Name passTemplateName);
void SetPassClass(TypeId passClassTypeId);
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp
index 9fc99e3ea4..dbf0fea791 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Model/ModelAssetBuilderComponent.cpp
@@ -2088,7 +2088,7 @@ namespace AZ
AZ::Vector3 vpos; //note: it seems to be fastest to reuse a local Vector3 rather than constructing new ones each loop iteration
for (uint32_t i = 0; i < elementCount; ++i)
{
- vpos.Set(const_cast(reinterpret_cast(&buffer[i])));
+ vpos.Set(reinterpret_cast(&buffer[i]));
aabb.AddPoint(vpos);
}
}
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp
index d9e458c615..d172abd81f 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp
@@ -90,13 +90,13 @@ namespace AZ
return filter;
}
- void PassFilter::SetOwenrScene(const Scene* scene)
+ void PassFilter::SetOwnerScene(const Scene* scene)
{
m_ownerScene = scene;
UpdateFilterOptions();
}
- void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline)
+ void PassFilter::SetOwnerRenderPipeline(const RenderPipeline* renderPipeline)
{
m_ownerRenderPipeline = renderPipeline;
UpdateFilterOptions();
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
index 9a432643d7..e362229d2d 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Model/ModelAsset.cpp
@@ -201,23 +201,11 @@ namespace AZ
AZ::Vector3& normal) const
{
const BufferAssetView& indexBufferView = mesh.GetIndexBufferAssetView();
- const AZStd::array_view& streamBufferList = mesh.GetStreamBufferInfoList();
+ const BufferAssetView* positionBufferView = mesh.GetSemanticBufferAssetView(m_positionName);
- // find position semantic
- const ModelLodAsset::Mesh::StreamBufferInfo* positionBuffer = nullptr;
-
- for (const ModelLodAsset::Mesh::StreamBufferInfo& bufferInfo : streamBufferList)
+ if (positionBufferView && positionBufferView->GetBufferAsset().Get())
{
- if (bufferInfo.m_semantic.m_name == m_positionName)
- {
- positionBuffer = &bufferInfo;
- break;
- }
- }
-
- if (positionBuffer && positionBuffer->m_bufferAssetView.GetBufferAsset().Get())
- {
- BufferAsset* bufferAssetViewPtr = positionBuffer->m_bufferAssetView.GetBufferAsset().Get();
+ BufferAsset* bufferAssetViewPtr = positionBufferView->GetBufferAsset().Get();
BufferAsset* indexAssetViewPtr = indexBufferView.GetBufferAsset().Get();
if (!bufferAssetViewPtr || !indexAssetViewPtr)
@@ -225,7 +213,7 @@ namespace AZ
return false;
}
- RHI::BufferViewDescriptor positionBufferViewDesc = bufferAssetViewPtr->GetBufferViewDescriptor();
+ RHI::BufferViewDescriptor positionBufferViewDesc = positionBufferView->GetBufferViewDescriptor();
AZStd::array_view positionRawBuffer = bufferAssetViewPtr->GetBuffer();
const uint32_t positionElementSize = positionBufferViewDesc.m_elementSize;
@@ -234,22 +222,28 @@ namespace AZ
// Position is 3 floats
if (positionElementSize != sizeof(float) * 3)
{
- AZ_Warning("ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment");
+ AZ_Warning(
+ "ModelAsset", false, "unsupported mesh posiiton format, only full 3 floats per vertex are supported at the moment");
return false;
}
+ RHI::BufferViewDescriptor indexBufferViewDesc = indexBufferView.GetBufferViewDescriptor();
AZStd::array_view indexRawBuffer = indexAssetViewPtr->GetBuffer();
- RHI::BufferViewDescriptor indexRawDesc = indexAssetViewPtr->GetBufferViewDescriptor();
-
- bool anyHit = false;
const AZ::Vector3 rayEnd = rayStart + rayDir;
AZ::Vector3 a, b, c;
AZ::Vector3 intersectionNormal;
+ bool anyHit = false;
float shortestDistanceNormalized = AZStd::numeric_limits::max();
- const AZ::u32* indexPtr = reinterpret_cast(indexRawBuffer.data());
- for (uint32_t indexIter = 0; indexIter <= indexRawDesc.m_elementCount - 3; indexIter += 3, indexPtr += 3)
+
+ const AZ::u32* indexPtr = reinterpret_cast(
+ indexRawBuffer.data() + (indexBufferViewDesc.m_elementOffset * indexBufferViewDesc.m_elementSize));
+ const float* positionPtr = reinterpret_cast(
+ positionRawBuffer.data() + (positionBufferViewDesc.m_elementOffset * positionBufferViewDesc.m_elementSize));
+
+ constexpr int StepSize = 3; // number of values per vertex (x, y, z)
+ for (uint32_t indexIter = 0; indexIter < indexBufferViewDesc.m_elementCount; indexIter += StepSize, indexPtr += StepSize)
{
AZ::u32 index0 = indexPtr[0];
AZ::u32 index1 = indexPtr[1];
@@ -261,17 +255,17 @@ namespace AZ
return false;
}
- const float* p = reinterpret_cast(&positionRawBuffer[index0 * positionElementSize]);
- a.Set(const_cast(p)); // faster than AZ::Vector3 c-tor
-
- p = reinterpret_cast(&positionRawBuffer[index1 * positionElementSize]);
- b.Set(const_cast(p));
-
- p = reinterpret_cast(&positionRawBuffer[index2 * positionElementSize]);
- c.Set(const_cast(p));
+ // faster than AZ::Vector3 c-tor
+ const float* aRef = &positionPtr[index0 * StepSize];
+ a.Set(aRef);
+ const float* bRef = &positionPtr[index1 * StepSize];
+ b.Set(bRef);
+ const float* cRef = &positionPtr[index2 * StepSize];
+ c.Set(cRef);
float currentDistanceNormalized;
- if (AZ::Intersect::IntersectSegmentTriangleCCW(rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized))
+ if (AZ::Intersect::IntersectSegmentTriangleCCW(
+ rayStart, rayEnd, a, b, c, intersectionNormal, currentDistanceNormalized))
{
anyHit = true;
diff --git a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
index 7b07e14de0..81d773d8c0 100644
--- a/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
+++ b/Gems/Atom/RPI/Code/Tests/Model/ModelTests.cpp
@@ -38,7 +38,7 @@ namespace UnitTest
bufferData.resize(bufferSize);
//The actual data doesn't matter
- const uint8_t bufferDataSize = static_cast(bufferData.size());
+ const uint8_t bufferDataSize = aznumeric_cast(bufferData.size());
for (uint8_t i = 0; i < bufferDataSize; ++i)
{
bufferData[i] = i;
@@ -248,7 +248,8 @@ namespace UnitTest
return asset;
}
- AZ::Data::Asset BuildTestModel(const uint32_t lodCount, const uint32_t sharedMeshCount, const uint32_t separateMeshCount, ExpectedModel& expectedModel)
+ AZ::Data::Asset BuildTestModel(
+ const uint32_t lodCount, const uint32_t sharedMeshCount, const uint32_t separateMeshCount, ExpectedModel& expectedModel)
{
using namespace AZ;
@@ -989,6 +990,9 @@ namespace UnitTest
uint32_t{ 0 }, 2, 1, 1, 2, 3, 4, 5, 6, 5, 7, 6, 0, 4, 2, 4, 6, 2, 1, 3, 5, 5, 3, 7, 0, 1, 4, 4, 1, 5, 2, 6, 3, 6, 7, 3,
};
+ static constexpr AZStd::array QuadPositions = { -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f };
+ static constexpr AZStd::array QuadIndices = { uint32_t{ 0 }, 2, 1, 1, 2, 3 };
+
// This class creates a Model with one LOD, whose mesh contains 2 planes. Plane 1 is in the XY plane at Z=-0.5, and
// plane 2 is in the XY plane at Z=0.5. The two planes each have 9 quads which have been triangulated. It only has
// a position and index buffer.
@@ -1031,42 +1035,80 @@ namespace UnitTest
static constexpr inline auto minmaxElement = AZStd::minmax_element(begin(TwoSeparatedPlanesIndices), end(TwoSeparatedPlanesIndices));
static_assert(*minmaxElement.second == (TwoSeparatedPlanesPositions.size() / 3) - 1);
- template class TD;
class TestMesh
{
public:
+ TestMesh() = default;
+
TestMesh(const float* positions, size_t positionCount, const uint32_t* indices, size_t indicesCount)
{
AZ::RPI::ModelLodAssetCreator lodCreator;
- lodCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
+ Begin(lodCreator);
+ Add(lodCreator, positions, positionCount, /*positionOffset=*/0, indices, indicesCount, /*indexOffset=*/0);
+ End(lodCreator);
+ }
+ // initiate the asset lod creation process (note: End must be called after meshes have been added).
+ void Begin(AZ::RPI::ModelLodAssetCreator& lodCreator)
+ {
+ lodCreator.Begin(AZ::Data::AssetId(AZ::Uuid::CreateRandom()));
+ }
+
+ // add a sub mesh and reuse existing position/index buffer (be very careful with the offsets used)
+ void Add(
+ AZ::RPI::ModelLodAssetCreator& lodCreator,
+ const float* positions,
+ size_t positionCount,
+ size_t positionOffset,
+ AZ::Data::Asset positionBuffer,
+ const uint32_t* indices,
+ size_t indexCount,
+ size_t indexOffset,
+ AZ::Data::Asset indexBuffer)
+ {
lodCreator.BeginMesh();
- lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({-1.0f, -1.0f, -0.5f}, {1.0f, 1.0f, 0.5f}));
+ lodCreator.SetMeshAabb(AZ::Aabb::CreateFromMinMax({ -1.0f, -1.0f, -0.5f }, { 1.0f, 1.0f, 0.5f }));
lodCreator.SetMeshMaterialSlot(AZ::Sfmt::GetInstance().Rand32());
- {
- AZ::Data::Asset indexBuffer = BuildTestBuffer(static_cast(indicesCount), sizeof(uint32_t));
- AZStd::copy(indices, indices + indicesCount, reinterpret_cast(const_cast(indexBuffer->GetBuffer().data())));
- lodCreator.SetMeshIndexBuffer({
- indexBuffer,
- AZ::RHI::BufferViewDescriptor::CreateStructured(0, static_cast(indicesCount), sizeof(uint32_t))
- });
- }
+ AZStd::copy(
+ indices, indices + indexCount,
+ reinterpret_cast(const_cast(indexBuffer->GetBuffer().data())) + indexOffset);
+ lodCreator.SetMeshIndexBuffer(
+ { indexBuffer,
+ AZ::RHI::BufferViewDescriptor::CreateStructured(
+ aznumeric_cast(indexOffset), aznumeric_cast(indexCount), sizeof(uint32_t)) });
+ AZStd::copy(
+ positions, positions + positionCount,
+ reinterpret_cast(const_cast(positionBuffer->GetBuffer().data())) + positionOffset);
+ lodCreator.AddMeshStreamBuffer(
+ AZ::RHI::ShaderSemantic(AZ::Name("POSITION")), AZ::Name(),
+ { positionBuffer,
+ AZ::RHI::BufferViewDescriptor::CreateStructured(
+ aznumeric_cast(positionOffset / 3), aznumeric_cast(positionCount / 3), sizeof(float) * 3) });
- {
- AZ::Data::Asset positionBuffer = BuildTestBuffer(static_cast(positionCount / 3), sizeof(float) * 3);
- AZStd::copy(positions, positions + positionCount, reinterpret_cast(const_cast(positionBuffer->GetBuffer().data())));
- lodCreator.AddMeshStreamBuffer(
- AZ::RHI::ShaderSemantic(AZ::Name("POSITION")),
- AZ::Name(),
- {
- positionBuffer,
- AZ::RHI::BufferViewDescriptor::CreateStructured(0, static_cast(positionCount / 3), sizeof(float) * 3)
- }
- );
- }
lodCreator.EndMesh();
+ }
+ // overload of Add - here a new index/position buffer is created for the new data instead of potentially reusing an existing buffer
+ void Add(
+ AZ::RPI::ModelLodAssetCreator& lodCreator,
+ const float* positions,
+ size_t positionCount,
+ size_t positionOffset,
+ const uint32_t* indices,
+ size_t indexCount,
+ size_t indexOffset)
+ {
+ AZ::Data::Asset indexBuffer = BuildTestBuffer(aznumeric_cast(indexCount), sizeof(uint32_t));
+ AZ::Data::Asset positionBuffer =
+ BuildTestBuffer(aznumeric_cast(positionCount / 3), sizeof(float) * 3);
+
+ Add(lodCreator, positions, positionCount, positionOffset, positionBuffer, indices, indexCount, indexOffset, indexBuffer);
+ }
+
+ // complete the asset lod creation process
+ void End(AZ::RPI::ModelLodAssetCreator& lodCreator)
+ {
AZ::Data::Asset lodAsset;
lodCreator.End(lodAsset);
@@ -1199,7 +1241,7 @@ namespace UnitTest
constexpr float rayLength = 100.0f;
EXPECT_THAT(
m_kdTree->RayIntersection(
- AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true));
+ AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::IsTrue());
EXPECT_THAT(t, testing::FloatEq(0.005f));
}
@@ -1210,7 +1252,7 @@ namespace UnitTest
constexpr float rayLength = 10.0f;
EXPECT_THAT(
- m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(0.75f), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::Eq(true));
+ m_kdTree->RayIntersection(AZ::Vector3::CreateAxisZ(0.75f), AZ::Vector3::CreateAxisZ(-rayLength), t, normal), testing::IsTrue());
EXPECT_THAT(t, testing::FloatEq(0.025f));
}
@@ -1288,7 +1330,7 @@ namespace UnitTest
EXPECT_THAT(
m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
AZ::Vector3::CreateAxisZ(5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal),
- testing::Eq(true));
+ testing::IsTrue());
EXPECT_THAT(t, testing::FloatEq(0.4f));
}
@@ -1302,8 +1344,87 @@ namespace UnitTest
EXPECT_THAT(
m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(9.0f), AllowBruteForce, t, normal),
- testing::Eq(true));
+ testing::IsTrue());
EXPECT_THAT(t, testing::FloatEq(1.0f));
EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisY()));
}
+
+ // test to verify that each secondary sub meshes are still intersected with correctly when using brute-force
+ // ray intersection
+ class BruteForceMultiModelIntersectsFixture : public ModelTests
+ {
+ public:
+ inline static const float QuadOffsetX = 15.0f;
+
+ void SetUp() override
+ {
+ ModelTests::SetUp();
+ m_mesh = AZStd::make_unique();
+
+ AZ::RPI::ModelLodAssetCreator lodCreator;
+ m_mesh->Begin(lodCreator);
+
+ // take default quad positions and offset in X by set amount
+ AZStd::vector offsetQuadPositions;
+ offsetQuadPositions.resize(QuadPositions.size());
+ AZStd::copy(QuadPositions.begin(), QuadPositions.end(), offsetQuadPositions.begin());
+ for (size_t xVertIndex = 0; xVertIndex < offsetQuadPositions.size(); xVertIndex += 3)
+ {
+ offsetQuadPositions[xVertIndex] += QuadOffsetX;
+ }
+
+ // create shared buffer to store cube and quad mesh in the same buffer
+ const size_t indicesCount = QuadIndices.size() + CubeIndices.size();
+ const size_t positionCount = QuadPositions.size() + CubePositions.size();
+ AZ::Data::Asset indexBuffer = BuildTestBuffer(aznumeric_cast(indicesCount), sizeof(uint32_t));
+ AZ::Data::Asset positionBuffer =
+ BuildTestBuffer(aznumeric_cast(positionCount / 3), sizeof(float) * 3);
+
+ // add the cube mesh
+ m_mesh->Add(
+ lodCreator, CubePositions.data(), CubePositions.size(), 0, positionBuffer, CubeIndices.data(), CubeIndices.size(), 0,
+ indexBuffer);
+ // add the quad mesh (offset by the cube position and index data into the same buffer)
+ m_mesh->Add(
+ lodCreator, offsetQuadPositions.data(), offsetQuadPositions.size(), /*offset=*/CubePositions.size(), positionBuffer,
+ QuadIndices.data(), QuadIndices.size(), /*offset=*/CubeIndices.size(), indexBuffer);
+
+ m_mesh->End(lodCreator);
+ }
+
+ void TearDown() override
+ {
+ m_mesh.reset();
+ ModelTests::TearDown();
+ }
+
+ AZStd::unique_ptr m_mesh;
+ inline static constexpr bool AllowBruteForce = false;
+ };
+
+ TEST_F(BruteForceMultiModelIntersectsFixture, RayIntersectsWithFirstSubMesh)
+ {
+ float t = 0.0f;
+ AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
+ // fire a ray at the first sub mesh and ensure a successful hit is returned
+ EXPECT_THAT(
+ m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
+ AZ::Vector3(0.0f, 0.0f, 5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal),
+ testing::IsTrue());
+ EXPECT_THAT(t, testing::FloatEq(0.4f));
+ EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisZ()));
+ }
+
+ TEST_F(BruteForceMultiModelIntersectsFixture, RayIntersectsWithSecondSubMesh)
+ {
+ float t = 0.0f;
+ AZ::Vector3 normal = AZ::Vector3::CreateOne(); // invalid starting normal
+ // fire a ray at the second sub mesh and ensure a successful hit is returned
+ EXPECT_THAT(
+ m_mesh->GetModel()->LocalRayIntersectionAgainstModel(
+ AZ::Vector3(QuadOffsetX, 0.0f, 5.0f), -AZ::Vector3::CreateAxisZ(10.0f), AllowBruteForce, t, normal),
+ testing::IsTrue());
+ EXPECT_THAT(t, testing::FloatEq(0.5f));
+ EXPECT_THAT(normal, IsClose(AZ::Vector3::CreateAxisZ()));
+ }
} // namespace UnitTest
diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
index a3161002a0..a3978c2d03 100644
--- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
+++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp
@@ -880,12 +880,14 @@ namespace AZ
{
if (m_meshHandle)
{
- Data::Instance wrinkleMaskObjectSrg = m_meshFeatureProcessor->GetObjectSrg(*m_meshHandle);
- if (wrinkleMaskObjectSrg)
+ const AZStd::vector>& wrinkleMaskObjectSrgs = m_meshFeatureProcessor->GetObjectSrgs(*m_meshHandle);
+
+ for (auto& wrinkleMaskObjectSrg : wrinkleMaskObjectSrgs)
{
RHI::ShaderInputImageIndex wrinkleMasksIndex = wrinkleMaskObjectSrg->FindShaderInputImageIndex(Name{ "m_wrinkle_masks" });
RHI::ShaderInputConstantIndex wrinkleMaskWeightsIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_weights" });
RHI::ShaderInputConstantIndex wrinkleMaskCountIndex = wrinkleMaskObjectSrg->FindShaderInputConstantIndex(Name{ "m_wrinkle_mask_count" });
+
if (wrinkleMasksIndex.IsValid() || wrinkleMaskWeightsIndex.IsValid() || wrinkleMaskCountIndex.IsValid())
{
AZ_Error("AtomActorInstance", wrinkleMasksIndex.IsValid(), "m_wrinkle_masks not found on the ObjectSrg, but m_wrinkle_mask_weights and/or m_wrinkle_mask_count are being used.");
diff --git a/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas b/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas
index 2a0d6d476a..d87baa8aa2 100644
--- a/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas
+++ b/Gems/GameStateSamples/Assets/UI/Canvases/DefaultMainMenuScreen.uicanvas
@@ -753,7 +753,7 @@
-
+
@@ -983,7 +983,7 @@
-
+
diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
index 4574b938f6..ce9eab5f7e 100644
--- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
+++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.cpp
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -448,6 +449,9 @@ namespace LandscapeCanvasEditor
AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AZ_Assert(m_serializeContext, "Failed to acquire application serialize context.");
+ m_prefabFocusPublicInterface = AZ::Interface::Get();
+ AZ_Assert(m_prefabFocusPublicInterface, "LandscapeCanvas - could not get PrefabFocusPublicInterface on construction.");
+
const GraphCanvas::EditorId& editorId = GetEditorId();
// Register unique color palettes for our connections (data types)
@@ -459,6 +463,7 @@ namespace LandscapeCanvasEditor
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
AzToolsFramework::EntityCompositionNotificationBus::Handler::BusConnect();
AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusConnect();
+ AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect();
CrySystemEventBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect();
@@ -484,6 +489,7 @@ namespace LandscapeCanvasEditor
AZ::EntitySystemBus::Handler::BusDisconnect();
CrySystemEventBus::Handler::BusDisconnect();
AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect();
+ AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler::BusDisconnect();
AzToolsFramework::ToolsApplicationNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
@@ -2500,6 +2506,24 @@ namespace LandscapeCanvasEditor
}
}
+ void MainWindow::OnPrefabFocusChanged()
+ {
+ // Make sure to close any open graphs that aren't currently in prefab focus
+ // to prevent the user from making modifications outside of the allowed focus scope
+ AZStd::vector dockWidgetsToClose;
+ for (auto [entityId, dockWidgetId] : m_dockWidgetsByEntity)
+ {
+ if (!m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
+ {
+ dockWidgetsToClose.push_back(dockWidgetId);
+ }
+ }
+ for (auto dockWidgetId : dockWidgetsToClose)
+ {
+ CloseEditor(dockWidgetId);
+ }
+ }
+
void MainWindow::OnPrefabInstancePropagationBegin()
{
// Ignore graph updates during prefab propagation because the entities will be
diff --git a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
index e0fb2d8e10..de6b10529d 100644
--- a/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
+++ b/Gems/LandscapeCanvas/Code/Source/Editor/MainWindow.h
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -31,6 +32,14 @@
#include
#endif
+namespace AzToolsFramework
+{
+ namespace Prefab
+ {
+ class PrefabFocusPublicInterface;
+ }
+}
+
namespace LandscapeCanvasEditor
{
////////////////////////////////////////////////////////////////////////
@@ -81,6 +90,7 @@ namespace LandscapeCanvasEditor
, private AzToolsFramework::EntityCompositionNotificationBus::Handler
, private AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler
, private AzToolsFramework::ToolsApplicationNotificationBus::Handler
+ , private AzToolsFramework::Prefab::PrefabFocusNotificationBus::Handler
, private AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler
, private CrySystemEventBus::Handler
{
@@ -181,6 +191,9 @@ namespace LandscapeCanvasEditor
void EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) override;
////////////////////////////////////////////////////////////////////////
+ //! PrefabFocusNotificationBus overrides
+ void OnPrefabFocusChanged() override;
+
//! PrefabPublicNotificationBus overrides
void OnPrefabInstancePropagationBegin() override;
void OnPrefabInstancePropagationEnd() override;
@@ -248,6 +261,8 @@ namespace LandscapeCanvasEditor
AZ::SerializeContext* m_serializeContext = nullptr;
+ AzToolsFramework::Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
+
bool m_ignoreGraphUpdates = false;
bool m_prefabPropagationInProgress = false;
bool m_inObjectPickMode = false;
diff --git a/Gems/LmbrCentral/Assets/seedList.seed b/Gems/LmbrCentral/Assets/seedList.seed
deleted file mode 100644
index 54c12c9faa..0000000000
--- a/Gems/LmbrCentral/Assets/seedList.seed
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Gems/LyShine/Assets/seedList.seed b/Gems/LyShine/Assets/seedList.seed
index b19aa77191..6b53200c4a 100644
--- a/Gems/LyShine/Assets/seedList.seed
+++ b/Gems/LyShine/Assets/seedList.seed
@@ -2,8 +2,8 @@
-
-
+
+
diff --git a/Gems/LyShine/Code/Source/Sprite.cpp b/Gems/LyShine/Code/Source/Sprite.cpp
index 5c7adae481..d9a0775cc1 100644
--- a/Gems/LyShine/Code/Source/Sprite.cpp
+++ b/Gems/LyShine/Code/Source/Sprite.cpp
@@ -855,7 +855,8 @@ bool CSprite::LoadImage(const AZStd::string& nameTex, AZ::Data::Instance().c_str());
return false;
}
diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas
index 386df81e5c..6a41034bd2 100644
--- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas
+++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Button/Styles.uicanvas
@@ -569,7 +569,7 @@
-
+
@@ -591,7 +591,7 @@
-
+
@@ -626,7 +626,7 @@
-
+
@@ -650,7 +650,7 @@
-
+
@@ -1161,7 +1161,7 @@
-
+
@@ -1209,7 +1209,7 @@
-
+
@@ -1227,7 +1227,7 @@
-
+
@@ -1368,7 +1368,7 @@
-
+
@@ -1438,7 +1438,7 @@
-
+
@@ -1498,7 +1498,7 @@
-
+
@@ -1516,7 +1516,7 @@
-
+
@@ -1657,7 +1657,7 @@
-
+
@@ -1714,7 +1714,7 @@
-
+
@@ -1771,7 +1771,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas
index a0fbcbc0ce..0fb5e390d3 100644
--- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas
+++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Image/ImageTypes.uicanvas
@@ -370,7 +370,7 @@
-
+
@@ -475,7 +475,7 @@
-
+
@@ -616,7 +616,7 @@
-
+
@@ -757,7 +757,7 @@
-
+
@@ -898,7 +898,7 @@
-
+
@@ -1118,7 +1118,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas
index a99a40c6be..e627fafd54 100644
--- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas
+++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Mask/MaskingInteractables.uicanvas
@@ -215,7 +215,7 @@
-
+
@@ -240,7 +240,7 @@
-
+
@@ -265,7 +265,7 @@
-
+
@@ -301,7 +301,7 @@
-
+
@@ -378,7 +378,7 @@
-
+
@@ -455,7 +455,7 @@
-
+
@@ -645,7 +645,7 @@
-
+
@@ -716,7 +716,7 @@
-
+
@@ -975,7 +975,7 @@
-
+
@@ -1000,7 +1000,7 @@
-
+
@@ -1052,7 +1052,7 @@
-
+
@@ -1129,7 +1129,7 @@
-
+
@@ -1206,7 +1206,7 @@
-
+
@@ -1296,7 +1296,7 @@
-
+
@@ -1399,7 +1399,7 @@
-
+
@@ -1425,7 +1425,7 @@
-
+
@@ -1475,7 +1475,7 @@
-
+
@@ -1658,7 +1658,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas
index 3bcd4f3db3..efa2e79b50 100644
--- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas
+++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Comp/Text/ImageMarkup.uicanvas
@@ -475,7 +475,7 @@
-
+
@@ -854,7 +854,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas
index 9b89289dd4..4d3f08a1cd 100644
--- a/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas
+++ b/Gems/LyShineExamples/Assets/UI/Canvases/LyShineExamples/Performance/DrawCallsControl.uicanvas
@@ -1910,7 +1910,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice
index 4c857ecb60..9e5c72b9ee 100644
--- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice
+++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_Draggable.slice
@@ -64,7 +64,7 @@
-
+
@@ -102,7 +102,7 @@
-
+
@@ -422,7 +422,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice
index cb6f6749d4..6f00a98399 100644
--- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice
+++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/ChildDropTargets/ChildDropTargets_EndDropTarget.slice
@@ -174,7 +174,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice
index 8781688a94..3249e61b53 100644
--- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice
+++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/DragAndDrop/DraggableElement.slice
@@ -61,7 +61,7 @@
-
+
@@ -99,7 +99,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice
index 85046d4d1b..661fa6ccf3 100644
--- a/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice
+++ b/Gems/LyShineExamples/Assets/UI/Slices/LyShineExamples/NextButton.slice
@@ -63,7 +63,7 @@
-
+
@@ -118,7 +118,7 @@
-
+
diff --git a/Gems/LyShineExamples/Assets/seedList.seed b/Gems/LyShineExamples/Assets/seedList.seed
index 777269ee7a..d730765515 100644
--- a/Gems/LyShineExamples/Assets/seedList.seed
+++ b/Gems/LyShineExamples/Assets/seedList.seed
@@ -11,10 +11,10 @@
-
+
-
+
@@ -27,10 +27,10 @@
-
+
-
+
@@ -43,10 +43,10 @@
-
+
-
+
@@ -59,10 +59,10 @@
-
+
-
+
@@ -75,10 +75,10 @@
-
+
-
+
@@ -91,26 +91,26 @@
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
index 5cfeb250fa..58a47b336f 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
@@ -443,35 +443,31 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
{{ DeclareArchetypePropertyGetters(Component)|indent(8) -}}
- {{ DeclareRpcInvocations(Component, 'Client', 'Authority', false)|indent(8) -}}
- {{ DeclareRpcInvocations(Component, 'Client', 'Authority', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', false)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Authority', 'Client', true)|indent(8) -}}
+
+ //! RPC Handlers: Override handlers in order to implement what happens after receiving an RPC
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Server', 'Authority', false)|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Client', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Autonomous', 'Authority', false)|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Server', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Client', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Autonomous', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Autonomous')|indent(8) -}}
+
+ //! RPC Event Getters: Subscribe to these events and get notified when an RPC is received
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Server', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Client', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Autonomous', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) }}
+ {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Autonomous')|indent(8) -}}
+
{% for Service in Component.iter('ComponentRelation') %}
{% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %}
{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* Get{{ Service.attrib['Name'] }}Controller();
{% endif %}
{% endfor %}
-
+
protected:
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Server', 'Authority')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Client', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Autonomous', 'Authority')|indent(8) -}}
{{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Autonomous')|indent(8) }}
};
@@ -517,6 +513,8 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', false)|indent(8) -}}
{{ DeclareArchetypePropertyGetters(Component)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}}
+
+ //! RPC Event Getters: Subscribe to these events and get notified when this component receives an RPC
{{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Client')|indent(8) -}}
//! MultiplayerComponent interface
@@ -541,9 +539,13 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}}
+
+ //! RPC Handlers: Override handlers in order to implement what happens after receiving an RPC
{{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Client', false)|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Client')|indent(8) -}}
- {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) }}
+
+ //! RPC Events: Subscribe to these events and get notified when an RPC is received
+ {{ AutoComponentMacros.DeclareRpcEvents(Component, 'Authority', 'Client')|indent(8) -}}
+
{% for Service in Component.iter('ComponentRelation') %}
{% if Service.attrib['Constraint'] != 'Incompatible' %}
const {{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}* Get{{ Service.attrib['Name'] }}() const;
diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
index cf62f6f901..e9bc21875b 100644
--- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
+++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
@@ -340,27 +340,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par
{% endmacro %}
{#
-#}
-{% macro DefineRpcSignal(Component, ClassName, Property, InvokeFrom) %}
-{% set paramNames = [] %}
-{% set paramTypes = [] %}
-{% set paramDefines = [] %}
-{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
-void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }})
-{
- m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(paramNames) }});
-}
-{% endmacro %}
-{#
-
#}
{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, IsProtected) %}
{% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %}
{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %}
{{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}}
-{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
-{{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}}
-{% endif %}
{% endif %}
{% endcall %}
{% endmacro %}
@@ -374,33 +358,46 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
- ->Method("{{ UpperFirst(Property.attrib['Name']) }}", [](const {{ ClassName }}* self, {{ ', '.join(paramDefines) }}) {
- self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
+ ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self, {{ ', '.join(paramDefines) }}) {
+{% if (InvokeFrom == 'Server') %}
+ self->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
+{% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %}
+ if (self->m_controller)
+ {
+ self->m_controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
+ }
+ else
+ {
+ AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This remote-procedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", self->GetEntity()->GetName().c_str(), self->GetEntityId().ToString().c_str())
+ }
+{% endif %}
})
->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) {
AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id);
if (!entity)
{
- AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
+ AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
return;
}
{{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>();
if (!networkComponent)
{
- AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
return;
}
-
+{% if (InvokeFrom == 'Server') %}
+ networkComponent->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
+{% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %}
{{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController());
if (!controller)
{
- AZ_Warning("Network Property", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str())
+ AZ_Warning("Network RPC", false, "{{ ClassName }} {{ UpperFirst(Property.attrib['Name']) }}ByEntityId method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. This RemoteProcedure can only be invoked from {{InvokeFrom}} network entities, because this entity doesn't have a controller, it must not be a {{InvokeFrom}} entity. Please check your network context before attempting to call {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str())
return;
}
-
controller->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }});
+{% endif %}
}, { { { "Source", "The Source containing the {{ ClassName }}Controller" }{% for paramName in paramNames %}, {"{{ paramName }}"}{% endfor %}}})
->Attribute(AZ::Script::Attributes::ToolTip, "{{Property.attrib['Description']}}")
{% endif %}
@@ -436,9 +433,13 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo
{% set paramTypes = [] %}
{% set paramDefines = [] %}
{{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }}
- ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}Event", [](const {{ ClassName }}* self) -> AZ::Event<{{ ', '.join(paramTypes) }}>&
+ ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}Event", []({{ ClassName }}* self) -> AZ::Event<{{ ', '.join(paramTypes) }}>&
{
+{% if HandleOn == 'Client' %}
+ return self->Get{{ UpperFirst(Property.attrib['Name']) }}Event();
+{% elif (HandleOn == 'Authority') or (HandleOn == 'Autonomous') %}
return self->m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event();
+{% endif %}
})
->Attribute(AZ::Script::Attributes::AzEventDescription, {{ LowerFirst(Property.attrib['Name']) }}EventDesc)
->Method("Get{{ UpperFirst(Property.attrib['Name']) }}EventByEntityId", [](AZ::EntityId id) -> AZ::Event<{{ ', '.join(paramTypes) }}>*
@@ -456,7 +457,9 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }}EventByEntityId failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
return nullptr;
}
-
+{% if HandleOn == 'Client' %}
+ return &networkComponent->Get{{ UpperFirst(Property.attrib['Name']) }}Event();
+{% elif (HandleOn == 'Authority') or (HandleOn == 'Autonomous') %}
{{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController());
if (!controller)
{
@@ -465,6 +468,7 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo
}
return &controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event();
+{% endif %}
})
->Attribute(AZ::Script::Attributes::AzEventDescription, AZStd::move({{ LowerFirst(Property.attrib['Name']) }}EventDesc))
{% endif %}
@@ -494,29 +498,31 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp
{
AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority");
m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }});
-{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
- m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }});
-{% endif %}
+{% if (Property.attrib['GenerateEventBindings']|booleanTrue == true) %}
+ m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }});
+{% endif %}
}
-{% if Property.attrib['IsReliable']|booleanTrue %}
-{# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #}
else // Note that this rpc is marked reliable, trigger the appropriate rpc event so it can be forwarded
{
+{% if Property.attrib['IsReliable']|booleanTrue %}
+{# if the rpc is not reliable we can simply drop it, also note message reliability type is default reliable in EntityRpcMessage #}
m_netBindComponent->{{ "GetSend" + InvokeFrom + "To" + HandleOn + "RpcEvent" }}().Signal(message);
+{% endif %}
}
-
-{% endif %}
{% elif HandleOn == 'Autonomous' %}
if (m_controller)
{
AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy");
m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }});
-{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
- m_controller->Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(rpcParamList) }});
-{% endif %}
+{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
+ m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }});
+{% endif %}
}
-{% else %}
+{% elif HandleOn == 'Client' %}
Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }});
+{% if Property.attrib['GenerateEventBindings']|booleanTrue == true %}
+ m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(rpcParamList) }});
+{% endif %}
{% endif %}
}
else if (paramsSerialized)
diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp
index 3558c9fb56..107bced7f2 100644
--- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp
+++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp
@@ -224,8 +224,22 @@ namespace PhysX {
physx::PxJointLimitCone limitCone(swingLimitY, swingLimitZ);
joint->setSwingLimit(limitCone);
- const float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
- const float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
+ float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
+ float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
+ // make sure there is at least a small difference between the lower and upper limits to avoid problems in PhysX
+ const float minTwistLimitRangeRadians = AZ::DegToRad(JointConstants::MinTwistLimitRangeDegrees);
+ if (const float twistLimitRange = twistUpper - twistLower;
+ twistLimitRange < minTwistLimitRangeRadians)
+ {
+ if (twistUpper > 0.0f)
+ {
+ twistLower -= (minTwistLimitRangeRadians - twistLimitRange);
+ }
+ else
+ {
+ twistUpper += (minTwistLimitRangeRadians - twistLimitRange);
+ }
+ }
physx::PxJointAngularLimitPair twistLimitPair(twistLower, twistUpper);
joint->setTwistLimit(twistLimitPair);
diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h
index 7a30473dac..a99eb7aacb 100644
--- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h
+++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h
@@ -18,9 +18,11 @@ namespace PhysX
{
namespace JointConstants
{
- // Setting swing limits to very small values can cause extreme stability problems, so clamp above a small
+ // Setting joint limits to very small values can cause extreme stability problems, so clamp above a small
// threshold.
static const float MinSwingLimitDegrees = 1.0f;
+ // Minimum range between lower and upper twist limits.
+ static const float MinTwistLimitRangeDegrees = 1.0f;
} // namespace JointConstants
namespace Utils
diff --git a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h
index 849a462ab2..9a36cf5222 100644
--- a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h
+++ b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraConstants.h
@@ -24,17 +24,6 @@ namespace Camera
Z_Axis = 2
};
- //////////////////////////////////////////////////////////////////////////
- /// These are intended to be used as an index and needs to be implicitly
- /// convertible to int. See StartingPointCameraUtilities.h for examples
- enum VectorComponentType : int
- {
- X_Component = 0,
- Y_Component = 1,
- Z_Component = 2,
- None = 3,
- };
-
//////////////////////////////////////////////////////////////////////////
/// These are intended to be used as an index and needs to be implicitly
/// convertible to int. See StartingPointCameraUtilities.h for examples
diff --git a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h
index eec86059c5..c565bf9379 100644
--- a/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h
+++ b/Gems/StartingPointCamera/Code/Include/StartingPointCamera/StartingPointCameraUtilities.h
@@ -16,24 +16,16 @@ namespace Camera
{
const char* GetNameFromUuid(const AZ::Uuid& uuid);
- //////////////////////////////////////////////////////////////////////////
- /// This methods will 0 out a vector component and re-normalize it
- //////////////////////////////////////////////////////////////////////////
- void MaskComponentFromNormalizedVector(AZ::Vector3& v, VectorComponentType vectorComponentType);
+ //! This methods will 0 out specified vector components and re-normalize it
+ void MaskComponentFromNormalizedVector(AZ::Vector3& v, bool ignoreX, bool ignoreY, bool ignoreZ);
- //////////////////////////////////////////////////////////////////////////
- /// This will calculate the requested Euler angle from a given AZ::Quaternion
- //////////////////////////////////////////////////////////////////////////
+ //! This will calculate the requested Euler angle from a given AZ::Quaternion
float GetEulerAngleFromTransform(const AZ::Transform& rotation, EulerAngleType eulerAngleType);
- //////////////////////////////////////////////////////////////////////////
- /// This will calculate an AZ::Transform based on an Euler angle
- //////////////////////////////////////////////////////////////////////////
+ //! This will calculate an AZ::Transform based on an Euler angle
AZ::Transform CreateRotationFromEulerAngle(EulerAngleType rotationType, float radians);
- //////////////////////////////////////////////////////////////////////////
- /// Creates the Quaternion representing the rotation looking down the vector
- //////////////////////////////////////////////////////////////////////////
+ //! Creates the Quaternion representing the rotation looking down the vector
AZ::Quaternion CreateQuaternionFromViewVector(const AZ::Vector3 lookVector);
} //namespace Camera
diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp
index d7fcc771f4..5031f149b8 100644
--- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp
+++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp
@@ -20,10 +20,12 @@ namespace Camera
if (serializeContext)
{
serializeContext->Class()
- ->Version(1)
+ ->Version(2)
->Field("Axis to slide along", &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong)
->Field("Angle Type", &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor)
- ->Field("Vector Component To Ignore", &SlideAlongAxisBasedOnAngle::m_vectorComponentToIgnore)
+ ->Field("Ignore X Component", &SlideAlongAxisBasedOnAngle::m_ignoreX)
+ ->Field("Ignore Y Component", &SlideAlongAxisBasedOnAngle::m_ignoreY)
+ ->Field("Ignore Z Component", &SlideAlongAxisBasedOnAngle::m_ignoreZ)
->Field("Max Positive Slide Distance", &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance)
->Field("Max Negative Slide Distance", &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance);
@@ -40,15 +42,16 @@ namespace Camera
->EnumAttribute(EulerAngleType::Pitch, "Pitch")
->EnumAttribute(EulerAngleType::Roll, "Roll")
->EnumAttribute(EulerAngleType::Yaw, "Yaw")
- ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_vectorComponentToIgnore, "Vector Component To Ignore", "The Vector Component To Ignore")
- ->EnumAttribute(VectorComponentType::None, "None")
- ->EnumAttribute(VectorComponentType::X_Component, "X")
- ->EnumAttribute(VectorComponentType::Y_Component, "Y")
- ->EnumAttribute(VectorComponentType::Z_Component, "Z")
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", "The maximum distance to slide in the positive")
->Attribute(AZ::Edit::Attributes::Suffix, "m")
->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", "The maximum distance to slide in the negative")
- ->Attribute(AZ::Edit::Attributes::Suffix, "m");
+ ->Attribute(AZ::Edit::Attributes::Suffix, "m")
+ ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore")
+ ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+ ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.")
+ ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.")
+ ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.")
+ ;
}
}
}
@@ -60,7 +63,7 @@ namespace Camera
float slideScale = currentPositionOnRange > 0.0f ? m_maximumPositiveSlideDistance : m_maximumNegativeSlideDistance;
AZ::Vector3 basis = outLookAtTargetTransform.GetBasis(m_axisToSlideAlong);
- MaskComponentFromNormalizedVector(basis, m_vectorComponentToIgnore);
+ MaskComponentFromNormalizedVector(basis, m_ignoreX, m_ignoreY, m_ignoreZ);
outLookAtTargetTransform.SetTranslation(outLookAtTargetTransform.GetTranslation() + basis * currentPositionOnRange * slideScale);
}
diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h
index 3558fd7272..2c756d1ac7 100644
--- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h
+++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h
@@ -43,8 +43,10 @@ namespace Camera
// Reflected data
RelativeAxisType m_axisToSlideAlong = ForwardBackward;
EulerAngleType m_angleTypeToChangeFor = Pitch;
- VectorComponentType m_vectorComponentToIgnore = None;
float m_maximumPositiveSlideDistance = 0.0f;
float m_maximumNegativeSlideDistance = 0.0f;
+ bool m_ignoreX = false;
+ bool m_ignoreY = false;
+ bool m_ignoreZ = false;
};
} // namespace Camera
diff --git a/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp b/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp
index b8f0945c55..0831ef26e0 100644
--- a/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp
+++ b/Gems/StartingPointCamera/Code/Source/StartingPointCamera/StartingPointCameraUtilities.cpp
@@ -26,38 +26,32 @@ namespace Camera
return "";
}
- //////////////////////////////////////////////////////////////////////////
- /// This methods will 0 out a vector component and re-normalize it
- //////////////////////////////////////////////////////////////////////////
- void MaskComponentFromNormalizedVector(AZ::Vector3& v, VectorComponentType vectorComponentType)
+ void MaskComponentFromNormalizedVector(AZ::Vector3& v, bool ignoreX, bool ignoreY, bool ignoreZ)
{
- switch (vectorComponentType)
- {
- case X_Component:
+
+ if (ignoreX)
{
v.SetX(0.f);
- break;
}
- case Y_Component:
+
+ if (ignoreY)
{
v.SetY(0.f);
- break;
}
- case Z_Component:
+
+ if (ignoreZ)
{
v.SetZ(0.f);
- break;
}
- default:
- AZ_Assert(false, "MaskComponentFromNormalizedVector: VectorComponentType - unexpected value");
- break;
+
+ if (v.IsZero())
+ {
+ AZ_Warning("StartingPointCameraUtilities", false, "MaskComponentFromNormalizedVector: trying to normalize zero vector.")
+ return;
}
v.Normalize();
}
- //////////////////////////////////////////////////////////////////////////
- /// This will calculate the requested Euler angle from a given AZ::Quaternion
- //////////////////////////////////////////////////////////////////////////
float GetEulerAngleFromTransform(const AZ::Transform& rotation, EulerAngleType eulerAngleType)
{
AZ::Vector3 angles = rotation.GetEulerDegrees();
@@ -70,14 +64,11 @@ namespace Camera
case Yaw:
return angles.GetZ();
default:
- AZ_Warning("", false, "GetEulerAngleFromRotation: eulerAngleType - value not supported");
+ AZ_Warning("StartingPointCameraUtilities", false, "GetEulerAngleFromRotation: eulerAngleType - value not supported");
return 0.f;
}
}
- //////////////////////////////////////////////////////////////////////////
- /// This will calculate an AZ::Transform based on an Euler angle
- //////////////////////////////////////////////////////////////////////////
AZ::Transform CreateRotationFromEulerAngle(EulerAngleType rotationType, float radians)
{
switch (rotationType)
@@ -89,14 +80,11 @@ namespace Camera
case Yaw:
return AZ::Transform::CreateRotationZ(radians);
default:
- AZ_Warning("", false, "CreateRotationFromEulerAngle: rotationType - value not supported");
+ AZ_Warning("StartingPointCameraUtilities", false, "CreateRotationFromEulerAngle: rotationType - value not supported");
return AZ::Transform::Identity();
}
}
- //////////////////////////////////////////////////////////////////////////
- /// Creates the Quaternion representing the rotation looking down the vector
- //////////////////////////////////////////////////////////////////////////
AZ::Quaternion CreateQuaternionFromViewVector(const AZ::Vector3 lookVector)
{
float twoDimensionLength = AZ::Vector2(lookVector.GetX(), lookVector.GetY()).GetLength();
diff --git a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp
index ec500d6ada..89fc714c3c 100644
--- a/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp
+++ b/Gems/Terrain/Code/Tests/TerrainHeightGradientListTests.cpp
@@ -19,7 +19,6 @@
#include
using ::testing::_;
-using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;
@@ -29,8 +28,6 @@ class TerrainHeightGradientListComponentTest : public ::testing::Test
protected:
AZ::ComponentApplication m_app;
- AZStd::unique_ptr m_entity;
-
void SetUp() override
{
AZ::ComponentApplication::Descriptor appDesc;
@@ -46,47 +43,70 @@ protected:
m_app.Destroy();
}
- void CreateEntity()
+ AZStd::unique_ptr CreateEntity()
{
- m_entity = AZStd::make_unique();
- ASSERT_TRUE(m_entity);
-
- // Create the required box component.
- UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = m_entity->CreateComponent();
- m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor());
+ auto entity = AZStd::make_unique();
+ entity->Init();
+ return entity;
+ }
+ Terrain::TerrainHeightGradientListComponent* AddHeightGradientListToEntity(AZ::Entity* entity)
+ {
// Create the TerrainHeightGradientListComponent with an entity in its configuration.
Terrain::TerrainHeightGradientListConfig config;
- config.m_gradientEntities.push_back(m_entity->GetId());
+ config.m_gradientEntities.push_back(entity->GetId());
- Terrain::TerrainHeightGradientListComponent* heightGradientListComponent = m_entity->CreateComponent(config);
+ auto heightGradientListComponent = entity->CreateComponent(config);
m_app.RegisterComponentDescriptor(heightGradientListComponent->CreateDescriptor());
- // Create a MockTerrainLayerSpawnerComponent to provide the required TerrainAreaService.
- UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = m_entity->CreateComponent();
- m_app.RegisterComponentDescriptor(layerSpawner->CreateDescriptor());
+ return heightGradientListComponent;
+ }
- m_entity->Init();
+ void AddRequiredComponetsToEntity(AZ::Entity* entity)
+ {
+ // Create the required box component.
+ UnitTest::MockAxisAlignedBoxShapeComponent* boxComponent = entity->CreateComponent();
+ m_app.RegisterComponentDescriptor(boxComponent->CreateDescriptor());
+
+ // Create a MockTerrainLayerSpawnerComponent to provide the required TerrainAreaService.
+ UnitTest::MockTerrainLayerSpawnerComponent* layerSpawner = entity->CreateComponent();
+ m_app.RegisterComponentDescriptor(layerSpawner->CreateDescriptor());
}
};
+TEST_F(TerrainHeightGradientListComponentTest, MissingRequiredComponentsActivateFailure)
+{
+ auto entity = CreateEntity();
+
+ AddHeightGradientListToEntity(entity.get());
+
+ const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
+ EXPECT_FALSE(sortOutcome.IsSuccess());
+}
+
TEST_F(TerrainHeightGradientListComponentTest, ActivateEntityActivateSuccess)
{
// Check that the entity activates.
- CreateEntity();
+ auto entity = CreateEntity();
- m_entity->Activate();
- EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active);
+ AddHeightGradientListToEntity(entity.get());
- m_entity.reset();
+ AddRequiredComponetsToEntity(entity.get());
+
+ entity->Activate();
+ EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
}
TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTerrainSystem)
{
// Check that the HeightGradientListComponent informs the TerrainSystem when the composition changes.
- CreateEntity();
+ auto entity = CreateEntity();
- m_entity->Activate();
+ AddHeightGradientListToEntity(entity.get());
+
+ AddRequiredComponetsToEntity(entity.get());
+
+ entity->Activate();
NiceMock terrainSystem;
@@ -95,32 +115,34 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientRefreshesTer
// and once when the HeightGradientListComponent gets the OnCompositionChanged directly through the DependencyNotificationBus.
EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(2);
- LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
+ LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
// Stop the EXPECT_CALL check now, as OnCompositionChanged will get called twice again during the reset.
Mock::VerifyAndClearExpectations(&terrainSystem);
-
- m_entity.reset();
}
TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsHeights)
{
// Check that the HeightGradientListComponent returns expected height values.
- CreateEntity();
+ auto entity = CreateEntity();
- NiceMock heightfieldRequestBus(m_entity->GetId());
+ AddHeightGradientListToEntity(entity.get());
- m_entity->Activate();
+ AddRequiredComponetsToEntity(entity.get());
+
+ NiceMock heightfieldRequestBus(entity->GetId());
+
+ entity->Activate();
const float mockGradientValue = 0.25f;
- NiceMock gradientRequests(m_entity->GetId());
+ NiceMock gradientRequests(entity->GetId());
ON_CALL(gradientRequests, GetValue).WillByDefault(Return(mockGradientValue));
// Setup a mock to provide the encompassing Aabb to the HeightGradientListComponent.
const float min = 0.0f;
const float max = 1000.0f;
const AZ::Aabb aabb = AZ::Aabb::CreateFromMinMax(AZ::Vector3(min), AZ::Vector3(max));
- NiceMock mockShapeRequests(m_entity->GetId());
+ NiceMock mockShapeRequests(entity->GetId());
ON_CALL(mockShapeRequests, GetEncompassingAabb).WillByDefault(Return(aabb));
const float worldMax = 10000.0f;
@@ -130,17 +152,16 @@ TEST_F(TerrainHeightGradientListComponentTest, TerrainHeightGradientListReturnsH
ON_CALL(mockterrainDataRequests, GetTerrainAabb).WillByDefault(Return(worldAabb));
// Ensure the cached values in the HeightGradientListComponent are up to date.
- LmbrCentral::DependencyNotificationBus::Event(m_entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
+ LmbrCentral::DependencyNotificationBus::Event(entity->GetId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
const AZ::Vector3 inPosition = AZ::Vector3::CreateZero();
AZ::Vector3 outPosition = AZ::Vector3::CreateZero();
bool terrainExists = false;
- Terrain::TerrainAreaHeightRequestBus::Event(m_entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists);
+ Terrain::TerrainAreaHeightRequestBus::Event(
+ entity->GetId(), &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists);
const float height = outPosition.GetZ();
EXPECT_NEAR(height, mockGradientValue * max, 0.01f);
-
- m_entity.reset();
}
diff --git a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp
index dea861bda5..71f5d64fa8 100644
--- a/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp
+++ b/Gems/Terrain/Code/Tests/TerrainSurfaceGradientListTests.cpp
@@ -11,8 +11,6 @@
#include
using ::testing::NiceMock;
-using ::testing::AtLeast;
-using ::testing::_;
using ::testing::Return;
namespace UnitTest
@@ -22,10 +20,6 @@ namespace UnitTest
protected:
AZ::ComponentApplication m_app;
- AZStd::unique_ptr m_entity;
- UnitTest::MockTerrainLayerSpawnerComponent* m_layerSpawnerComponent = nullptr;
- AZStd::unique_ptr m_gradientEntity1, m_gradientEntity2;
-
const AZStd::string surfaceTag1 = "testtag1";
const AZStd::string surfaceTag2 = "testtag2";
@@ -37,81 +31,76 @@ namespace UnitTest
appDesc.m_stackRecordLevels = 20;
m_app.Create(appDesc);
-
- CreateEntities();
}
void TearDown() override
{
- m_gradientEntity2.reset();
- m_gradientEntity1.reset();
- m_entity.reset();
-
m_app.Destroy();
}
- void CreateEntities()
+ AZStd::unique_ptr CreateEntity()
{
- m_entity = AZStd::make_unique();
- ASSERT_TRUE(m_entity);
-
- m_entity->Init();
-
- m_gradientEntity1 = AZStd::make_unique();
- ASSERT_TRUE(m_gradientEntity1);
-
- m_gradientEntity1->Init();
-
- m_gradientEntity2 = AZStd::make_unique();
- ASSERT_TRUE(m_gradientEntity2);
-
- m_gradientEntity2->Init();
+ auto entity = AZStd::make_unique();
+ entity->Init();
+ return entity;
}
- void AddSurfaceGradientListToEntities()
+ UnitTest::MockTerrainLayerSpawnerComponent* AddRequiredComponentsToEntity(AZ::Entity* entity)
{
- m_layerSpawnerComponent = m_entity->CreateComponent();
- m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor());
+ auto layerSpawnerComponent = entity->CreateComponent();
+ m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor());
- Terrain::TerrainSurfaceGradientListConfig config;
-
- Terrain::TerrainSurfaceGradientMapping mapping1;
- mapping1.m_gradientEntityId = m_gradientEntity1->GetId();
- mapping1.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag1);
- config.m_gradientSurfaceMappings.emplace_back(mapping1);
-
- Terrain::TerrainSurfaceGradientMapping mapping2;
- mapping2.m_gradientEntityId = m_gradientEntity2->GetId();
- mapping2.m_surfaceTag = SurfaceData::SurfaceTag(surfaceTag2);
- config.m_gradientSurfaceMappings.emplace_back(mapping2);
-
- Terrain::TerrainSurfaceGradientListComponent* terrainSurfaceGradientListComponent =
- m_entity->CreateComponent(config);
- m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());
+ return layerSpawnerComponent;
}
};
+ TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientMissingRequirementsActivateFails)
+ {
+ auto entity = CreateEntity();
+
+ auto terrainSurfaceGradientListComponent = entity->CreateComponent();
+ m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());
+
+ const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails();
+ EXPECT_FALSE(sortOutcome.IsSuccess());
+ }
+
+ TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientActivateSuccess)
+ {
+ auto entity = CreateEntity();
+
+ AddRequiredComponentsToEntity(entity.get());
+
+ auto terrainSurfaceGradientListComponent = entity->CreateComponent();
+ m_app.RegisterComponentDescriptor(terrainSurfaceGradientListComponent->CreateDescriptor());
+
+ entity->Activate();
+
+ EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active);
+ }
+
TEST_F(TerrainSurfaceGradientListTest, SurfaceGradientReturnsSurfaceWeights)
{
// When there is more than one surface/weight defined and added to the component, they should all
// be returned. The component isn't required to return them in descending order.
- AddSurfaceGradientListToEntities();
+ auto entity = CreateEntity();
- m_entity->Activate();
- m_gradientEntity1->Activate();
- m_gradientEntity2->Activate();
+ AddRequiredComponentsToEntity(entity.get());
+
+ auto gradientEntity1 = CreateEntity();
+ auto gradientEntity2 = CreateEntity();
const float gradient1Value = 0.3f;
- NiceMock mockGradientRequests1(m_gradientEntity1->GetId());
+ NiceMock mockGradientRequests1(gradientEntity1->GetId());
ON_CALL(mockGradientRequests1, GetValue).WillByDefault(Return(gradient1Value));
const float gradient2Value = 1.0f;
- NiceMock mockGradientRequests2(m_gradientEntity2->GetId());
+ NiceMock mockGradientRequests2(gradientEntity2->GetId());
ON_CALL(mockGradientRequests2, GetValue).WillByDefault(Return(gradient2Value));
AzFramework::SurfaceData::SurfaceTagWeightList weightList;
Terrain::TerrainAreaSurfaceRequestBus::Event(
- m_entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightList);
+ entity->GetId(), &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, AZ::Vector3::CreateZero(), weightList);
AZ::Crc32 expectedCrcList[] = { AZ::Crc32(surfaceTag1), AZ::Crc32(surfaceTag2) };
const float expectedWeightList[] = { gradient1Value, gradient2Value };
diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice
index 276d181ad6..020db8367a 100644
--- a/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice
+++ b/Gems/UiBasics/Assets/UI/Slices/Library/Button.slice
@@ -112,7 +112,7 @@
-
+
@@ -158,7 +158,7 @@
-
+
diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice
index 9334903463..74e7bb1c2b 100644
--- a/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice
+++ b/Gems/UiBasics/Assets/UI/Slices/Library/Checkbox.slice
@@ -30,7 +30,7 @@
-
+
@@ -55,7 +55,7 @@
-
+
@@ -74,7 +74,7 @@
-
+
@@ -234,7 +234,7 @@
-
+
@@ -311,7 +311,7 @@
-
+
diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice
index e73c53e0d5..4185e80332 100644
--- a/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice
+++ b/Gems/UiBasics/Assets/UI/Slices/Library/Dropdown.slice
@@ -231,7 +231,7 @@
-
+
@@ -383,7 +383,7 @@
-
+
@@ -1218,7 +1218,7 @@
-
+
diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice b/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice
index cb9eaeb213..f57d307543 100644
--- a/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice
+++ b/Gems/UiBasics/Assets/UI/Slices/Library/Textinput.slice
@@ -75,7 +75,7 @@
-
+
@@ -233,7 +233,7 @@
-
+
diff --git a/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice b/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice
index e92f722837..5c9aa5cbf2 100644
--- a/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice
+++ b/Gems/UiBasics/Assets/UI/Slices/Library/TooltipDisplay.slice
@@ -79,7 +79,7 @@
-
+
diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py
index 9e576d64b5..9b7c8cc782 100644
--- a/scripts/o3de/o3de/download.py
+++ b/scripts/o3de/o3de/download.py
@@ -105,7 +105,7 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path:
origin_uri = downloadable_object_data['originuri']
parsed_uri = urllib.parse.urlparse(origin_uri)
- download_zip_result = utils.download_zip_file(parsed_uri, download_zip_path, download_progress_callback)
+ download_zip_result = utils.download_zip_file(parsed_uri, download_zip_path, force_overwrite, download_progress_callback)
if download_zip_result != 0:
return download_zip_result
diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py
old mode 100755
new mode 100644
index 71929af7b5..88f84ae75e
--- a/scripts/o3de/o3de/utils.py
+++ b/scripts/o3de/o3de/utils.py
@@ -140,9 +140,9 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite: bool
download_file_size = s.headers['content-length']
except KeyError:
pass
- def download_progress(blocks):
- if download_progress_callback and download_file_size:
- return download_progress_callback(int(blocks/int(download_file_size) * 100))
+ def download_progress(downloaded_bytes):
+ if download_progress_callback:
+ return download_progress_callback(int(downloaded_bytes), int(download_file_size))
return False
with download_path.open('wb') as f:
download_cancelled = copyfileobj(s, f, download_progress)
@@ -157,12 +157,12 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite: bool
return 0
-def download_zip_file(parsed_uri, download_zip_path: pathlib.Path, download_progress_callback = None) -> int:
+def download_zip_file(parsed_uri, download_zip_path: pathlib.Path, force_overwrite: bool, download_progress_callback = None) -> int:
"""
:param parsed_uri: uniform resource identifier to zip file to download
:param download_zip_path: path to output zip file
"""
- download_file_result = download_file(parsed_uri, download_zip_path, True, download_progress_callback)
+ download_file_result = download_file(parsed_uri, download_zip_path, force_overwrite, download_progress_callback)
if download_file_result != 0:
return download_file_result