diff --git a/Code/CryEngine/CryCommon/LyShine/Bus/UiSystemBus.h b/Code/CryEngine/CryCommon/LyShine/Bus/UiSystemBus.h index 682bfe753e..8b17ca591c 100644 --- a/Code/CryEngine/CryCommon/LyShine/Bus/UiSystemBus.h +++ b/Code/CryEngine/CryCommon/LyShine/Bus/UiSystemBus.h @@ -18,11 +18,6 @@ public: // Public functions - //! Initialize the UI system. This should be called when all other systems that the UI - //! system depends upon are initialized. Once the engine is fully modularized this - //! function will be unnecessary. - virtual void InitializeSystem() {} - //! Register a component type with the UI system. //! The order in which component types are registered is the order that they show up in //! the add component and in the properties pane. diff --git a/Code/CryEngine/CrySystem/System.h b/Code/CryEngine/CrySystem/System.h index 2ecc8ebeb2..8c122d0df2 100644 --- a/Code/CryEngine/CrySystem/System.h +++ b/Code/CryEngine/CrySystem/System.h @@ -431,7 +431,6 @@ private: bool InitFileSystem(); bool InitFileSystem_LoadEngineFolders(const SSystemInitParams& initParams); bool InitAudioSystem(const SSystemInitParams& initParams); - bool InitShine(const SSystemInitParams& initParams); //@} diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 7464df8ec2..4b07de6933 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -852,16 +852,6 @@ bool CSystem::InitVTuneProfiler() return true; } -///////////////////////////////////////////////////////////////////////////////// -bool CSystem::InitShine([[maybe_unused]] const SSystemInitParams& initParams) -{ - LOADING_TIME_PROFILE_SECTION(GetISystem()); - - EBUS_EVENT(UiSystemBus, InitializeSystem); - - return true; -} - ////////////////////////////////////////////////////////////////////////// void CSystem::InitLocalization() { @@ -1550,20 +1540,6 @@ AZ_POP_DISABLE_WARNING } m_Time.ResetTimer(); - ////////////////////////////////////////////////////////////////////////// - // UI. Should be after input and hardware mouse - ////////////////////////////////////////////////////////////////////////// - if (!m_bDedicatedServer) - { - AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "UI system initialization"); - INDENT_LOG_DURING_SCOPE(); - if (!InitShine(startupParams)) - { - return false; - } - } - - InlineInitializationProcessing("CSystem::Init InitShine"); // CONSOLE ////////////////////////////////////////////////////////////////////////// if (!InitConsole()) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp index 51943536e8..057c0591b0 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerializer.cpp @@ -483,6 +483,9 @@ namespace AZ // tell the caller of this function to write the type id and provide a default object, if requested, for // the specific polymorphic instance the pointer is pointing to. const AZ::Uuid& actualClassId = rtti.GetActualUuid(object); + + // Note: If it is crashing here, it might be that you're serializing a pointer and forgot to initialize it with nullptr. + // Check the elementClassData to identify the causing element. const AZ::Uuid& actualDefaultClassId = rtti.GetActualUuid(defaultObject); if (actualClassId != rtti.GetTypeId()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index c58379ea3e..9d1e95657d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -414,7 +414,6 @@ namespace AzToolsFramework } m_templateFilePathToIdMap.emplace(AZStd::make_pair(filePath, newTemplateId)); - newTemplate.MarkAsDirty(true); return newTemplateId; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp index bc48846585..dcf2a57c64 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabUndoCache.cpp @@ -130,10 +130,7 @@ namespace AzToolsFramework if (!instanceOptionalReference.has_value()) { - AZ_Warning( - "Undo", false, - "PrefabUndoCache was told to update the cache for entity of id %p (%s), but that entity does not have an owning instance.", - entityId, entity->GetName().c_str()); + // This is not an error, we just don't handle this entity. return; } diff --git a/Code/Sandbox/Editor/MainWindow.cpp b/Code/Sandbox/Editor/MainWindow.cpp index 71b31102fd..b4cf317c26 100644 --- a/Code/Sandbox/Editor/MainWindow.cpp +++ b/Code/Sandbox/Editor/MainWindow.cpp @@ -1350,10 +1350,6 @@ void MainWindow::RegisterStdViewClasses() AzAssetBrowserWindow::RegisterViewClass(); AssetEditorWindow::RegisterViewClass(); - //These view dialogs aren't used anymore so they became disabled. - //CLightmapCompilerDialog::RegisterViewClass(); - //CLightmapCompilerDialog::RegisterViewClass(); - // Notify that views can now be registered AzToolsFramework::EditorEvents::Bus::Broadcast( &AzToolsFramework::EditorEvents::Bus::Events::NotifyRegisterViews); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 883ae79043..8fb35b906c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -175,6 +175,14 @@ namespace O3DE::ProjectManager ShowOverlay(); } + void CartButton::hideEvent(QHideEvent*) + { + if (m_cartOverlay) + { + m_cartOverlay->hide(); + } + } + void CartButton::ShowOverlay() { const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 8d6606e63d..dc8f687b31 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #endif @@ -59,6 +60,7 @@ namespace O3DE::ProjectManager private: void mousePressEvent(QMouseEvent* event) override; + void hideEvent(QHideEvent*) override; GemModel* m_gemModel = nullptr; QHBoxLayout* m_layout = nullptr; diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp index a97499ab44..4dfe46b3bf 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilder.cpp @@ -24,8 +24,8 @@ namespace O3DE::ProjectManager { - // 10 Minutes - constexpr int MaxBuildTimeMSecs = 600000; + // QProcess::waitForFinished uses -1 to indicate that the process should not timeout + constexpr int MaxBuildTimeMSecs = -1; ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo) : QObject() diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h index 1295e84281..1058dae68a 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h @@ -13,7 +13,7 @@ namespace O3DE::ProjectManager inline constexpr static int ProjectPreviewImageWidth = 210; inline constexpr static int ProjectPreviewImageHeight = 280; - static const QString ProjectBuildPathPostfix = "Windows_VS2019"; + static const QString ProjectBuildPathPostfix = "build/windows_vs2019"; static const QString ProjectBuildErrorLogPathPostfix = "CMakeFiles/CMakeProjectBuildError.log"; static const QString ProjectPreviewImagePath = "preview.png"; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index d2da1ef437..5b93e4faca 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -118,9 +119,10 @@ namespace O3DE::ProjectManager return false; } - // TODO: Block UX and Notify User they need to wait - + QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); copyResult = CopyProject(origPath, newPath); + QGuiApplication::restoreOverrideCursor(); + } return copyResult; diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 38d3d3b751..e079d97a8b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -41,6 +41,7 @@ #include #include #include +#include //#define DISPLAY_PROJECT_DEV_DATA true @@ -403,9 +404,11 @@ namespace O3DE::ProjectManager if (warningResult == QMessageBox::Yes) { + QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); // Remove project from O3DE and delete from disk HandleRemoveProject(projectPath); ProjectUtils::DeleteProjectFiles(projectPath); + QGuiApplication::restoreOverrideCursor(); } } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp index 235bb66864..0a2a837539 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Thumbnail/ImageThumbnail.cpp @@ -58,7 +58,7 @@ namespace ImageProcessingAtom void ImageThumbnail::LoadThread() { - AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::QueueEvent( + AzToolsFramework::Thumbnailer::ThumbnailerRendererRequestBus::Event( AZ::RPI::StreamingImageAsset::RTTI_Type(), &AzToolsFramework::Thumbnailer::ThumbnailerRendererRequests::RenderThumbnail, m_key, ImageThumbnailSize); diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index a71fc65e2a..9b2c465352 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -714,6 +714,19 @@ "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" + }, + { + "id": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "id": "m_opacityAffectsSpecularFactor" + } } ], "uv": [ diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli index dbd36735b8..cf699228c2 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_Common.azsli @@ -50,6 +50,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial float m_anisotropicFactor; // Base layer anisotropic strength of deviation: negative = Bi-Normal direction, positive = Tangent direction float m_opacityFactor; + float m_opacityAffectsSpecularFactor; Texture2D m_opacityMap; uint m_opacityMapUvIndex; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index f4269d9320..8e9b75e2ad 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -326,7 +326,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent) { - alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); } PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); @@ -344,8 +345,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. // It's done this way because surface transparency doesn't really change specular response (eg, glass). + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; } else if (o_opacity_mode == OpacityMode::TintedTransparent) { @@ -362,7 +368,12 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // m_diffuseColor.rgb (source) is added to that, and the final result is stored in render target 0. lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); } else @@ -410,4 +421,3 @@ ForwardPassOutput EnhancedPbr_ForwardPassPS_EDS(VSOutput IN, bool isFrontFace : return OUT; } - diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 93220973df..8b7e4b1c7e 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -655,6 +655,19 @@ "displayName": "Double-sided", "description": "Whether to render back-faces or just front-faces.", "type": "Bool" + }, + { + "id": "alphaAffectsSpecular", + "displayName": "Alpha affects specular", + "description": "How much the alpha value should also affect specular reflection. This should be 0.0 for materials where light can transmit through their physical surface (like glass), but 1.0 when alpha determines the very presence of a surface (like hair or grass)", + "type": "float", + "min": 0.0, + "max": 1.0, + "defaultValue": 0.0, + "connection": { + "type": "ShaderInput", + "id": "m_opacityAffectsSpecularFactor" + } } ], "uv": [ diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli index d4f4e905b1..f0637c6675 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Common.azsli @@ -45,6 +45,7 @@ ShaderResourceGroup MaterialSrg : SRG_PerMaterial float4 m_pad2; // [GFX TODO][ATOM-14595] This is a workaround for a data stomping bug. Remove once it's fixed. float m_opacityFactor; + float m_opacityAffectsSpecularFactor; Texture2D m_opacityMap; uint m_opacityMapUvIndex; diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl index b2262a65de..2dfdd3681f 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl @@ -254,7 +254,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent) { - alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + float fresnelAlpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles. + alpha = lerp(fresnelAlpha, alpha, MaterialSrg::m_opacityAffectsSpecularFactor); } PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha); @@ -269,8 +270,13 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // For blended mode, we do (dest * alpha) + (source * 1.0). This allows the specular // to be added on top of the diffuse, but then the diffuse must be pre-multiplied. // It's done this way because surface transparency doesn't really change specular response (eg, glass). + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; } else if (o_opacity_mode == OpacityMode::TintedTransparent) { @@ -287,7 +293,12 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // m_diffuseColor.rgb (source) is added to that, and the final result is stored in render target 0. lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse - lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + + // Add specular. m_opacityAffectsSpecularFactor controls how much the alpha masks out specular contribution. + float3 specular = lightingOutput.m_specularColor.rgb; + specular = lerp(specular, specular * lightingOutput.m_diffuseColor.w, MaterialSrg::m_opacityAffectsSpecularFactor); + lightingOutput.m_diffuseColor.rgb += specular; + lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); } else diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material new file mode 100644 index 0000000000..dbaec36136 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_Blended_Alpha_Affects_Specular.material @@ -0,0 +1,24 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "baseColor": { + "color": [ + 0.5906767249107361, + 1.0, + 0.11703670024871826, + 1.0 + ], + "textureMap": "Textures/Default/default_basecolor.tif" + }, + "opacity": { + "alphaSource": "Split", + "factor": 0.75, + "mode": "Blended", + "textureMap": "TestData/Textures/checker8x8_gray_512.png", + "alphaAffectsSpecular": 1.0 + } + } +} diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.cpp index 9409f1468d..0cc96d8a2e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.cpp @@ -24,48 +24,6 @@ namespace CommandSystem { - - AZStd::vector MetaData::GenerateMotionMetaData(EMotionFX::Motion* motion) - { - AZStd::vector commands; - - if (!motion) - { - AZ_Error("EMotionFX", false, "Cannot generate meta data for motion. Motion invalid."); - return commands; - } - - // Save event tracks including motion events. - CommandAdjustMotion* adjustMotionCommand = aznew CommandAdjustMotion(); - adjustMotionCommand->SetMotionExtractionFlags(motion->GetMotionExtractionFlags()); - commands.emplace_back(adjustMotionCommand); - - const size_t eventTrackCount = motion->GetEventTable()->GetNumTracks(); - for (size_t trackIndex = 0; trackIndex < eventTrackCount; ++trackIndex) - { - const EMotionFX::MotionEventTrack* track = motion->GetEventTable()->GetTrack(trackIndex); - - CommandCreateMotionEventTrack* createMotionEventTrackCommand = aznew CommandCreateMotionEventTrack(); - createMotionEventTrackCommand->SetEventTrackName(track->GetName()); - commands.emplace_back(createMotionEventTrackCommand); - - const size_t eventCount = track->GetNumEvents(); - for (size_t eventIndex = 0; eventIndex < eventCount; ++eventIndex) - { - const EMotionFX::MotionEvent& event = track->GetEvent(eventIndex); - CommandCreateMotionEvent* createMotionEventCommand = aznew CommandCreateMotionEvent(); - commands.emplace_back(createMotionEventCommand); - createMotionEventCommand->SetEventTrackName(track->GetName()); - createMotionEventCommand->SetStartTime(event.GetStartTime()); - createMotionEventCommand->SetEndTime(event.GetEndTime()); - createMotionEventCommand->SetEventDatas(event.GetEventDatas()); - } - } - - return commands; - } - - bool MetaData::ApplyMetaDataOnMotion(EMotionFX::Motion* motion, const AZStd::vector& metaDataCommands) { for (MCore::Command* command : metaDataCommands) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.h index c309bf04be..7fba241110 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/MetaData.h @@ -30,13 +30,6 @@ namespace CommandSystem class COMMANDSYSTEM_API MetaData { public: - /** - * Constructs a list of commands representing the changes the user did on the source asset and returns it as a string. - * @param motion The motion to read the changes from. - * @result A string containing a list of commands. - */ - static AZStd::vector GenerateMotionMetaData(EMotionFX::Motion* motion); - /** * Use the given list , prepare it for the given motion and apply the meta data. * @param motion The motion to apply the meta data on. diff --git a/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/MotionEventExport.cpp b/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/MotionEventExport.cpp index db2dcafbdc..78daf024f5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/MotionEventExport.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Exporters/ExporterLib/Exporter/MotionEventExport.cpp @@ -5,6 +5,13 @@ * */ +#include +#include +#include +#include +#include +#include +#include #include "Exporter.h" #include #include @@ -28,17 +35,38 @@ namespace ExporterLib return; } - AZ::Outcome serializedMotionEventTable = MCore::ReflectionSerializer::Serialize(motionEventTable); - if (!serializedMotionEventTable.IsSuccess()) + AZ::SerializeContext* context = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + if (!context) { + AZ_Error("EMotionFX", false, "Can't save motion events. Can't get serialize context from component application."); return; } - const size_t serializedTableSizeInBytes = serializedMotionEventTable.GetValue().size(); + + AZ::JsonSerializerSettings settings; + settings.m_serializeContext = context; + rapidjson::Document jsonDocument; + auto jsonResult = AZ::JsonSerialization::Store(jsonDocument, jsonDocument.GetAllocator(), *motionEventTable, settings); + if (jsonResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted) + { + AZ_Error("EMotionFX", false, "JSON serialization failed: %s", jsonResult.ToString("").c_str()); + return; + } + + AZStd::string serializedMotionEventTable; + auto writeToStringOutcome = AzFramework::FileFunc::WriteJsonToString(jsonDocument, serializedMotionEventTable); + if (!writeToStringOutcome.IsSuccess()) + { + AZ_Error("EMotionFX", false, "WriteJsonToString failed: %s", writeToStringOutcome.GetError().c_str()); + return; + } + + const size_t serializedTableSizeInBytes = serializedMotionEventTable.size(); // the motion event table chunk header EMotionFX::FileFormat::FileChunk chunkHeader; chunkHeader.mChunkID = EMotionFX::FileFormat::SHARED_CHUNK_MOTIONEVENTTABLE; - chunkHeader.mVersion = 2; + chunkHeader.mVersion = 3; chunkHeader.mSizeInBytes = static_cast(serializedTableSizeInBytes + sizeof(EMotionFX::FileFormat::FileMotionEventTableSerialized)); @@ -51,6 +79,6 @@ namespace ExporterLib // save the chunk header and the chunk file->Write(&chunkHeader, sizeof(EMotionFX::FileFormat::FileChunk)); file->Write(&tableHeader, sizeof(EMotionFX::FileFormat::FileMotionEventTableSerialized)); - file->Write(serializedMotionEventTable.GetValue().c_str(), serializedTableSizeInBytes); + file->Write(serializedMotionEventTable.c_str(), serializedTableSizeInBytes); } } // namespace ExporterLib diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp index c077324ef1..c4ed3307ae 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/RCExt/Motion/MotionGroupExporter.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -72,7 +73,7 @@ namespace EMotionFX result += SceneEvents::Process(dataBuilderContext, AZ::RC::Phase::Filling); result += SceneEvents::Process(dataBuilderContext, AZ::RC::Phase::Finalizing); - // Check if there is meta data and apply it to the motion. + // Legacy meta data: Check if there is legacy (XML) event data rule and apply it. AZStd::vector metaDataCommands; if (Rule::MetaDataRule::LoadMetaData(motionGroup, metaDataCommands)) { @@ -82,6 +83,14 @@ namespace EMotionFX } } + // Apply motion meta data. + AZStd::shared_ptr motionMetaData; + if (EMotionFX::Pipeline::Rule::LoadFromGroup(motionGroup, motionMetaData)) + { + motion->SetEventTable(motionMetaData->GetClonedEventTable(motion)); + motion->SetMotionExtractionFlags(motionMetaData->GetMotionExtractionFlags()); + } + ExporterLib::SaveMotion(filename, motion, MCore::Endian::ENDIAN_LITTLE); static AZ::Data::AssetType emotionFXMotionAssetType("{00494B8E-7578-4BA2-8B28-272E90680787}"); // from MotionAsset.h in EMotionFX Gem context.m_products.AddProduct(AZStd::move(filename), context.m_group.GetId(), emotionFXMotionAssetType, diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/MotionGroupBehavior.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/MotionGroupBehavior.cpp index ceffaf29ea..42f369d992 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/MotionGroupBehavior.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Behaviors/MotionGroupBehavior.cpp @@ -17,12 +17,13 @@ #include #include -#include +#include #include +#include +#include +#include #include #include -#include -#include namespace EMotionFX { @@ -35,11 +36,13 @@ namespace EMotionFX void MotionGroupBehavior::Reflect(AZ::ReflectContext* context) { Group::MotionGroup::Reflect(context); - Rule::MotionScaleRule::Reflect(context); - Rule::MotionCompressionSettingsRule::Reflect(context); - Rule::MorphTargetRuleReadOnly::Reflect(context); Rule::MotionAdditiveRule::Reflect(context); + Rule::MotionCompressionSettingsRule::Reflect(context); + Rule::MotionMetaData::Reflect(context); + Rule::MotionMetaDataRule::Reflect(context); Rule::MotionSamplingRule::Reflect(context); + Rule::MotionScaleRule::Reflect(context); + Rule::MorphTargetRuleReadOnly::Reflect(context); AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/MotionGroup.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/MotionGroup.cpp index d3b74dd72f..c699e12a0c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/MotionGroup.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Groups/MotionGroup.cpp @@ -16,9 +16,11 @@ #include #include #include +#include #include #include +#include #include namespace EMotionFX @@ -89,7 +91,7 @@ namespace EMotionFX serializeContext->Class()->Version(1); - serializeContext->Class()->Version(5, VersionConverter) + serializeContext->Class()->Version(6, VersionConverter) ->Field("name", &MotionGroup::m_name) ->Field("selectedRootBone", &MotionGroup::m_selectedRootBone) ->Field("id", &MotionGroup::m_id) @@ -225,6 +227,60 @@ namespace EMotionFX } } + // Motion meta data introduced (no more string- or object-based commands stored in the former meta data rule) + if (version < 6) + { + AZ::SerializeContext::DataElementNode* ruleContainerNode = classElement.FindSubElement(AZ_CRC("rules", 0x899a993c)); + if (!ruleContainerNode) + { + AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Can't find rule container.\n"); + return false; + } + + AZ::SerializeContext::DataElementNode* rulesNode = ruleContainerNode->FindSubElement(AZ_CRC("rules", 0x899a993c)); + if (!rulesNode) + { + AZ_TracePrintf(AZ::SceneAPI::Utilities::ErrorWindow, "Can't find rules within rule container.\n"); + return false; + } + + const int numRules = rulesNode->GetNumSubElements(); + for (int i = 0; i < numRules; ++i) + { + AZ::SerializeContext::DataElementNode& sharedPointerNode = rulesNode->GetSubElement(i); + if (sharedPointerNode.GetNumSubElements() == 1) + { + AZ::SerializeContext::DataElementNode& currentRuleNode = sharedPointerNode.GetSubElement(0); + if (currentRuleNode.GetId() == azrtti_typeid()) + { + // Read the old, command-based meta data rule and retrieve the command objects. + Rule::MetaDataRule oldMetaDataRule; + currentRuleNode.GetData(oldMetaDataRule); + const AZStd::vector& commands = oldMetaDataRule.GetMetaData&>(); + + // Apply the commands onto a temporary motion. + auto motion = new EMotionFX::Motion(""); + motion->SetMotionData(aznew EMotionFX::NonUniformMotionData()); + CommandSystem::MetaData::ApplyMetaDataOnMotion(motion, commands); + + // Construct the new motion meta data rule. + auto metaData = AZStd::make_shared(motion->GetMotionExtractionFlags(), motion->GetEventTable()); + auto metaDataRule = AZStd::make_shared(metaData); + + // Add the new motion meta data rule. + AZ::SceneAPI::Containers::RuleContainer ruleContainer; + ruleContainerNode->GetDataHierarchy(context, ruleContainer); + ruleContainer.RemoveRule(i); + ruleContainer.AddRule(metaDataRule); + ruleContainerNode->SetData(context, ruleContainer); + + motion->Destroy(); + break; + } + } + } + } + return result; } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/ExternalToolRule.inl b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/ExternalToolRule.inl index e98e2e7187..da97743229 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/ExternalToolRule.inl +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/ExternalToolRule.inl @@ -35,7 +35,7 @@ namespace EMotionFX return false; } - outData = rule->GetData(); + outData = AZStd::move(rule->GetData()); return true; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MetaDataRule.h b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MetaDataRule.h index bc9a440cc2..58250174da 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MetaDataRule.h +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MetaDataRule.h @@ -57,7 +57,7 @@ namespace EMotionFX /** * Set the meta data string which contains a list of commands representing the changes the user did on the source asset. - * This string can be constructed using CommandSystem::GenerateMotionMetaData() and CommandSystem::GenerateActorMetaData(). + * This string can be constructed using CommandSystem::GenerateActorMetaData(). * @param metaData The meta data string containing a list of commands to be applied on the source asset. */ void SetMetaData(const AZStd::string& metaData); diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.cpp b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.cpp new file mode 100644 index 0000000000..40648a7f8f --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace EMotionFX::Pipeline::Rule +{ + void MotionMetaData::Reflect(AZ::ReflectContext* context) + { + AZ::SerializeContext* serializeContext = azrtti_cast(context); + if (!serializeContext) + { + return; + } + + serializeContext->Class() + ->Version(1) + ->Field("motionEventTable", &MotionMetaData::m_motionEventTable) + ->Field("motionExtractionFlags", &MotionMetaData::m_motionExtractionFlags) + ; + } + + MotionMetaData::MotionMetaData(EMotionFX::EMotionExtractionFlags extractionFlags, EMotionFX::MotionEventTable* eventTable) + : m_motionExtractionFlags(extractionFlags) + { + m_motionEventTable = CloneMotionEventTable(eventTable); + } + + MotionMetaData::MotionMetaData() + : m_motionExtractionFlags(static_cast(0)) + { + } + + AZStd::unique_ptr MotionMetaData::GetClonedEventTable(EMotionFX::Motion* targetMotion) const + { + AZStd::unique_ptr clonedEventTable = CloneMotionEventTable(m_motionEventTable.get()); + clonedEventTable->InitAfterLoading(targetMotion); + return clonedEventTable; + } + + AZStd::unique_ptr MotionMetaData::CloneMotionEventTable(EMotionFX::MotionEventTable* sourceEventTable) + { + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + if (!serializeContext) + { + AZ_Error("EMotionFX", false, "Cannot clone motion event table for motion meta data. Can't get serialize context from component application."); + return {}; + } + + AZStd::unique_ptr clonedEventTable(serializeContext->CloneObject(sourceEventTable)); + return clonedEventTable; + } + + MotionMetaDataRule::MotionMetaDataRule() + : ExternalToolRule>() + { + } + + MotionMetaDataRule::MotionMetaDataRule(const AZStd::shared_ptr& data) + : m_data(data) + { + } + + void MotionMetaDataRule::Reflect(AZ::ReflectContext* context) + { + AZ::SerializeContext* serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Version(1) + ->Field("data", &MotionMetaDataRule::m_data) + ; + } + } +} // EMotionFX::Pipeline::Rule diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.h b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.h new file mode 100644 index 0000000000..8ede0e130f --- /dev/null +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/Rules/MotionMetaDataRule.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace EMotionFX::Pipeline::Rule +{ + struct MotionMetaData + { + AZ_RTTI(EMotionFX::Pipeline::Rule::MotionMetaData, "{A381A915-3CB3-4F60-82B3-70865CFA1F4F}"); + AZ_CLASS_ALLOCATOR(MotionMetaData, AZ::SystemAllocator, 0) + + MotionMetaData(); + MotionMetaData(EMotionFX::EMotionExtractionFlags extractionFlags, EMotionFX::MotionEventTable* eventTable); + virtual ~MotionMetaData() = default; + + EMotionFX::EMotionExtractionFlags GetMotionExtractionFlags() const { return m_motionExtractionFlags; } + AZStd::unique_ptr GetClonedEventTable(EMotionFX::Motion* targetMotion) const; + + static void Reflect(AZ::ReflectContext* context); + + private: + static AZStd::unique_ptr CloneMotionEventTable(EMotionFX::MotionEventTable* sourceEventTable); + + EMotionFX::EMotionExtractionFlags m_motionExtractionFlags; + AZStd::unique_ptr m_motionEventTable; + }; + + class MotionMetaDataRule + : public ExternalToolRule> + { + public: + AZ_RTTI(EMotionFX::Pipeline::Rule::MotionMetaDataRule, "{E68D0C3D-CBFF-4536-95C1-676474B351A5}", AZ::SceneAPI::DataTypes::IRule); + AZ_CLASS_ALLOCATOR(MotionMetaDataRule, AZ::SystemAllocator, 0) + + MotionMetaDataRule(); + MotionMetaDataRule(const AZStd::shared_ptr& data); + ~MotionMetaDataRule() final = default; + + const AZStd::shared_ptr& GetData() const override { return m_data; } + void SetData(const AZStd::shared_ptr& data) override { m_data = data; } + + static void Reflect(AZ::ReflectContext* context); + + private: + AZStd::shared_ptr m_data; + }; +} // EMotionFX::Pipeline::Rule diff --git a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/sceneapi_ext_files.cmake b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/sceneapi_ext_files.cmake index bf8977b317..211f85cb1c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/sceneapi_ext_files.cmake +++ b/Gems/EMotionFX/Code/EMotionFX/Pipeline/SceneAPIExt/sceneapi_ext_files.cmake @@ -37,6 +37,8 @@ set(FILES Rules/IMotionCompressionSettingsRule.h Rules/MotionCompressionSettingsRule.h Rules/MotionCompressionSettingsRule.cpp + Rules/MotionMetaDataRule.h + Rules/MotionMetaDataRule.cpp Rules/IMotionScaleRule.h Rules/MotionScaleRule.h Rules/MotionScaleRule.cpp diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Event.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Event.cpp index 62c3924d78..e69ef9f20e 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Event.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Event.cpp @@ -15,6 +15,16 @@ namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(Event, MotionEventAllocator, 0) + Event::Event(EventDataPtr&& data) + : m_eventDatas{ AZStd::move(data) } + { + } + + Event::Event(EventDataSet&& datas) + : m_eventDatas(AZStd::move(datas)) + { + } + void Event::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Event.h b/Gems/EMotionFX/Code/EMotionFX/Source/Event.h index 8ac3e48a8c..6665ef1ae3 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Event.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Event.h @@ -27,16 +27,9 @@ namespace EMotionFX AZ_RTTI(Event, "{67549E9F-8E3F-4336-BDB8-716AFCBD4985}"); AZ_CLASS_ALLOCATOR_DECL - Event(EventDataPtr&& data = nullptr) - : m_eventDatas{AZStd::move(data)} - { - } - - Event(EventDataSet&& datas) - : m_eventDatas(AZStd::move(datas)) - { - } - + Event() = default; + explicit Event(EventDataPtr&& data); + explicit Event(EventDataSet&& datas); virtual ~Event() = default; static void Reflect(AZ::ReflectContext* context); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp index 1ca657af5f..ac4a44b8c0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.cpp @@ -6,10 +6,17 @@ */ #include +#include +#include #include #include #include #include +#include +#include +#include +#include + #include #include #include @@ -1161,10 +1168,11 @@ namespace EMotionFX AZStd::vector buffer(fileEventTable.m_size); file->Read(&buffer[0], fileEventTable.m_size); - MotionEventTable* motionEventTable = AZ::Utils::LoadObjectFromBuffer(&buffer[0], buffer.size(), context); + auto motionEventTable = AZStd::unique_ptr(AZ::Utils::LoadObjectFromBuffer(&buffer[0], buffer.size(), context)); if (motionEventTable) { - motionEventTable->InitAfterLoading(motion); + motion->SetEventTable(AZStd::move(motionEventTable)); + motion->GetEventTable()->InitAfterLoading(motion); return true; } @@ -1173,6 +1181,57 @@ namespace EMotionFX //================================================================================================= + bool ChunkProcessorMotionEventTrackTable3::Process(MCore::File* file, Importer::ImportParameters& importParams) + { + Motion* motion = importParams.mMotion; + MCORE_ASSERT(motion); + + FileFormat::FileMotionEventTableSerialized fileEventTable; + file->Read(&fileEventTable, sizeof(FileFormat::FileMotionEventTableSerialized)); + + if (GetLogging()) + { + MCore::LogDetailedInfo("- Motion Event Table:"); + MCore::LogDetailedInfo(" + size = %d", fileEventTable.m_size); + } + + AZStd::vector buffer(fileEventTable.m_size); + file->Read(&buffer[0], fileEventTable.m_size); + AZStd::string_view bufferStringView(&buffer[0], buffer.size()); + + auto readJsonOutcome = AzFramework::FileFunc::ReadJsonFromString(bufferStringView); + AZStd::string errorMsg; + if (!readJsonOutcome.IsSuccess()) + { + AZ_Error("EMotionFX", false, "Loading motion event table failed due to ReadJsonFromString. %s", readJsonOutcome.TakeError().c_str()); + return false; + } + rapidjson::Document document = readJsonOutcome.TakeValue(); + + AZ::SerializeContext* context = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + if (!context) + { + return false; + } + + AZ::JsonDeserializerSettings settings; + settings.m_serializeContext = context; + + MotionEventTable* motionEventTable = motion->GetEventTable(); + AZ::JsonSerializationResult::ResultCode jsonResult = AZ::JsonSerialization::Load(*motionEventTable, document, settings); + if (jsonResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted) + { + AZ_Error("EMotionFX", false, "Loading motion event table failed due to AZ::JsonSerialization::Load."); + return false; + } + + motionEventTable->InitAfterLoading(motion); + return true; + } + + //================================================================================================= + bool ChunkProcessorActorInfo::Process(MCore::File* file, Importer::ImportParameters& importParams) { const MCore::Endian::EEndianType endianType = importParams.mEndianType; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h index a319af42c8..057ebea83f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/ChunkProcessors.h @@ -312,6 +312,7 @@ namespace EMotionFX // shared file format chunk processors EMFX_CHUNKPROCESSOR(ChunkProcessorMotionEventTrackTable, FileFormat::SHARED_CHUNK_MOTIONEVENTTABLE, 1) EMFX_CHUNKPROCESSOR(ChunkProcessorMotionEventTrackTable2, FileFormat::SHARED_CHUNK_MOTIONEVENTTABLE, 2) + EMFX_CHUNKPROCESSOR(ChunkProcessorMotionEventTrackTable3, FileFormat::SHARED_CHUNK_MOTIONEVENTTABLE, 3) // Actor file format chunk processors EMFX_CHUNKPROCESSOR(ChunkProcessorActorInfo, FileFormat::ACTOR_CHUNK_INFO, 1) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp index 2e568d2539..2c74c5f4e9 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Importer/Importer.cpp @@ -1061,6 +1061,7 @@ namespace EMotionFX // shared processors RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable()); RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable2()); + RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable3()); // Actor file format RegisterChunkProcessor(aznew ChunkProcessorActorInfo()); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Motion.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Motion.cpp index 3c34fb83f0..bff1f855d6 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Motion.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Motion.cpp @@ -26,29 +26,20 @@ namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(Motion, MotionAllocator, 0) - - // constructor Motion::Motion(const char* name) : BaseObject() { - mCustomData = nullptr; - mNameID = MCORE_INVALIDINDEX32; - mID = MCore::GetIDGenerator().GenerateID(); - mEventTable = aznew MotionEventTable(); - mUnitType = GetEMotionFX().GetUnitType(); - mFileUnitType = mUnitType; - mExtractionFlags = static_cast(0); - m_motionData = nullptr; + mID = MCore::GetIDGenerator().GenerateID(); + m_eventTable = AZStd::make_unique(); + mUnitType = GetEMotionFX().GetUnitType(); + mFileUnitType = mUnitType; + mExtractionFlags = static_cast(0); if (name) { SetName(name); } - mMotionFPS = 30.0f; - mDirtyFlag = false; - mAutoUnregister = true; - #if defined(EMFX_DEVELOPMENT_BUILD) mIsOwnedByRuntime = false; #endif // EMFX_DEVELOPMENT_BUILD @@ -57,8 +48,6 @@ namespace EMotionFX GetMotionManager().AddMotion(this); } - - // destructor Motion::~Motion() { // trigger the OnDeleteMotion event @@ -70,11 +59,6 @@ namespace EMotionFX GetMotionManager().RemoveMotion(this, false); } - if (mEventTable) - { - mEventTable->Destroy(); - } - delete m_motionData; } @@ -208,19 +192,14 @@ namespace EMotionFX MotionEventTable* Motion::GetEventTable() const { - return mEventTable; + return m_eventTable.get(); } - void Motion::SetEventTable(MotionEventTable* newTable) + void Motion::SetEventTable(AZStd::unique_ptr eventTable) { - if (mEventTable && mEventTable != newTable) - { - mEventTable->Destroy(); - } - mEventTable = newTable; + m_eventTable = AZStd::move(eventTable); } - void Motion::SetID(uint32 id) { mID = id; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Motion.h b/Gems/EMotionFX/Code/EMotionFX/Source/Motion.h index 7e66350cdc..e34e2ef7ab 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Motion.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Motion.h @@ -7,7 +7,7 @@ #pragma once -// include the required headers +#include #include "EMotionFXConfig.h" #include "EMotionFXManager.h" #include "PlayBackInfo.h" @@ -115,7 +115,7 @@ namespace EMotionFX * Set the event table. * @param newTable The new motion event table for the Motion to use. */ - void SetEventTable(MotionEventTable* newTable); + void SetEventTable(AZStd::unique_ptr eventTable); /** * Set the motion framerate. @@ -249,19 +249,19 @@ namespace EMotionFX void SetMotionData(MotionData* motionData, bool delOldFromMem=true); protected: - MotionData* m_motionData; /**< The motion data, which can in theory be any data representation/compression. */ + MotionData* m_motionData = nullptr; /**< The motion data, which can in theory be any data representation/compression. */ AZStd::string mFileName; /**< The filename of the motion. */ PlayBackInfo m_defaultPlayBackInfo; /**< The default/fallback motion playback info which will be used when no playback info is passed to the Play() function. */ - MotionEventTable* mEventTable; /**< The event table, which contains all events, and will make sure events get executed. */ + AZStd::unique_ptr m_eventTable; /**< The event table, which contains all events, and will make sure events get executed. */ MCore::Distance::EUnitType mUnitType; /**< The type of units used. */ MCore::Distance::EUnitType mFileUnitType; /**< The type of units used, inside the file that got loaded. */ - void* mCustomData; /**< A pointer to custom user data that is linked with this motion object. */ - float mMotionFPS; /**< The number of keyframes per second. */ - uint32 mNameID; /**< The ID represention the name or description of this motion. */ - uint32 mID; /**< The unique identification number for the motion. */ + void* mCustomData = nullptr; /**< A pointer to custom user data that is linked with this motion object. */ + float mMotionFPS = 30.0f; /**< The number of keyframes per second. */ + uint32 mNameID = MCORE_INVALIDINDEX32; /**< The ID represention the name or description of this motion. */ + uint32 mID = MCORE_INVALIDINDEX32; /**< The unique identification number for the motion. */ EMotionExtractionFlags mExtractionFlags; /**< The motion extraction flags, which define behavior of the motion extraction system when applied to this motion. */ - bool mDirtyFlag; /**< The dirty flag which indicates whether the user has made changes to the motion since the last file save operation. */ - bool mAutoUnregister; /**< Automatically unregister the motion from the motion manager when this motion gets deleted? Default is true. */ + bool mDirtyFlag = false; /**< The dirty flag which indicates whether the user has made changes to the motion since the last file save operation. */ + bool mAutoUnregister = true; /**< Automatically unregister the motion from the motion manager when this motion gets deleted? Default is true. */ #if defined(EMFX_DEVELOPMENT_BUILD) bool mIsOwnedByRuntime; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.cpp index 2060203166..751f7e551a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.cpp @@ -5,7 +5,6 @@ * */ -// include the required headers #include "MotionEventTable.h" #include "MotionEvent.h" #include "MotionEventTrack.h" @@ -19,22 +18,11 @@ namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(MotionEventTable, MotionEventAllocator, 0) - - // constructor - MotionEventTable::MotionEventTable() - : BaseObject() - , m_syncTrack(nullptr) - { - } - - - // destructor MotionEventTable::~MotionEventTable() { RemoveAllTracks(); } - void MotionEventTable::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -56,7 +44,6 @@ namespace EMotionFX track->SetMotion(motion); } - motion->SetEventTable(this); AutoCreateSyncTrack(motion); } @@ -96,7 +83,7 @@ namespace EMotionFX { for (MotionEventTrack* track : m_tracks) { - track->Destroy(); + delete track; } } @@ -109,7 +96,7 @@ namespace EMotionFX { if (delFromMem) { - m_tracks[index]->Destroy(); + delete m_tracks[index]; } m_tracks.erase(AZStd::next(m_tracks.begin(), index)); @@ -196,9 +183,8 @@ namespace EMotionFX AnimGraphSyncTrack* syncTrack; if (!track) { - // create and add the sync track syncTrack = aznew AnimGraphSyncTrack("Sync", motion); - AddTrack(syncTrack); + InsertTrack(0, syncTrack); } else { diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.h b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.h index 25726134ae..2101843a52 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTable.h @@ -7,9 +7,7 @@ #pragma once -// include the required headers #include "EMotionFXConfig.h" -#include "BaseObject.h" #include "AnimGraphSyncTrack.h" #include @@ -40,17 +38,15 @@ namespace EMotionFX * The handling of those events is done by the MotionEventHandler class that you specify to the MotionEventManager singleton. */ class EMFX_API MotionEventTable - : public BaseObject { friend class MotionEvent; public: AZ_CLASS_ALLOCATOR_DECL - AZ_RTTI(MotionEventTable, "{DB5BF142-99BE-4026-8D3E-3E5B30C14714}", BaseObject) + AZ_RTTI(MotionEventTable, "{DB5BF142-99BE-4026-8D3E-3E5B30C14714}") - MotionEventTable(); - - ~MotionEventTable(); + MotionEventTable() = default; + virtual ~MotionEventTable(); static void Reflect(AZ::ReflectContext* context); @@ -100,7 +96,6 @@ namespace EMotionFX AZStd::vector m_tracks; /// A shortcut to the track containing sync events. - AnimGraphSyncTrack* m_syncTrack; - + AnimGraphSyncTrack* m_syncTrack = nullptr; }; } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.cpp index ea984b82be..f1ec5950fb 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.cpp @@ -5,7 +5,6 @@ * */ -// include the required headers #include "MotionEventTrack.h" #include "MotionEvent.h" #include "EventManager.h" @@ -20,30 +19,19 @@ #include #include - namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(MotionEventTrack, MotionEventAllocator, 0) - // constructor MotionEventTrack::MotionEventTrack(Motion* motion) - : BaseObject() - , mMotion(motion) - , mNameID(MCORE_INVALIDINDEX32) - , mEnabled(true) - , mDeletable(true) + : mMotion(motion) { } - - // extended constructor MotionEventTrack::MotionEventTrack(const char* name, Motion* motion) - : BaseObject() - , mMotion(motion) - , mEnabled(true) - , mDeletable(true) + : mMotion(motion) + , m_name(name) { - SetName(name); } MotionEventTrack::MotionEventTrack(const MotionEventTrack& other) @@ -59,7 +47,7 @@ namespace EMotionFX } m_events = other.m_events; mMotion = other.mMotion; - mNameID = other.mNameID; + m_name = other.m_name; return *this; } @@ -72,8 +60,8 @@ namespace EMotionFX } serializeContext->Class() - ->Version(1) - ->Field("name", &MotionEventTrack::mNameID) + ->Version(2, VersionConverter) + ->Field("name", &MotionEventTrack::m_name) ->Field("enabled", &MotionEventTrack::mEnabled) ->Field("deletable", &MotionEventTrack::mDeletable) ->Field("events", &MotionEventTrack::m_events) @@ -94,6 +82,31 @@ namespace EMotionFX ; } + bool MotionEventTrack::VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) + { + const unsigned int version = classElement.GetVersion(); + if (version < 2) + { + int nameElementIndex = classElement.FindElement(AZ_CRC_CE("name")); + if (nameElementIndex < 0) + { + return false; + } + AZ::SerializeContext::DataElementNode& nameElement = classElement.GetSubElement(nameElementIndex); + + MCore::StringIdPoolIndex oldName; + const bool result = nameElement.GetData(oldName); + + classElement.RemoveElement(nameElementIndex); + if (result) + { + AZStd::string newName = MCore::GetStringIdPool().GetName(oldName.m_index); + classElement.AddElementWithData(context, "name", newName); + } + } + return true; + } + // creation MotionEventTrack* MotionEventTrack::Create(Motion* motion) @@ -112,7 +125,7 @@ namespace EMotionFX // set the name of the motion event track void MotionEventTrack::SetName(const char* name) { - mNameID = MCore::GetStringIdPool().GenerateIdForString(name); + m_name = name; } @@ -362,60 +375,31 @@ namespace EMotionFX RemoveAllEvents(); } - - // get the name const char* MotionEventTrack::GetName() const { - if (mNameID == MCORE_INVALIDINDEX32) - { - return ""; - } - - return MCore::GetStringIdPool().GetName(mNameID).c_str(); + return m_name.c_str(); } - - // get the name as string object const AZStd::string& MotionEventTrack::GetNameString() const { - if (mNameID == MCORE_INVALIDINDEX32) - { - return MCore::GetStringIdPool().GetName(0); - } - - return MCore::GetStringIdPool().GetName(mNameID); + return m_name; } - // copy the track contents to a target track // this overwrites all existing contents of the target track void MotionEventTrack::CopyTo(MotionEventTrack* targetTrack) const { - targetTrack->mNameID = mNameID; + targetTrack->m_name = m_name; targetTrack->m_events = m_events; targetTrack->mEnabled = mEnabled; } - // reserve memory for a given amount of events void MotionEventTrack::ReserveNumEvents(size_t numEvents) { m_events.reserve(numEvents); } - - uint32 MotionEventTrack::GetNameID() const - { - return mNameID; - } - - - void MotionEventTrack::SetNameID(uint32 id) - { - mNameID = id; - } - - void MotionEventTrack::SetIsEnabled(bool enabled) { mEnabled = enabled; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.h b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.h index 40e8f24405..b7cfc526cc 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionEventTrack.h @@ -7,13 +7,10 @@ #pragma once -// include the required headers +#include #include "EMotionFXConfig.h" #include "BaseObject.h" #include "MotionEvent.h" -#include - -#include namespace AZ { @@ -38,15 +35,15 @@ namespace EMotionFX * The handling of those events is done by the MotionEventHandler class that you specify to the MotionEventManager singleton. */ class EMFX_API MotionEventTrack - : public BaseObject { friend class MotionEvent; public: - AZ_RTTI(MotionEventTrack, "{D142399D-C7DF-4E4A-A099-7E4E662F1E81}", BaseObject) + AZ_RTTI(MotionEventTrack, "{D142399D-C7DF-4E4A-A099-7E4E662F1E81}") AZ_CLASS_ALLOCATOR_DECL - MotionEventTrack() {} + MotionEventTrack() = default; + virtual ~MotionEventTrack() = default; /** * The constructor. @@ -167,8 +164,6 @@ namespace EMotionFX const char* GetName() const; const AZStd::string& GetNameString() const; - uint32 GetNameID() const; - void SetNameID(uint32 id); void SetIsEnabled(bool enabled); bool GetIsEnabled() const; @@ -182,23 +177,22 @@ namespace EMotionFX void ReserveNumEvents(size_t numEvents); protected: - /// The collection of motion events. AZStd::vector m_events; + AZStd::string m_name; /// The motion where this track belongs to. Motion* mMotion; - /// The name ID. - MCore::StringIdPoolIndex mNameID; - /// Is this track enabled? - bool mEnabled; - bool mDeletable; + bool mEnabled = true; + bool mDeletable = true; private: void ProcessEventsImpl(float startTime, float endTime, ActorInstance* actorInstance, const MotionInstance* motionInstance, const AZStd::function& processFunc); template void ExtractEvents(float startTime, float endTime, const MotionInstance* motionInstance, const Functor& processFunc, bool handleLoops = true) const; + + static bool VersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); }; } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/PhysicsSetup.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/PhysicsSetup.cpp index 9fab1b18c3..33e5e3dbc8 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/PhysicsSetup.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/PhysicsSetup.cpp @@ -298,14 +298,20 @@ namespace EMotionFX { Physics::CapsuleShapeConfiguration* capsule = static_cast(collider.second.get()); capsule->m_height = boneDirection.GetLength(); - collider.first->m_rotation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), localBoneDirection.GetNormalized()); + if (AZ::IsClose(localBoneDirection.GetLength(), 1.0f)) + { + collider.first->m_rotation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), localBoneDirection.GetNormalized()); + } capsule->m_height = boneLength; const float radius = AZ::GetMin(rootMeanSquareDistanceFromBone, minRadiusRatio * boneLength); capsule->m_radius = radius; } else if (colliderType == azrtti_typeid()) { - collider.first->m_rotation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), localBoneDirection.GetNormalized()); + if (AZ::IsClose(localBoneDirection.GetLength(), 1.0f)) + { + collider.first->m_rotation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisZ(), localBoneDirection.GetNormalized()); + } Physics::BoxShapeConfiguration* box = static_cast(collider.second.get()); box->m_dimensions = AZ::Vector3(2.0f * rootMeanSquareDistanceFromBone, 2.0f * rootMeanSquareDistanceFromBone, boneLength); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp index c2b9babf70..8c22d657c3 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Commands.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -293,16 +294,63 @@ namespace EMStudio AZStd::string sourceAssetFilename; EBUS_EVENT_RESULT(fullPathFound, AzToolsFramework::AssetSystemRequestBus, GetFullSourcePathFromRelativeProductPath, productFilename, sourceAssetFilename); - // Generate meta data command for all changes being made to the motion. - const AZStd::vector metaData = CommandSystem::MetaData::GenerateMotionMetaData(motion); + // Load the manifest from disk. + AZStd::shared_ptr scene; + AZ::SceneAPI::Events::SceneSerializationBus::BroadcastResult(scene, &AZ::SceneAPI::Events::SceneSerializationBus::Events::LoadScene, sourceAssetFilename, AZ::Uuid::CreateNull()); + if (!scene) + { + AZ_Error("EMotionFX", false, "Unable to save meta data to manifest due to failed scene loading."); + return false; + } - // Save meta data commands to the manifest. - const bool saveResult = EMotionFX::Pipeline::Rule::MetaDataRule::SaveMetaDataToFile(sourceAssetFilename, groupName, metaData, outResult); + AZ::SceneAPI::Containers::SceneManifest& manifest = scene->GetManifest(); + auto values = manifest.GetValueStorage(); + auto groupView = AZ::SceneAPI::Containers::MakeDerivedFilterView(values); + for (EMotionFX::Pipeline::Group::MotionGroup& group : groupView) + { + // Non-case sensitive group name comparison. Product filenames are lower case only and might mismatch casing of the entered group name. + if (AzFramework::StringFunc::Equal(group.GetName().c_str(), groupName.c_str())) + { + // Remove legacy meta data rule. + EMotionFX::Pipeline::Rule::RemoveRuleFromGroup>(*scene, group); + + // Add motion meta data. + auto motionMetaData = AZStd::make_shared(motion->GetMotionExtractionFlags(), motion->GetEventTable()); + EMotionFX::Pipeline::Rule::SaveToGroup>(*scene, group, motionMetaData); + } + } + + const AZStd::string& manifestFilename = scene->GetManifestFilename(); + const bool fileExisted = AZ::IO::FileIOBase::GetInstance()->Exists(manifestFilename.c_str()); + + // Source Control: Checkout file. + if (fileExisted) + { + using ApplicationBus = AzToolsFramework::ToolsApplicationRequestBus; + bool checkoutResult = false; + ApplicationBus::BroadcastResult(checkoutResult, &ApplicationBus::Events::RequestEditForFileBlocking, manifestFilename.c_str(), "Checking out manifest from source control.", []([[maybe_unused]] int& current, [[maybe_unused]] int& max) {}); + if (!checkoutResult) + { + AZ_Error("EMotionFX", false, "Cannot checkout file '%s' from source control.", manifestFilename.c_str()); + return false; + } + } + + const bool saveResult = manifest.SaveToFile(manifestFilename.c_str()); if (saveResult) { motion->SetDirtyFlag(false); } + // Source Control: Add file in case it did not exist before (when saving it the first time). + if (saveResult && !fileExisted) + { + using ApplicationBus = AzToolsFramework::ToolsApplicationRequestBus; + bool checkoutResult = false; + ApplicationBus::BroadcastResult(checkoutResult, &ApplicationBus::Events::RequestEditForFileBlocking, manifestFilename.c_str(), "Adding manifest to source control.", []([[maybe_unused]] int& current, [[maybe_unused]] int& max) {}); + AZ_Error("EMotionFX", checkoutResult, "Cannot add file '%s' to source control.", manifestFilename.c_str()); + } + return saveResult; } diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp index 0a1137d7d9..69cccace81 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/ActorAsset.cpp @@ -63,6 +63,8 @@ namespace EMotionFX &actorSettings, ""); + // Set the is owned by runtime flag before finalizing the actor, as that uses the flag already. + assetData->m_emfxActor->SetIsOwnedByRuntime(true); assetData->m_emfxActor->Finalize(); // Clear out the EMFX raw asset data. @@ -74,8 +76,6 @@ namespace EMotionFX return false; } - assetData->m_emfxActor->SetIsOwnedByRuntime(true); - // Note: Render actor depends on the mesh asset, so we need to manually create it after mesh asset has been loaded. return static_cast(assetData->m_emfxActor); } diff --git a/Gems/EMotionFX/Code/Tests/EventManagerTests.cpp b/Gems/EMotionFX/Code/Tests/EventManagerTests.cpp index 6ab796691c..c717a1b27e 100644 --- a/Gems/EMotionFX/Code/Tests/EventManagerTests.cpp +++ b/Gems/EMotionFX/Code/Tests/EventManagerTests.cpp @@ -31,8 +31,8 @@ TEST_F(SystemComponentFixture, DISABLED_EventDataFactoryMakesUniqueData) EXPECT_EQ(loadedTrack->GetEvent(0).GetEventDatas()[0], track->GetEvent(0).GetEventDatas()[0]); EXPECT_EQ(loadedTrack->GetEvent(0).GetEventDatas()[0].use_count(), 2); - track->Destroy(); - loadedTrack->Destroy(); + delete track; + delete loadedTrack; } } // end namespace EMotionFX diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 7a57f3aeb4..ff23f21945 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -202,12 +202,6 @@ namespace LyShine LyShineAllocatorScope::DeactivateAllocators(); } - //////////////////////////////////////////////////////////////////////////////////////////////////// - void LyShineSystemComponent::InitializeSystem() - { - BroadcastCursorImagePathname(); - } - //////////////////////////////////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::RegisterComponentTypeForMenuOrdering(const AZ::Uuid& typeUuid) { @@ -379,6 +373,8 @@ namespace LyShine #endif m_pLyShine = new CLyShine(gEnv->pSystem); gEnv->pLyShine = m_pLyShine; + + BroadcastCursorImagePathname(); } void LyShineSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.h b/Gems/LyShine/Code/Source/LyShineSystemComponent.h index f4bd478067..50a8ee5aba 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.h +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.h @@ -60,7 +60,6 @@ namespace LyShine //////////////////////////////////////////////////////////////////////// // UiSystemBus interface implementation - void InitializeSystem() override; void RegisterComponentTypeForMenuOrdering(const AZ::Uuid& typeUuid) override; const AZStd::vector* GetComponentTypesForMenuOrdering() override; const AZStd::list* GetLyShineComponentDescriptors(); diff --git a/cmake/Platform/Windows/Packaging/Template.wxs.in b/cmake/Platform/Windows/Packaging/Template.wxs.in index e14e064fbc..6d4dd54f75 100644 --- a/cmake/Platform/Windows/Packaging/Template.wxs.in +++ b/cmake/Platform/Windows/Packaging/Template.wxs.in @@ -14,8 +14,10 @@ - - + +