/* * 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 * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace EMotionFX { namespace Integration { class ActorComponent : public AZ::Component , private AZ::Data::AssetBus::Handler , private AZ::TransformNotificationBus::MultiHandler , private AZ::TickBus::Handler , private ActorComponentRequestBus::Handler , private ActorComponentNotificationBus::Handler , private LmbrCentral::AttachmentComponentNotificationBus::Handler , private AzFramework::CharacterPhysicsDataRequestBus::Handler , private AzFramework::RagdollPhysicsNotificationBus::Handler { public: AZ_COMPONENT(ActorComponent, "{BDC97E7F-A054-448B-A26F-EA2B5D78E377}"); friend class EditorActorComponent; class BoundingBoxConfiguration { public: AZ_TYPE_INFO(BoundingBoxConfiguration, "{EBCFF975-00A5-4578-85C7-59909F52067C}"); BoundingBoxConfiguration() = default; EMotionFX::ActorInstance::EBoundsType m_boundsType = EMotionFX::ActorInstance::BOUNDS_STATIC_BASED; float m_expandBy = 25.0f; ///< Expand the bounding volume by the given percentage. bool m_autoUpdateBounds = true; float m_updateTimeFrequency = 0.0f; AZ::u32 m_updateItemFrequency = 1; // Set the bounding box configuration of the given actor instance to the parameters given by 'this'. The actor instance must not be null (this is not checked). void Set(ActorInstance* actorInstance) const; // Set the bounding box configuration, then update the bounds of the actor instance void SetAndUpdate(ActorInstance* actorInstance) const; static void Reflect(AZ::ReflectContext* context); AZ::Crc32 GetVisibilityAutoUpdate() const; AZ::Crc32 GetVisibilityAutoUpdateSettings() const; }; /** * Configuration struct for procedural configuration of Actor Components. */ struct Configuration { AZ_TYPE_INFO(Configuration, "{053BFBC0-ABAA-4F4E-911F-5320F941E1A8}") AZ::Data::Asset m_actorAsset{AZ::Data::AssetLoadBehavior::NoLoad}; ///< Selected actor asset. ActorAsset::MaterialList m_materialPerLOD{}; ///< Material assignment per LOD. AZ::EntityId m_attachmentTarget{}; ///< Target entity this actor should attach to. size_t m_attachmentJointIndex = InvalidIndex; ///< Index of joint on target skeleton for actor attachments. AttachmentType m_attachmentType = AttachmentType::None; ///< Type of attachment. SkinningMethod m_skinningMethod = SkinningMethod::DualQuat; ///< The skinning method for this actor size_t m_lodLevel = 0; ActorRenderFlags m_renderFlags = ActorRenderFlags::Default; ///< Actor render flag // Force updating the joints when it is out of camera view. By // default, joints level update (beside the root joint) on // actor are disabled when the actor is out of view. bool m_forceUpdateJointsOOV = false; BoundingBoxConfiguration m_bboxConfig; ///< Configuration for bounding box type and updates static void Reflect(AZ::ReflectContext* context); }; ActorComponent(const Configuration* configuration = nullptr); ~ActorComponent() override; ////////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation void Activate() override; void Deactivate() override; ////////////////////////////////////////////////////////////////////////// // ActorComponentRequestBus::Handler size_t GetNumJoints() const override; size_t GetJointIndexByName(const char* name) const override; AZ::Transform GetJointTransform(size_t jointIndex, Space space) const override; void GetJointTransformComponents(size_t jointIndex, Space space, AZ::Vector3& outPosition, AZ::Quaternion& outRotation, AZ::Vector3& outScale) const override; Physics::AnimationConfiguration* GetPhysicsConfig() const override; ActorInstance* GetActorInstance() override { return m_actorInstance.get(); } void AttachToEntity(AZ::EntityId targetEntityId, AttachmentType attachmentType) override; void DetachFromEntity() override; bool GetRenderCharacter() const override; void SetRenderCharacter(bool enable) override; bool GetRenderActorVisible() const override; SkinningMethod GetSkinningMethod() const override; void SetActorAsset(AZ::Data::Asset actorAsset) override; ////////////////////////////////////////////////////////////////////////// // ActorComponentNotificationBus::Handler void OnActorInstanceCreated(ActorInstance* actorInstance) override; void OnActorInstanceDestroyed(ActorInstance* actorInstance) override; ////////////////////////////////////////////////////////////////////////// // The entity has attached to the target. void OnAttached(AZ::EntityId targetId) override; // The entity is detaching from the target. void OnDetached(AZ::EntityId targetId) override; ////////////////////////////////////////////////////////////////////////// // AzFramework::CharacterPhysicsDataBus::Handler bool GetRagdollConfiguration(Physics::RagdollConfiguration& config) const override; Physics::RagdollState GetBindPose(const Physics::RagdollConfiguration& config) const override; AZStd::string GetParentNodeName(const AZStd::string& childName) const override; ////////////////////////////////////////////////////////////////////////// // AzFramework::RagdollPhysicsNotificationBus::Handler void OnRagdollActivated() override; void OnRagdollDeactivated() override; ////////////////////////////////////////////////////////////////////////// static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC("EMotionFXActorService", 0xd6e8f48d)); provided.push_back(AZ_CRC("MeshService", 0x71d8a455)); provided.push_back(AZ_CRC("CharacterPhysicsDataService", 0x34757927)); provided.push_back(AZ_CRC("MaterialReceiverService", 0x0d1a6a74)); } static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) { incompatible.push_back(AZ_CRC("EMotionFXActorService", 0xd6e8f48d)); incompatible.push_back(AZ_CRC("MeshService", 0x71d8a455)); incompatible.push_back(AZ_CRC_CE("NonUniformScaleService")); } static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) { dependent.push_back(AZ_CRC("PhysicsService", 0xa7350d22)); } static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { required.push_back(AZ_CRC("TransformService", 0x8ee22c50)); } static void Reflect(AZ::ReflectContext* context); // AZ::Data::AssetBus::Handler void OnAssetReady(AZ::Data::Asset asset) override; void OnAssetReloaded(AZ::Data::Asset asset) override; bool IsPhysicsSceneSimulationFinishEventConnected() const; AZ::Data::Asset GetActorAsset() const { return m_configuration.m_actorAsset; } void SetRenderFlag(ActorRenderFlags renderFlags); private: // AZ::TransformNotificationBus::MultiHandler void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; // AZ::TickBus::Handler void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; int GetTickOrder() override; void CheckActorCreation(); void DestroyActor(); void CheckAttachToEntity(); Configuration m_configuration; ///< Component configuration. /// Live state ActorAsset::ActorInstancePtr m_attachmentTargetActor; ///< Target actor instance to attach to. AZ::EntityId m_attachmentTargetEntityId; ///< Target actor entity ID ActorAsset::ActorInstancePtr m_actorInstance; ///< Live actor instance. AZStd::vector m_attachments; AZStd::unique_ptr m_renderActorInstance; AzPhysics::SceneEvents::OnSceneSimulationFinishHandler m_sceneFinishSimHandler; }; } //namespace Integration } // namespace EMotionFX