| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Component/ComponentApplication.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <AzCore/Utils/Utils.h>
- #include <AzFramework/Physics/CharacterBus.h>
- #include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
- #include <EMotionFX/Source/Allocators.h>
- #include <EMotionFX/Source/SingleThreadScheduler.h>
- #include <EMotionFX/Source/EMotionFXManager.h>
- #include <EMotionFX/Source/AnimGraphManager.h>
- #include <EMotionFX/Source/AnimGraphObjectFactory.h>
- #include <EMotionFX/Source/MotionSet.h>
- #include <EMotionFX/Source/Recorder.h>
- #include <EMotionFX/Source/ConstraintTransformRotationAngles.h>
- #include <EMotionFX/Source/Parameter/ParameterFactory.h>
- #include <EMotionFX/Source/TwoStringEventData.h>
- #include <EMotionFX/Source/EventDataFootIK.h>
- #include <EMotionFX/Source/EventDataFloatArray.h>
- #include <EMotionFX/Source/MotionEvent.h>
- #include <EMotionFX/Source/AnimGraphNodeGroup.h>
- #include <EMotionFX/Source/MotionEventTable.h>
- #include <EMotionFX/Source/MotionEventTrack.h>
- #include <EMotionFX/Source/AnimGraphSyncTrack.h>
- #include <EMotionFX/Source/AnimGraph.h>
- #include <EMotionFX/Source/ActorManager.h>
- #include <EMotionFX/Source/ObjectId.h>
- #include <EMotionFX/Source/PhysicsSetup.h>
- #include <EMotionFX/Source/SimulatedObjectSetup.h>
- #include <MCore/Source/Command.h>
- #include <EMotionFX/CommandSystem/Source/MotionEventCommands.h>
- #include <EMotionFX/CommandSystem/Source/SimulatedObjectCommands.h>
- #include <EMotionFX/CommandSystem/Source/RagdollCommands.h>
- #include <EMotionFX/Source/PoseData.h>
- #include <EMotionFX/Source/PoseDataRagdoll.h>
- #include <Integration/AnimationBus.h>
- #include <Integration/EMotionFXBus.h>
- #include <Integration/Assets/ActorAsset.h>
- #include <Integration/Assets/MotionAsset.h>
- #include <Integration/Assets/MotionSetAsset.h>
- #include <Integration/Assets/AnimGraphAsset.h>
- #include <Integration/System/SystemComponent.h>
- #include <Integration/System/CVars.h>
- #include <AzFramework/Physics/PhysicsScene.h>
- #include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
- #include <AzFramework/Physics/Common/PhysicsTypes.h>
- #include <Integration/MotionExtractionBus.h>
- #if defined(EMOTIONFXANIMATION_EDITOR) // EMFX tools / editor includes
- // Qt
- #include <QtGui/QSurfaceFormat>
- // EMStudio tools and main window registration
- #include <LyViewPaneNames.h>
- #include <AzToolsFramework/ActionManager/Action/ActionManagerInterface.h>
- #include <AzToolsFramework/API/ViewPaneOptions.h>
- #include <AzQtComponents/Components/FancyDocking.h>
- #include <AzCore/std/string/wildcard.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <QApplication>
- #include <EMotionStudio/EMStudioSDK/Source/MainWindow.h>
- #include <EMotionStudio/EMStudioSDK/Source/PluginManager.h>
- #include <Source/Editor/PropertyWidgets/PropertyTypes.h>
- #include <EMotionFX_Traits_Platform.h>
- #include <EMotionFX/Source/AnimGraphStateMachine.h>
- #include <EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h>
- #include <EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
- #include <EMotionStudio/Plugins/StandardPlugins/Source/MotionSetsWindow/MotionSetsWindowPlugin.h>
- #include <IEditor.h>
- #endif // EMOTIONFXANIMATION_EDITOR
- #include <IConsole.h>
- #include <ISystem.h>
- // include required AzCore headers
- #include <AzCore/IO/FileIO.h>
- #include <AzFramework/API/ApplicationAPI.h>
- namespace EMotionFX
- {
- namespace Integration
- {
- //////////////////////////////////////////////////////////////////////////
- class EMotionFXEventHandler
- : public EMotionFX::EventHandler
- {
- public:
- AZ_CLASS_ALLOCATOR(EMotionFXEventHandler, EMotionFXAllocator);
- const AZStd::vector<EventTypes> GetHandledEventTypes() const override
- {
- return {
- EVENT_TYPE_ON_EVENT,
- EVENT_TYPE_ON_HAS_LOOPED,
- EVENT_TYPE_ON_STATE_ENTERING,
- EVENT_TYPE_ON_STATE_ENTER,
- EVENT_TYPE_ON_STATE_END,
- EVENT_TYPE_ON_STATE_EXIT,
- EVENT_TYPE_ON_START_TRANSITION,
- EVENT_TYPE_ON_END_TRANSITION
- };
- }
- /// Dispatch motion events to listeners via ActorNotificationBus::OnMotionEvent.
- void OnEvent(const EMotionFX::EventInfo& emfxInfo) override
- {
- const ActorInstance* actorInstance = emfxInfo.m_actorInstance;
- if (actorInstance)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- // Fill engine-compatible structure to dispatch to game code.
- MotionEvent motionEvent;
- motionEvent.m_entityId = owningEntityId;
- motionEvent.m_actorInstance = emfxInfo.m_actorInstance;
- motionEvent.m_motionInstance = emfxInfo.m_motionInstance;
- motionEvent.m_time = emfxInfo.m_timeValue;
- // TODO
- for (const auto& eventData : emfxInfo.m_event->GetEventDatas())
- {
- if (const EMotionFX::TwoStringEventData* twoStringEventData = azrtti_cast<const EMotionFX::TwoStringEventData*>(eventData.get()))
- {
- motionEvent.m_eventTypeName = twoStringEventData->GetSubject().c_str();
- motionEvent.SetParameterString(twoStringEventData->GetParameters().c_str(), twoStringEventData->GetParameters().size());
- break;
- }
- if (const EMotionFX::EventDataFloatArray* floatArrayEventData =
- azrtti_cast<const EMotionFX::EventDataFloatArray*>(eventData.get()))
- {
- motionEvent.m_eventTypeName = floatArrayEventData->GetSubject().c_str();
- const AZStd::string parameterString = floatArrayEventData->DataToString();
- motionEvent.SetParameterString(parameterString.c_str(), parameterString.size());
- break;
- }
- }
- motionEvent.m_globalWeight = emfxInfo.m_globalWeight;
- motionEvent.m_localWeight = emfxInfo.m_localWeight;
- motionEvent.m_isEventStart = emfxInfo.IsEventStart();
- // Queue the event to flush on the main thread.
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnMotionEvent, AZStd::move(motionEvent));
- }
- }
- void OnHasLooped(EMotionFX::MotionInstance* motionInstance) override
- {
- const ActorInstance* actorInstance = motionInstance->GetActorInstance();
- if (actorInstance)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnMotionLoop, motionInstance->GetMotion()->GetName());
- }
- }
- void OnStateEntering(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphNode* state) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance && state)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateEntering, state->GetName());
- }
- }
- void OnStateEnter(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphNode* state) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance && state)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateEntered, state->GetName());
- }
- }
- void OnStateEnd(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphNode* state) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance && state)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateExiting, state->GetName());
- }
- }
- void OnStateExit(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphNode* state) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance && state)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateExited, state->GetName());
- }
- }
- void OnStartTransition(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphStateTransition* transition) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- const char* sourceName = transition->GetSourceNode() ? transition->GetSourceNode()->GetName() : "";
- const char* targetName = transition->GetTargetNode() ? transition->GetTargetNode()->GetName() : "";
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateTransitionStart, sourceName, targetName);
- }
- }
- void OnEndTransition(EMotionFX::AnimGraphInstance* animGraphInstance, EMotionFX::AnimGraphStateTransition* transition) override
- {
- const ActorInstance* actorInstance = animGraphInstance->GetActorInstance();
- if (actorInstance)
- {
- const AZ::EntityId owningEntityId = actorInstance->GetEntityId();
- const char* sourceName = transition->GetSourceNode() ? transition->GetSourceNode()->GetName() : "";
- const char* targetName = transition->GetTargetNode() ? transition->GetTargetNode()->GetName() : "";
- ActorNotificationBus::QueueEvent(owningEntityId, &ActorNotificationBus::Events::OnStateTransitionEnd, sourceName, targetName);
- }
- }
- };
- //////////////////////////////////////////////////////////////////////////
- class ActorNotificationBusHandler
- : public ActorNotificationBus::Handler
- , public AZ::BehaviorEBusHandler
- {
- public:
- AZ_EBUS_BEHAVIOR_BINDER(ActorNotificationBusHandler, "{D2CD62E7-5FCF-4DC2-85DF-C205D5AB1E8B}", AZ::SystemAllocator,
- OnMotionEvent,
- OnMotionLoop,
- OnStateEntering,
- OnStateEntered,
- OnStateExiting,
- OnStateExited,
- OnStateTransitionStart,
- OnStateTransitionEnd);
- void OnMotionEvent(MotionEvent motionEvent) override
- {
- Call(FN_OnMotionEvent, motionEvent);
- }
- void OnMotionLoop(const char* motionName) override
- {
- Call(FN_OnMotionLoop, motionName);
- }
- void OnStateEntering(const char* stateName) override
- {
- Call(FN_OnStateEntering, stateName);
- }
- void OnStateEntered(const char* stateName) override
- {
- Call(FN_OnStateEntered, stateName);
- }
- void OnStateExiting(const char* stateName) override
- {
- Call(FN_OnStateExiting, stateName);
- }
- void OnStateExited(const char* stateName) override
- {
- Call(FN_OnStateExited, stateName);
- }
- void OnStateTransitionStart(const char* fromState, const char* toState) override
- {
- Call(FN_OnStateTransitionStart, fromState, toState);
- }
- void OnStateTransitionEnd(const char* fromState, const char* toState) override
- {
- Call(FN_OnStateTransitionEnd, fromState, toState);
- }
- };
- SystemComponent::~SystemComponent() = default;
- void SystemComponent::ReflectEMotionFX(AZ::ReflectContext* context)
- {
- MCore::ReflectionSerializer::Reflect(context);
- MCore::StringIdPoolIndex::Reflect(context);
- EMotionFX::ConstraintTransformRotationAngles::Reflect(context);
- EMotionFX::ObjectId::Reflect(context);
- // Actor
- EMotionFX::PhysicsSetup::Reflect(context);
- EMotionFX::SimulatedObjectSetup::Reflect(context);
- EMotionFX::PoseData::Reflect(context);
- EMotionFX::PoseDataRagdoll::Reflect(context);
- // Motion set
- EMotionFX::MotionSet::Reflect(context);
- EMotionFX::MotionSet::MotionEntry::Reflect(context);
- // Base AnimGraph objects
- EMotionFX::AnimGraphObject::Reflect(context);
- EMotionFX::AnimGraph::Reflect(context);
- EMotionFX::AnimGraphNodeGroup::Reflect(context);
- // Anim graph objects
- EMotionFX::AnimGraphObjectFactory::ReflectTypes(context);
- // Anim graph's parameters
- EMotionFX::ParameterFactory::ReflectParameterTypes(context);
- EMotionFX::MotionEventTable::Reflect(context);
- EMotionFX::MotionEventTrack::Reflect(context);
- EMotionFX::AnimGraphSyncTrack::Reflect(context);
- EMotionFX::Event::Reflect(context);
- EMotionFX::MotionEvent::Reflect(context);
- EMotionFX::EventData::Reflect(context);
- EMotionFX::EventDataSyncable::Reflect(context);
- EMotionFX::TwoStringEventData::Reflect(context);
- EMotionFX::EventDataFootIK::Reflect(context);
- EMotionFX::EventDataFloatArray::Reflect(context);
- EMotionFX::Recorder::Reflect(context);
- EMotionFX::KeyTrackLinearDynamic<AZ::Vector3>::Reflect(context);
- EMotionFX::KeyTrackLinearDynamic<AZ::Quaternion>::Reflect(context);
- EMotionFX::KeyFrame<AZ::Vector3>::Reflect(context);
- EMotionFX::KeyFrame<AZ::Quaternion>::Reflect(context);
- MCore::Command::Reflect(context);
- CommandSystem::MotionIdCommandMixin::Reflect(context);
- CommandSystem::CommandAdjustMotion::Reflect(context);
- CommandSystem::CommandClearMotionEvents::Reflect(context);
- CommandSystem::CommandCreateMotionEventTrack::Reflect(context);
- CommandSystem::CommandAdjustMotionEventTrack::Reflect(context);
- CommandSystem::CommandCreateMotionEvent::Reflect(context);
- CommandSystem::CommandAdjustMotionEvent::Reflect(context);
- EMotionFX::CommandAdjustSimulatedObject::Reflect(context);
- EMotionFX::CommandAdjustSimulatedJoint::Reflect(context);
- EMotionFX::CommandAddRagdollJoint::Reflect(context);
- EMotionFX::CommandAdjustRagdollJoint::Reflect(context);
- EMotionFX::CommandRemoveRagdollJoint::Reflect(context);
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::Reflect(AZ::ReflectContext* context)
- {
- ReflectEMotionFX(context);
- // Reflect component for serialization.
- AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
- if (serializeContext)
- {
- serializeContext->Class<SystemComponent, AZ::Component>()
- ->Version(1)
- ->Field("NumThreads", &SystemComponent::m_numThreads)
- ;
- serializeContext->Class<MotionEvent>()
- ->Version(1)
- ;
- if (AZ::EditContext* ec = serializeContext->GetEditContext())
- {
- ec->Class<SystemComponent>("EMotion FX Animation", "Enables the EMotion FX animation solution")
- ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
- ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
- ->DataElement(AZ::Edit::UIHandlers::Default, &SystemComponent::m_numThreads, "Number of threads", "Number of threads used internally by EMotion FX")
- ;
- }
- }
- // Reflect system-level types and EBuses to behavior context.
- AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
- if (behaviorContext)
- {
- behaviorContext->EBus<SystemRequestBus>("SystemRequestBus")
- ;
- behaviorContext->EBus<SystemNotificationBus>("SystemNotificationBus")
- ;
- // In order for a property to be displayed in ScriptCanvas.
- behaviorContext->Class<MotionEvent>("MotionEvent")
- ->Property("entityId", BehaviorValueGetter(&MotionEvent::m_entityId), nullptr)
- ->Property("parameter", BehaviorValueGetter(&MotionEvent::m_parameter), nullptr)
- ->Property("eventType", BehaviorValueGetter(&MotionEvent::m_eventType), nullptr)
- ->Property("eventTypeName", BehaviorValueGetter(&MotionEvent::m_eventTypeName), nullptr)
- ->Property("time", BehaviorValueGetter(&MotionEvent::m_time), nullptr)
- ->Property("globalWeight", BehaviorValueGetter(&MotionEvent::m_globalWeight), nullptr)
- ->Property("localWeight", BehaviorValueGetter(&MotionEvent::m_localWeight), nullptr)
- ->Property("isEventStart", BehaviorValueGetter(&MotionEvent::m_isEventStart), nullptr)
- ;
- behaviorContext->EBus<ActorNotificationBus>("ActorNotificationBus")
- ->Handler<ActorNotificationBusHandler>()
- ->Event("OnMotionEvent", &ActorNotificationBus::Events::OnMotionEvent)
- ->Event("OnMotionLoop", &ActorNotificationBus::Events::OnMotionLoop)
- ->Event("OnStateEntering", &ActorNotificationBus::Events::OnStateEntering)
- ->Event("OnStateEntered", &ActorNotificationBus::Events::OnStateEntered)
- ->Event("OnStateExiting", &ActorNotificationBus::Events::OnStateExiting)
- ->Event("OnStateExited", &ActorNotificationBus::Events::OnStateExited)
- ->Event("OnStateTransitionStart", &ActorNotificationBus::Events::OnStateTransitionStart)
- ->Event("OnStateTransitionEnd", &ActorNotificationBus::Events::OnStateTransitionEnd)
- ;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
- {
- provided.push_back(AZ_CRC("EMotionFXAnimationService", 0x3f8a6369));
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
- {
- incompatible.push_back(AZ_CRC("EMotionFXAnimationService", 0x3f8a6369));
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
- {
- required.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
- {
- dependent.push_back(AZ_CRC("AssetCatalogService", 0xc68ffc57));
- dependent.push_back(AZ_CRC("JobsService", 0xd5ab5a50));
- }
- //////////////////////////////////////////////////////////////////////////
- SystemComponent::SystemComponent()
- : m_numThreads(1)
- {
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::Init()
- {
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::Activate()
- {
- // Initialize MCore, which is EMotionFX's standard library of containers and systems.
- MCore::Initializer::InitSettings coreSettings;
- coreSettings.m_memAllocFunction = &EMotionFXAlloc;
- coreSettings.m_memReallocFunction = &EMotionFXRealloc;
- coreSettings.m_memFreeFunction = &EMotionFXFree;
- if (!MCore::Initializer::Init(&coreSettings))
- {
- AZ_Error("EMotion FX Animation", false, "Failed to initialize EMotion FX SDK Core");
- return;
- }
- // Initialize EMotionFX runtime.
- EMotionFX::Initializer::InitSettings emfxSettings;
- emfxSettings.m_unitType = MCore::Distance::UNITTYPE_METERS;
- if (!EMotionFX::Initializer::Init(&emfxSettings))
- {
- AZ_Error("EMotion FX Animation", false, "Failed to initialize EMotion FX SDK Runtime");
- return;
- }
- SetMediaRoot("@products@");
- // \todo Right now we're pointing at the @projectroot@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through
- // the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @products@ cache, but write to the @projectroot@ data/metadata.
- EMotionFX::GetEMotionFX().InitAssetFolderPaths();
- // Register EMotionFX event handler
- m_eventHandler.reset(aznew EMotionFXEventHandler());
- EMotionFX::GetEventManager().AddEventHandler(m_eventHandler.get());
- // Setup asset types.
- RegisterAssetTypesAndHandlers();
- SystemRequestBus::Handler::BusConnect();
- AZ::TickBus::Handler::BusConnect();
- CrySystemEventBus::Handler::BusConnect();
- EMotionFXRequestBus::Handler::BusConnect();
- EnableRayRequests();
- m_renderBackendManager = AZStd::make_unique<RenderBackendManager>();
- #if defined (EMOTIONFXANIMATION_EDITOR)
- AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
- AzToolsFramework::EditorAnimationSystemRequestsBus::Handler::BusConnect();
- AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
- AzToolsFramework::ActionManagerRegistrationNotificationBus::Handler::BusConnect();
- // Register custom property handlers for the reflected property editor.
- m_propertyHandlers = RegisterPropertyTypes();
- #endif // EMOTIONFXANIMATION_EDITOR
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::Deactivate()
- {
- #if defined(EMOTIONFXANIMATION_EDITOR)
- // Unregister custom property handlers for the reflected property editor.
- UnregisterPropertyTypes(m_propertyHandlers);
- m_propertyHandlers.clear();
- if (EMStudio::GetManager())
- {
- m_emstudioManager.reset();
- MysticQt::Initializer::Shutdown();
- }
- {
- using namespace AzToolsFramework;
- EditorRequests::Bus::Broadcast(&EditorRequests::UnregisterViewPane, EMStudio::MainWindow::GetEMotionFXPaneName());
- }
- AzToolsFramework::ActionManagerRegistrationNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::EditorAnimationSystemRequestsBus::Handler::BusDisconnect();
- AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
- #endif // EMOTIONFXANIMATION_EDITOR
- m_renderBackendManager.reset();
- EMotionFX::GetEventManager().RemoveEventHandler(m_eventHandler.get());
- m_eventHandler.reset();
- AZ::TickBus::Handler::BusDisconnect();
- CrySystemEventBus::Handler::BusDisconnect();
- EMotionFXRequestBus::Handler::BusDisconnect();
- DisableRayRequests();
- if (SystemRequestBus::Handler::BusIsConnected())
- {
- SystemRequestBus::Handler::BusDisconnect();
- m_assetHandlers.resize(0);
- EMotionFX::Initializer::Shutdown();
- MCore::Initializer::Shutdown();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::EnableRayRequests()
- {
- AZ::Interface<IRaycastRequests>::Unregister(this);
- AZ::Interface<IRaycastRequests>::Register(this);
- }
- void SystemComponent::DisableRayRequests()
- {
- AZ::Interface<IRaycastRequests>::Unregister(this);
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::OnCrySystemInitialized([[maybe_unused]] ISystem& system, const SSystemInitParams&)
- {
- #if !defined(AZ_MONOLITHIC_BUILD)
- // When module is linked dynamically, we must set our gEnv pointer.
- // When module is linked statically, we'll share the application's gEnv pointer.
- gEnv = system.GetGlobalEnvironment();
- #endif
- REGISTER_CVAR2("emfx_updateEnabled", &CVars::emfx_updateEnabled, 1, VF_DEV_ONLY, "Enable main EMFX update");
- REGISTER_CVAR2(
- "emfx_ragdollManipulatorsEnabled", &CVars::emfx_ragdollManipulatorsEnabled, 1, VF_DEV_ONLY,
- "Feature flag for in development ragdoll manipulators");
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::OnCrySystemShutdown(ISystem&)
- {
- gEnv->pConsole->UnregisterVariable("emfx_updateEnabled");
- gEnv->pConsole->UnregisterVariable("emfx_ragdollManipulatorsEnabled");
- #if !defined(AZ_MONOLITHIC_BUILD)
- gEnv = nullptr;
- #endif
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::OnTick(float delta, [[maybe_unused]]AZ::ScriptTimePoint timePoint)
- {
- // Flush events prior to updating EMotion FX.
- ActorNotificationBus::ExecuteQueuedEvents();
- if (CVars::emfx_updateEnabled)
- {
- // Main EMotionFX runtime update.
- GetEMotionFX().Update(delta);
- bool inGameMode = true;
- #if defined (EMOTIONFXANIMATION_EDITOR)
- // Check if we are in game mode.
- IEditor* editor = nullptr;
- AzToolsFramework::EditorRequestBus::BroadcastResult(editor, &AzToolsFramework::EditorRequests::GetEditor);
- inGameMode = !editor || editor->IsInGameMode();
- #endif
- // Apply the motion extraction deltas to the character controller / entity transform for all entities.
- const ActorManager* actorManager = GetEMotionFX().GetActorManager();
- const size_t numActorInstances = actorManager->GetNumActorInstances();
- for (size_t i = 0; i < numActorInstances; ++i)
- {
- ActorInstance* actorInstance = actorManager->GetActorInstance(i);
- // Apply motion extraction only in game mode or in case the actor instance belongs to the Animation Editor.
- const bool applyMotionExtraction = inGameMode || !actorInstance->GetIsOwnedByRuntime();
- if (applyMotionExtraction)
- {
- actorInstance->SetMotionExtractionEnabled(true);
- ApplyMotionExtraction(actorInstance, delta);
- }
- else
- {
- actorInstance->SetMotionExtractionEnabled(false);
- }
- }
- }
- }
- void SystemComponent::ApplyMotionExtraction(const ActorInstance* actorInstance, float timeDelta)
- {
- AZ_Assert(actorInstance, "Cannot apply motion extraction. Actor instance is not valid.");
- AZ_Assert(actorInstance->GetActor(), "Cannot apply motion extraction. Actor instance is not linked to a valid actor.");
- AZ::Entity* entity = actorInstance->GetEntity();
- const Actor* actor = actorInstance->GetActor();
- if (!actorInstance->GetIsEnabled() ||
- !entity ||
- !actor->GetMotionExtractionNode())
- {
- return;
- }
- const AZ::EntityId entityId = entity->GetId();
- // Check if we have any physics character controllers.
- bool hasCustomMotionExtractionController = false;
- bool hasPhysicsController = false;
- Physics::CharacterRequestBus::EventResult(hasPhysicsController, entityId, &Physics::CharacterRequests::IsPresent);
- if (!hasPhysicsController)
- {
- hasCustomMotionExtractionController = MotionExtractionRequestBus::FindFirstHandler(entityId) != nullptr;
- }
- // If we have a physics controller.
- if (hasCustomMotionExtractionController || hasPhysicsController)
- {
- const float deltaTimeInv = (timeDelta > 0.0f) ? (1.0f / timeDelta) : 0.0f;
- AZ::Transform currentTransform = AZ::Transform::CreateIdentity();
- AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM);
- const AZ::Vector3 actorInstancePosition = actorInstance->GetWorldSpaceTransform().m_position;
- const AZ::Vector3 positionDelta = actorInstancePosition - currentTransform.GetTranslation();
- if (hasPhysicsController)
- {
- Physics::CharacterRequestBus::Event(
- entityId, &Physics::CharacterRequests::AddVelocityForTick, positionDelta * deltaTimeInv);
- }
- else if (hasCustomMotionExtractionController)
- {
- MotionExtractionRequestBus::Event(entityId, &MotionExtractionRequestBus::Events::ExtractMotion, positionDelta, timeDelta);
- AZ::TransformBus::EventResult(currentTransform, entityId, &AZ::TransformBus::Events::GetWorldTM);
- }
- // Update the entity rotation.
- const AZ::Quaternion actorInstanceRotation = actorInstance->GetWorldSpaceTransform().m_rotation;
- const AZ::Quaternion currentRotation = currentTransform.GetRotation();
- if (!currentRotation.IsClose(actorInstanceRotation, AZ::Constants::FloatEpsilon))
- {
- AZ::Transform newTransform = currentTransform;
- newTransform.SetRotation(actorInstanceRotation);
- AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform);
- }
- }
- else // There is no physics controller, just use EMotion FX's actor instance transform directly.
- {
- const AZ::Transform newTransform = actorInstance->GetWorldSpaceTransform().ToAZTransform();
- AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetWorldTM, newTransform);
- }
- }
- int SystemComponent::GetTickOrder()
- {
- return AZ::TICK_ANIMATION;
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::RegisterAnimGraphObjectType(EMotionFX::AnimGraphObject* objectTemplate)
- {
- EMotionFX::AnimGraphObjectFactory::GetUITypes().emplace(azrtti_typeid(objectTemplate));
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::RegisterAssetTypesAndHandlers()
- {
- // Initialize asset handlers.
- m_assetHandlers.emplace_back(aznew ActorAssetHandler);
- m_assetHandlers.emplace_back(aznew MotionAssetHandler);
- m_assetHandlers.emplace_back(aznew MotionSetAssetHandler);
- m_assetHandlers.emplace_back(aznew AnimGraphAssetHandler);
- // Add asset types and extensions to AssetCatalog.
- auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler();
- if (assetCatalog)
- {
- assetCatalog->EnableCatalogForAsset(azrtti_typeid<ActorAsset>());
- assetCatalog->EnableCatalogForAsset(azrtti_typeid<MotionAsset>());
- assetCatalog->EnableCatalogForAsset(azrtti_typeid<MotionSetAsset>());
- assetCatalog->EnableCatalogForAsset(azrtti_typeid<AnimGraphAsset>());
- assetCatalog->AddExtension("actor"); // Actor
- assetCatalog->AddExtension("motion"); // Motion
- assetCatalog->AddExtension("motionset"); // Motion set
- assetCatalog->AddExtension("animgraph"); // Anim graph
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::SetMediaRoot(const char* alias)
- {
- const char* rootPath = AZ::IO::FileIOBase::GetInstance()->GetAlias(alias);
- if (rootPath)
- {
- AZStd::string mediaRootPath = rootPath;
- AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::Bus::Events::NormalizePathKeepCase, mediaRootPath);
- EMotionFX::GetEMotionFX().SetMediaRootFolder(mediaRootPath.c_str());
- }
- else
- {
- AZ_Warning("EMotionFX", false, "Failed to set media root because alias \"%s\" could not be resolved.", alias);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- IRaycastRequests::RaycastResult SystemComponent::Raycast(
- [[maybe_unused]] AZ::EntityId entityId, const IRaycastRequests::RaycastRequest& rayRequest)
- {
- IRaycastRequests::RaycastResult rayResult;
- // Build the ray request in the physics system.
- AzPhysics::RayCastRequest physicsRayRequest;
- physicsRayRequest.m_start = rayRequest.m_start;
- physicsRayRequest.m_direction = rayRequest.m_direction;
- physicsRayRequest.m_distance = rayRequest.m_distance;
- physicsRayRequest.m_queryType = rayRequest.m_queryType;
- // Cast the ray in the physics system.
- if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
- {
- if (AzPhysics::SceneHandle sceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
- sceneHandle != AzPhysics::InvalidSceneHandle)
- {
- AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &physicsRayRequest);
- if (result) // We intersected.
- {
- rayResult.m_position = result.m_hits[0].m_position;
- rayResult.m_normal = result.m_hits[0].m_normal;
- rayResult.m_intersected = true;
- }
- }
- }
- return rayResult;
- }
- #if defined (EMOTIONFXANIMATION_EDITOR)
- //////////////////////////////////////////////////////////////////////////
- void SystemComponent::NotifyRegisterViews()
- {
- using namespace AzToolsFramework;
- // Construct data folder that is used by the tool for loading assets (images etc.).
- using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- auto settingsRegistry = AZ::SettingsRegistry::Get();
- AZ::IO::FixedMaxPath editorAssetsPath;
- if (settingsRegistry && settingsRegistry->Get(editorAssetsPath.Native(),
- FixedValueString::format("%s/EMotionFX/Path",AZ::SettingsRegistryMergeUtils::ManifestGemsRootKey)))
- {
- editorAssetsPath /= "Assets/Editor";
- editorAssetsPath = editorAssetsPath.LexicallyNormal();
- }
- // Re-initialize EMStudio.
- int argc = 0;
- char** argv = nullptr;
- MysticQt::Initializer::Init("", editorAssetsPath.c_str());
- m_emstudioManager = AZStd::make_unique<EMStudio::EMStudioManager>(qApp, argc, argv);
- // Register default plugins
- EMStudio::PluginManager* pluginManager = EMStudio::GetManager()->GetPluginManager();
- AZ_Assert(pluginManager, "The plugin manager should be initialized at the time the plugins get registered.");
- pluginManager->RegisterDefaultPlugins();
- // Let external gems register their plugins
- SystemNotificationBus::Broadcast(&SystemNotificationBus::Events::OnRegisterPlugin);
- // Get the MainWindow the first time so it is constructed
- EMStudio::GetManager()->GetMainWindow();
- EMStudio::GetManager()->ExecuteApp();
- AZStd::function<QWidget*(QWidget*)> windowCreationFunc = []([[maybe_unused]] QWidget* parent = nullptr)
- {
- return EMStudio::GetMainWindow();
- };
- // Register EMotionFX window with the main editor.
- AzToolsFramework::ViewPaneOptions emotionFXWindowOptions;
- emotionFXWindowOptions.isPreview = false;
- emotionFXWindowOptions.isDeletable = true;
- emotionFXWindowOptions.isDockable = false;
- #if AZ_TRAIT_EMOTIONFX_MAIN_WINDOW_DETACHED
- emotionFXWindowOptions.detachedWindow = true;
- #endif
- emotionFXWindowOptions.optionalMenuText = "Animation Editor";
- emotionFXWindowOptions.showOnToolsToolbar = true;
- emotionFXWindowOptions.toolbarIcon = ":/Menu/emfx_editor.svg";
- EditorRequests::Bus::Broadcast(&EditorRequests::RegisterViewPane, EMStudio::MainWindow::GetEMotionFXPaneName(), LyViewPane::CategoryTools, emotionFXWindowOptions, windowCreationFunc);
- }
- //////////////////////////////////////////////////////////////////////////
- bool SystemComponent::IsSystemActive(EditorAnimationSystemRequests::AnimationSystem systemType)
- {
- return (systemType == AnimationSystem::EMotionFX);
- }
- // AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
- AzToolsFramework::AssetBrowser::SourceFileDetails SystemComponent::GetSourceFileDetails(const char* fullSourceFileName)
- {
- using namespace AzToolsFramework::AssetBrowser;
- if (AZStd::wildcard_match("*.motionset", fullSourceFileName))
- {
- return SourceFileDetails("Editor/Images/AssetBrowser/MotionSet_80.svg");
- }
- else if (AZStd::wildcard_match("*.animgraph", fullSourceFileName))
- {
- return SourceFileDetails("Editor/Images/AssetBrowser/AnimGraph_80.svg");
- }
- return SourceFileDetails(); // no result
- }
- void SystemComponent::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, [[maybe_unused]] AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers)
- {
- using namespace AzToolsFramework::AssetBrowser;
- if (HandlesSource(fullSourceFileName))
- {
- auto animationEditorCallback =
- []([[maybe_unused]] const char* fullSourceFileNameInCall, const AZ::Uuid& sourceUUIDInCall)
- {
- AZ::Outcome<int, AZStd::string> openOutcome = AZ::Failure(AZStd::string());
- const SourceAssetBrowserEntry* fullDetails = SourceAssetBrowserEntry::GetSourceByUuid(sourceUUIDInCall);
- if (fullDetails)
- {
- AzToolsFramework::OpenViewPane(LyViewPane::AnimationEditor);
- EMStudio::GetMainWindow()->ApplicationModeChanged("AnimGraph");
- if (AZStd::wildcard_match("*.motionset", fullSourceFileNameInCall))
- {
- EMStudio::EMStudioPlugin* plugin =
- EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionSetsWindowPlugin::CLASS_ID);
- EMStudio::MotionSetsWindowPlugin* motionSetPlugin = (EMStudio::MotionSetsWindowPlugin*)plugin;
- if (plugin)
- {
- // We need to wait for the end of frame otherwise setting the current widget fails
- QTimer::singleShot(
- 0,
- [motionSetPlugin, fullSourceFileNameInCall]()
- {
- motionSetPlugin->LoadMotionSet(AZStd::string(fullSourceFileNameInCall));
- QDockWidget* dockWidget = motionSetPlugin->GetDockWidget();
- AzQtComponents::DockTabWidget* tabWidget =
- AzQtComponents::DockTabWidget::ParentTabWidget(dockWidget);
- tabWidget->setCurrentWidget(dockWidget);
- });
- }
- }
- else
- {
- EMStudio::EMStudioPlugin* plugin =
- EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::AnimGraphPlugin::CLASS_ID);
- EMStudio::AnimGraphPlugin* animGraphPlugin = (EMStudio::AnimGraphPlugin*)plugin;
- if (plugin)
- {
- animGraphPlugin->FileOpen(AZStd::string(fullSourceFileNameInCall));
- }
- }
- }
- };
- openers.push_back({ "Animation Editor", "Open In Animation Editor...",
- QIcon(), animationEditorCallback });
- }
- }
- void SystemComponent::AddSourceFileCreators(
- [[maybe_unused]] const char* fullSourceFolderName,
- [[maybe_unused]] const AZ::Uuid& sourceUUID,
- AzToolsFramework::AssetBrowser::SourceFileCreatorList& creators)
- {
- using namespace AzToolsFramework;
- creators.push_back(
- { "AnimGraph_Creator",
- "AnimGraph",
- QIcon(),
- [&]( const AZStd::string& fullSourceFolderNameInCallback, [[maybe_unused]] const AZ::Uuid& sourceUUID)
- {
- AZ::IO::FixedMaxPath outFilePath = AzFramework::StringFunc::Path::MakeUniqueFilenameWithSuffix(
- AZ::IO::PathView(fullSourceFolderNameInCallback + "/NewAnimGraph.animgraph"));
- EMotionFX::AnimGraph* animGraph = aznew EMotionFX::AnimGraph();
- // create the root state machine object
- EMotionFX::AnimGraphObject* rootSMObject =
- EMotionFX::AnimGraphObjectFactory::Create(azrtti_typeid<EMotionFX::AnimGraphStateMachine>(), animGraph);
- if (rootSMObject)
- {
- // type-cast the object to a state machine and set it as root state machine
- EMotionFX::AnimGraphStateMachine* rootSM = reinterpret_cast<EMotionFX::AnimGraphStateMachine*>(rootSMObject);
- animGraph->SetRootStateMachine(rootSM);
- animGraph->RecursiveReinit();
- animGraph->RecursiveInvalidateUniqueDatas();
- AZ::SerializeContext* serializeContext = nullptr;
- AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
- animGraph->SaveToFile(outFilePath.Native().c_str(), serializeContext);
- delete animGraph;
- }
- AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotificationBus::Event(
- AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::FileCreationNotificationBusId,
- &AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::HandleAssetCreatedInEditor,
- outFilePath.Native().c_str(),
- AZ::Crc32(),
- true);
- } });
- creators.push_back(
- { "MotionSet_Creator",
- "MotionSet",
- QIcon(),
- [&]( const AZStd::string& fullSourceFolderNameInCallback, [[maybe_unused]] const AZ::Uuid& sourceUUID)
- {
- AZ::IO::FixedMaxPath outFilePath = AzFramework::StringFunc::Path::MakeUniqueFilenameWithSuffix(
- AZ::IO::PathView(fullSourceFolderNameInCallback + "/NewMotionSet.motionset"));
- AZ::IO::PathView filePath = outFilePath.c_str();
- AZStd::string motionSetName = filePath.Stem().Native();
- EMotionFX::MotionSet* motionSet = aznew EMotionFX::MotionSet(motionSetName.c_str(), /*parentSet=*/nullptr);
- motionSet->SetFilename(outFilePath.c_str());
- AZ::SerializeContext* serializeContext = nullptr;
- AZ::ComponentApplicationBus::BroadcastResult(
- serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
- motionSet->SaveToFile(outFilePath.Native().c_str(), serializeContext);
- delete motionSet;
- AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotificationBus::Event(
- AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::FileCreationNotificationBusId,
- &AzToolsFramework::AssetBrowser::AssetBrowserFileCreationNotifications::HandleAssetCreatedInEditor,
- outFilePath.Native().c_str(),
- AZ::Crc32(),
- true);
- } });
- }
- void SystemComponent::OnActionContextRegistrationHook()
- {
- constexpr AZStd::string_view AnimationEditorActionContextIdentifier = "o3de.context.animationEditor";
- constexpr AZStd::string_view AnimationEditorAnimGraphActionContextIdentifier = "o3de.context.animationEditor.animGraph";
- if(auto actionManagerInterface = AZ::Interface<AzToolsFramework::ActionManagerInterface>::Get())
- {
- // EMFX Main Window
- {
- AzToolsFramework::ActionContextProperties contextProperties;
- contextProperties.m_name = "O3DE Animation Editor";
- actionManagerInterface->RegisterActionContext(AnimationEditorActionContextIdentifier, contextProperties);
- }
- // AnimGraph
- {
- AzToolsFramework::ActionContextProperties contextProperties;
- contextProperties.m_name = "O3DE Animation Editor - Anim Graph";
- actionManagerInterface->RegisterActionContext(AnimationEditorAnimGraphActionContextIdentifier, contextProperties);
- }
- }
- }
- bool SystemComponent::HandlesSource(AZStd::string_view fileName) const
- {
- return AZStd::wildcard_match("*.animgraph", fileName.data()) || AZStd::wildcard_match("*.motionset", fileName.data());
- }
- #endif // EMOTIONFXANIMATION_EDITOR
- }
- } // namespace EMotionFX
|