[LYN-4574] [LYN-4603] [LYN-4669] Saving motions and actors to json-based .assetinfo files in the Animation Editor fails (#1509)
* Fixes saving motions from within the Animation Editor * Fixes saving actors from within the Animation Editor * The motion event chunk of the .motion file format now also stores the event data as json (rather than XML) reducing motion file sizes (Example: 60KB motion went down to 49KB, containing only 4 motion events from 2 tracks). * Fully backward compatible * New motion meta data rule stores the event data directly rather than command strings or objects. This is the way that aligns with the Json paradigm and as side-effect bypasses the optionals that we use for the commands which fixes the issue. * [LYN-4574] Adding new motion event meta data rule that stores the event data directly rather than via commands to align with the Json paradigm * [LYN-4574] Preparing motion, event table and event track for Json serialization * [LYN-4574] New chunk to store motion event data in Json format (fully backward compatible to XML) * [LYN-4669] Json: Empty AZStd::vector<AZStd::shared_ptr<T>> serializes into 1x element with nullptr as data * [LYN-4603] EMotion FX: Cannot save actors with physics or simulated object setup in Json format
This commit is contained in:
@@ -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())
|
||||
|
||||
@@ -24,48 +24,6 @@
|
||||
|
||||
namespace CommandSystem
|
||||
{
|
||||
|
||||
AZStd::vector<MCore::Command*> MetaData::GenerateMotionMetaData(EMotionFX::Motion* motion)
|
||||
{
|
||||
AZStd::vector<MCore::Command*> 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<MCore::Command*>& metaDataCommands)
|
||||
{
|
||||
for (MCore::Command* command : metaDataCommands)
|
||||
|
||||
@@ -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<MCore::Command*> 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.
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
#include "Exporter.h"
|
||||
#include <MCore/Source/ReflectionSerializer.h>
|
||||
#include <EMotionFX/Source/MotionEvent.h>
|
||||
@@ -28,17 +35,38 @@ namespace ExporterLib
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Outcome<AZStd::string> 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<uint32>(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
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
||||
|
||||
#include <SceneAPIExt/Rules/MetaDataRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionMetaDataRule.h>
|
||||
#include <SceneAPIExt/Groups/IMotionGroup.h>
|
||||
#include <RCExt/Motion/MotionGroupExporter.h>
|
||||
#include <RCExt/ExportContexts.h>
|
||||
@@ -72,7 +73,7 @@ namespace EMotionFX
|
||||
result += SceneEvents::Process<MotionDataBuilderContext>(dataBuilderContext, AZ::RC::Phase::Filling);
|
||||
result += SceneEvents::Process<MotionDataBuilderContext>(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<MCore::Command*> metaDataCommands;
|
||||
if (Rule::MetaDataRule::LoadMetaData(motionGroup, metaDataCommands))
|
||||
{
|
||||
@@ -82,6 +83,15 @@ namespace EMotionFX
|
||||
}
|
||||
}
|
||||
|
||||
// Apply motion meta data.
|
||||
EMotionFX::Pipeline::Rule::MotionMetaData motionMetaData;
|
||||
if (EMotionFX::Pipeline::Rule::LoadFromGroup<EMotionFX::Pipeline::Rule::MotionMetaDataRule, EMotionFX::Pipeline::Rule::MotionMetaData>(motionGroup, motionMetaData))
|
||||
{
|
||||
motion->SetEventTable(AZStd::unique_ptr<MotionEventTable>(motionMetaData.m_motionEventTable));
|
||||
motion->GetEventTable()->InitAfterLoading(motion);
|
||||
motion->SetMotionExtractionFlags(motionMetaData.m_motionExtractionFlags);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
+9
-6
@@ -17,12 +17,13 @@
|
||||
|
||||
#include <SceneAPIExt/Behaviors/MotionGroupBehavior.h>
|
||||
#include <SceneAPIExt/Groups/MotionGroup.h>
|
||||
#include <SceneAPIExt/Rules/MotionScaleRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionAdditiveRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionCompressionSettingsRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionMetaDataRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionSamplingRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionScaleRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionRangeRule.h>
|
||||
#include <SceneAPIExt/Rules/MorphTargetRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionAdditiveRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionSamplingRule.h>
|
||||
|
||||
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<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Groups/IGroup.h>
|
||||
#include <SceneAPI/SceneCore/Events/ManifestMetaInfoBus.h>
|
||||
#include <SceneAPIExt/Rules/MotionMetaDataRule.h>
|
||||
|
||||
namespace EMotionFX::Pipeline::Rule
|
||||
{
|
||||
void MotionMetaData::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (!serializeContext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
serializeContext->Class<MotionMetaData>()
|
||||
->Version(1)
|
||||
->Field("motionEventTable", &MotionMetaData::m_motionEventTable)
|
||||
->Field("motionExtractionFlags", &MotionMetaData::m_motionExtractionFlags)
|
||||
;
|
||||
}
|
||||
|
||||
MotionMetaDataRule::MotionMetaDataRule()
|
||||
: ExternalToolRule<MotionMetaData>()
|
||||
{
|
||||
}
|
||||
|
||||
MotionMetaDataRule::MotionMetaDataRule(const MotionMetaData& data)
|
||||
: MotionMetaDataRule()
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
void MotionMetaDataRule::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<MotionMetaDataRule>()
|
||||
->Version(1)
|
||||
->Field("data", &MotionMetaDataRule::m_data)
|
||||
;
|
||||
}
|
||||
}
|
||||
} // EMotionFX::Pipeline::Rule
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <EMotionFX/Source/MotionEventTable.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
|
||||
#include <SceneAPI/SceneData/SceneDataConfiguration.h>
|
||||
#include <SceneAPIExt/Rules/ExternalToolRule.h>
|
||||
|
||||
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() = default;
|
||||
virtual ~MotionMetaData() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
EMotionFX::MotionEventTable* m_motionEventTable = nullptr;
|
||||
EMotionFX::EMotionExtractionFlags m_motionExtractionFlags;
|
||||
};
|
||||
|
||||
class MotionMetaDataRule
|
||||
: public ExternalToolRule<MotionMetaData>
|
||||
{
|
||||
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 MotionMetaData& data);
|
||||
~MotionMetaDataRule() final = default;
|
||||
|
||||
const MotionMetaData& GetData() const override { return m_data; }
|
||||
void SetData(const MotionMetaData& data) override { m_data = data; }
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
MotionMetaData m_data;
|
||||
};
|
||||
} // EMotionFX::Pipeline::Rule
|
||||
@@ -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
|
||||
|
||||
@@ -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<AZ::SerializeContext*>(context);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,10 +6,17 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/JSON/rapidjson.h>
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
|
||||
#include <EMotionFX/Source/Parameter/GroupParameter.h>
|
||||
#include <EMotionFX/Source/Parameter/ParameterFactory.h>
|
||||
#include <MCore/Source/AttributeFactory.h>
|
||||
@@ -1161,10 +1168,11 @@ namespace EMotionFX
|
||||
AZStd::vector<char> buffer(fileEventTable.m_size);
|
||||
file->Read(&buffer[0], fileEventTable.m_size);
|
||||
|
||||
MotionEventTable* motionEventTable = AZ::Utils::LoadObjectFromBuffer<MotionEventTable>(&buffer[0], buffer.size(), context);
|
||||
auto motionEventTable = AZStd::unique_ptr<MotionEventTable>(AZ::Utils::LoadObjectFromBuffer<MotionEventTable>(&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<char> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1061,6 +1061,7 @@ namespace EMotionFX
|
||||
// shared processors
|
||||
RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable());
|
||||
RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable2());
|
||||
RegisterChunkProcessor(aznew ChunkProcessorMotionEventTrackTable3());
|
||||
|
||||
// Actor file format
|
||||
RegisterChunkProcessor(aznew ChunkProcessorActorInfo());
|
||||
|
||||
@@ -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<EMotionExtractionFlags>(0);
|
||||
m_motionData = nullptr;
|
||||
mID = MCore::GetIDGenerator().GenerateID();
|
||||
m_eventTable = AZStd::make_unique<MotionEventTable>();
|
||||
mUnitType = GetEMotionFX().GetUnitType();
|
||||
mFileUnitType = mUnitType;
|
||||
mExtractionFlags = static_cast<EMotionExtractionFlags>(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<MotionEventTable> eventTable)
|
||||
{
|
||||
if (mEventTable && mEventTable != newTable)
|
||||
{
|
||||
mEventTable->Destroy();
|
||||
}
|
||||
mEventTable = newTable;
|
||||
m_eventTable = AZStd::move(eventTable);
|
||||
}
|
||||
|
||||
|
||||
void Motion::SetID(uint32 id)
|
||||
{
|
||||
mID = id;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// include the required headers
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#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<MotionEventTable> 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<MotionEventTable> 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;
|
||||
|
||||
@@ -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<AZ::SerializeContext*>(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
|
||||
{
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// include the required headers
|
||||
#include "EMotionFXConfig.h"
|
||||
#include "BaseObject.h"
|
||||
#include "AnimGraphSyncTrack.h"
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
@@ -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<MotionEventTrack*> m_tracks;
|
||||
|
||||
/// A shortcut to the track containing sync events.
|
||||
AnimGraphSyncTrack* m_syncTrack;
|
||||
|
||||
AnimGraphSyncTrack* m_syncTrack = nullptr;
|
||||
};
|
||||
} // namespace EMotionFX
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// include the required headers
|
||||
#include "MotionEventTrack.h"
|
||||
#include "MotionEvent.h"
|
||||
#include "EventManager.h"
|
||||
@@ -20,30 +19,19 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
|
||||
|
||||
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<MotionEventTrack>()
|
||||
->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<MCore::StringIdPoolIndex>(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;
|
||||
|
||||
@@ -7,13 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// include the required headers
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include "EMotionFXConfig.h"
|
||||
#include "BaseObject.h"
|
||||
#include "MotionEvent.h"
|
||||
#include <MCore/Source/StringIdPool.h>
|
||||
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
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<MotionEvent> 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<void(EMotionFX::EventInfo&)>& processFunc);
|
||||
|
||||
template <typename Functor>
|
||||
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
|
||||
|
||||
@@ -298,14 +298,20 @@ namespace EMotionFX
|
||||
{
|
||||
Physics::CapsuleShapeConfiguration* capsule = static_cast<Physics::CapsuleShapeConfiguration*>(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<Physics::BoxShapeConfiguration>())
|
||||
{
|
||||
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<Physics::BoxShapeConfiguration*>(collider.second.get());
|
||||
box->m_dimensions = AZ::Vector3(2.0f * rootMeanSquareDistanceFromBone, 2.0f * rootMeanSquareDistanceFromBone, boneLength);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <SceneAPIExt/Rules/ActorPhysicsSetupRule.h>
|
||||
#include <SceneAPIExt/Rules/SimulatedObjectSetupRule.h>
|
||||
#include <SceneAPIExt/Rules/MetaDataRule.h>
|
||||
#include <SceneAPIExt/Rules/MotionMetaDataRule.h>
|
||||
#include <SceneAPIExt/Groups/MotionGroup.h>
|
||||
#include <SceneAPIExt/Groups/ActorGroup.h>
|
||||
|
||||
@@ -293,16 +294,65 @@ 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<MCore::Command*> metaData = CommandSystem::MetaData::GenerateMotionMetaData(motion);
|
||||
// Load the manifest from disk.
|
||||
AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene> 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<EMotionFX::Pipeline::Group::MotionGroup>(sourceAssetFilename, groupName, metaData, outResult);
|
||||
AZ::SceneAPI::Containers::SceneManifest& manifest = scene->GetManifest();
|
||||
auto values = manifest.GetValueStorage();
|
||||
auto groupView = AZ::SceneAPI::Containers::MakeDerivedFilterView<EMotionFX::Pipeline::Group::MotionGroup>(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<EMotionFX::Pipeline::Rule::MetaDataRule, const AZStd::vector<MCore::Command*>>(*scene, group);
|
||||
|
||||
// Add motion meta data.
|
||||
EMotionFX::Pipeline::Rule::MotionMetaData motionMetaData;
|
||||
motionMetaData.m_motionEventTable = motion->GetEventTable();
|
||||
motionMetaData.m_motionExtractionFlags = motion->GetMotionExtractionFlags();
|
||||
EMotionFX::Pipeline::Rule::SaveToGroup<EMotionFX::Pipeline::Rule::MotionMetaDataRule, EMotionFX::Pipeline::Rule::MotionMetaData>(*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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user