/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #ifndef CRYINCLUDE_CRYANIMATION_SKELETONPHYSICS_H #define CRYINCLUDE_CRYANIMATION_SKELETONPHYSICS_H #pragma once #if ENABLE_CRY_PHYSICS #include "Memory/Memory.h" #include "Memory/Pool.h" #include "Model.h" #include "Skeleton.h" struct CCGAJoint; class CSkeletonPose; class CSkeletonAnim; class CCharInstance; class CSkeletonPhysicsNull { public: CSkeletonPhysicsNull() { m_pCharPhysics = NULL; m_ppBonePhysics = NULL; m_timeStandingUp = 0.0f; ; m_bHasPhysics = false; m_bHasPhysicsProxies = false; m_bPhysicsAwake = false; m_bPhysicsWasAwake = false; ; m_bPhysicsRelinquished = false; } public: IPhysicalEntity* GetPhysEntOnJoint(int32) { return NULL; } const IPhysicalEntity* GetPhysEntOnJoint(int32) const { return NULL; } void SetPhysEntOnJoint(int32, IPhysicalEntity*) { } int GetPhysIdOnJoint(int32) const { return 0; } void BuildPhysicalEntity(IPhysicalEntity*, f32, int, f32, int, int, const Matrix34&) { } IPhysicalEntity* CreateCharacterPhysics(IPhysicalEntity*, f32, int, f32, int, const Matrix34&) { return NULL; } int CreateAuxilaryPhysics(IPhysicalEntity*, const Matrix34&, int lod = 0) { return 0; } IPhysicalEntity* GetCharacterPhysics(int) const { return NULL; } IPhysicalEntity* GetCharacterPhysics(const char*) const { return NULL; } IPhysicalEntity* GetCharacterPhysics(void) const { return NULL; } void SetCharacterPhysics(IPhysicalEntity*) { } void SynchronizeWithPhysicalEntity(IPhysicalEntity*, const Vec3&, const Quat&) { } IPhysicalEntity* RelinquishCharacterPhysics(const Matrix34&, f32, bool, const Vec3&) { return NULL; } void DestroyCharacterPhysics(int) { } bool AddImpact(int, Vec3, Vec3) { return false; } int TranslatePartIdToDeadBody(int) { return 0; } int GetAuxPhysicsBoneId(int, int) const { return 0; } bool BlendFromRagdoll(QuatTS& location, IPhysicalEntity*& pPhysicalEntity) { return false; } int GetFallingDir(void) const { return 0; } int getBonePhysParentOrSelfIndex(int, int) const { return 0; } int GetBoneSurfaceTypeId(int, int) const { return 0; } bool Initialize(CSkeletonPose& skeletonPose) { return true; } int getBonePhysParentIndex(int nBoneIndex, int nLod = 0) { return 0; } CDefaultSkeleton::SJoint* GetModelJointPointer(int nBone) { return NULL; } Vec3 GetOffset() { return Vec3(0.0f, 0.0f, 0.0f); } void InitPhysicsSkeleton() { } void InitializeAnimToPhysIndexArray() { } int CreateAuxilaryPhysics(IPhysicalEntity* pHost, const Matrix34& mtx, f32 scale, Vec3 offset, int nLod) { return 0; } void DestroyPhysics() { } void SetAuxParams(pe_params* pf) { } void SynchronizeWithPhysics(Skeleton::CPoseData& poseData) { } void SynchronizeWithPhysicalEntity(Skeleton::CPoseData& poseData, IPhysicalEntity* pent, const Vec3& posMaster, const Quat& qMaster, QuatT offset, int iDir = -1) { } void SynchronizeWithPhysicsPost() { } public: IPhysicalEntity* m_pCharPhysics; IPhysicalEntity** m_ppBonePhysics; float m_timeStandingUp; bool m_bHasPhysics : 1; bool m_bHasPhysicsProxies : 1; bool m_bPhysicsAwake : 1; bool m_bPhysicsWasAwake : 1; bool m_bPhysicsRelinquished : 1; }; struct CPhysicsJoint { CPhysicsJoint() : m_DefaultRelativeQuat(IDENTITY) , m_qRelPhysParent(IDENTITY) , m_qRelFallPlay(IDENTITY) { } void GetMemoryUsage(ICrySizer* pSizer) const{} QuatT m_DefaultRelativeQuat; //default relative joint (can be different for every instance) Quat m_qRelPhysParent; // default orientation relative to the physicalized parent Quat m_qRelFallPlay; }; struct aux_bone_info { quaternionf quat0; Vec3 dir0; int iBone; f32 rlen0; }; struct aux_phys_data { IPhysicalEntity* pPhysEnt; Vec3* pVtx; Vec3* pSubVtx; const char* strName; aux_bone_info* pauxBoneInfo; int nChars; int nBones; int iBoneTiedTo[2]; int nSubVtxAlloc; bool bPhysical; bool bTied0, bTied1; int iBoneStiffnessController; void GetMemoryUsage(ICrySizer* pSizer) const {} }; struct SBatchUpdateValidator : pe_action_batch_parts_update::Validator { SBatchUpdateValidator() { bValid = 1; nRefCount = 1; lock = 0; WriteLock glock(g_lockList); next = prev = &g_firstValidator; next = g_firstValidator.next; g_firstValidator.next->prev = this; g_firstValidator.next = this; } ~SBatchUpdateValidator() { WriteLock glock(g_lockList); prev->next = next; next->prev = prev; } int bValid; int nRefCount; volatile int lock; volatile SBatchUpdateValidator* next, * prev; static SBatchUpdateValidator g_firstValidator; static volatile int g_lockList; virtual bool Lock() { if (!bValid) { Release(); return false; } CryReadLock(&lock, false); return true; } virtual void Unlock() { CryReleaseReadLock(&lock); Release(); } int AddRef() { return CryInterlockedIncrement(&nRefCount); } void Release() { if (CryInterlockedDecrement(&nRefCount) <= 0) { delete this; } } }; class CSkeletonPhysics { public: CSkeletonPhysics(); ~CSkeletonPhysics(); public: bool Initialize(CSkeletonPose& skeletonPose); // Helper public: IPhysicalEntity* GetCharacterPhysics() const { return m_pCharPhysics; } IPhysicalEntity* GetCharacterPhysics(const char* pRootBoneName) const; IPhysicalEntity* GetCharacterPhysics(int iAuxPhys) const; void SetCharacterPhysics(IPhysicalEntity* pent) { m_pCharPhysics = pent; m_timeStandingUp = -1.0f; } int getBonePhysParentIndex(int nBoneIndex, int nLod = 0); CDefaultSkeleton::SJoint* GetModelJointPointer(int nBone); const CDefaultSkeleton::SJoint* GetModelJointPointer(int nBone) const; Vec3 GetOffset() { return m_vOffset; } IPhysicalEntity* GetPhysEntOnJoint(int32 nId) { return m_ppBonePhysics ? m_ppBonePhysics[nId] : 0; } const IPhysicalEntity* GetPhysEntOnJoint(int32 nId) const { return const_cast<CSkeletonPhysics*>(this)->GetPhysEntOnJoint(nId); } void SetPhysEntOnJoint(int32 nId, IPhysicalEntity* pPhysEnt); int GetPhysIdOnJoint(int32 nId) const; int GetAuxPhysicsBoneId(int iAuxPhys, int iBone = 0) const { PREFAST_SUPPRESS_WARNING(6385) return (iAuxPhys < m_nAuxPhys && iBone < m_auxPhys[iAuxPhys].nBones) ? m_auxPhys[iAuxPhys].pauxBoneInfo[iBone].iBone : -1; } int TranslatePartIdToDeadBody(int partid); int getBonePhysParentOrSelfIndex (int nBoneIndex, int nLod = 0) const; int GetBoneSurfaceTypeId(int nBoneIndex, int nLod) const; private: int getBonePhysChildIndex (int nBoneIndex, int nLod = 0) const; uint32 getBoneParentIndex(uint32 nBoneIndex) const; int GetModelJointChildIndex (int nBone, int i = 0) const { return nBone + GetModelJointPointer(nBone)->m_nOffsetChildren; } int GetPhysicsLod() const { return m_bHasPhysicsProxies ? 1 : 0; } void ResetNonphysicalBoneRotations(Skeleton::CPoseData& poseData, int nLod, float fBlend); void UnconvertBoneGlobalFromRelativeForm(Skeleton::CPoseData& poseData, bool bNonphysicalOnly, int nLod = 0, bool bRopeTipsOnly = false); void FindSpineBones() const; void ForceReskin(); void SetOffset(Vec3 offset) { m_vOffset = offset; } // Initialization/creation public: void InitPhysicsSkeleton(); void InitializeAnimToPhysIndexArray(); int CreateAuxilaryPhysics(IPhysicalEntity* pHost, const Matrix34& mtx, int nLod = 0); int CreateAuxilaryPhysics(IPhysicalEntity* pHost, const Matrix34& mtx, f32 scale, Vec3 offset, int nLod); void DestroyPhysics(); void SetAuxParams(pe_params* pf); void BuildPhysicalEntity(IPhysicalEntity* pent, f32 mass, int surface_idx, f32 stiffness_scale, int nLod = 0, int partid0 = 0, const Matrix34& mtxloc = Matrix34(QuatT(IDENTITY))); IPhysicalEntity* CreateCharacterPhysics(IPhysicalEntity* pHost, f32 mass, int surface_idx, f32 stiffness_scale, int nLod = 0, const Matrix34& mtxloc = Matrix34(QuatT(IDENTITY))); IPhysicalEntity* RelinquishCharacterPhysics(const Matrix34& mtx, float stiffness, bool bCopyJointVelocities, const Vec3& velHost); void DestroyCharacterPhysics(int iMode = 0); bool AddImpact(int partid, Vec3 point, Vec3 impact); void SetJointPhysInfo(uint32 iJoint, const CryBonePhysics& pi, int nLod); const CryBonePhysics& GetJointPhysInfo(uint32 iJoint, int nLod) const; DynArray<SJointProperty> GetJointPhysProperties_ROPE(uint32 jointIndex, int nLod) const; bool SetJointPhysProperties_ROPE(uint32 jointIndex, int nLod, const DynArray<SJointProperty>& props); void SetLocation(const QuatTS& location) { m_location = location; } private: void CreateRagdollDefaultPose(Skeleton::CPoseData& poseData); public: bool BlendFromRagdoll(QuatTS& location, IPhysicalEntity*& pPhysicalEntity); int GetFallingDir() const; // Execution public: void Job_SynchronizeWithPhysicsPrepare(Memory::CPool& memoryPool); void Job_Physics_SynchronizeFrom(Skeleton::CPoseData& poseData, float timeDelta); void SynchronizeWithPhysics(Skeleton::CPoseData& poseData); void SynchronizeWithPhysicalEntity(IPhysicalEntity* pent, const Vec3& posMaster, const Quat& qMaster); void SynchronizeWithPhysicalEntity(Skeleton::CPoseData& poseData, IPhysicalEntity* pPhysicalEntity, const Vec3& posMaster, const Quat& qMaster, QuatT offset, int iDir = -1); void SynchronizeWithPhysicsPost(); private: void ProcessPhysics(Skeleton::CPoseData& poseData, float timeDelta); void Physics_SynchronizeToAux(const Skeleton::CPoseData& poseData); void Physics_SynchronizeToEntity(IPhysicalEntity& physicalEntity, QuatT offset); void Physics_SynchronizeToEntityArticulated(float fDeltaTimePhys); void Physics_SynchronizeToImpact(float timeDelta); void Job_Physics_SynchronizeFromEntityPrepare(Memory::CPool& memoryPool, IPhysicalEntity* pPhysicalEntity); void Job_Physics_SynchronizeFromEntity(Skeleton::CPoseData& poseData, IPhysicalEntity* pPhysicalEntity, QuatT offset); void Job_Physics_SynchronizeFromEntityArticulated(Skeleton::CPoseData& poseData, float timeDelta); void Job_Physics_SynchronizeFromAuxPrepare(Memory::CPool& memoryPool); void Job_Physics_SynchronizeFromAux(Skeleton::CPoseData& poseData); void Job_Physics_SynchronizeFromImpactPrepare(Memory::CPool& memoryPool); void Job_Physics_SynchronizeFromImpact(Skeleton::CPoseData& poseData, float timeDelta); void Job_Physics_BlendFromRagdoll(Skeleton::CPoseData& poseData, float timeDelta); void SetPrevHost(IPhysicalEntity* pNewHost = 0) { if (m_pPrevCharHost == pNewHost) { return; } if (m_pPrevCharHost) { m_pPrevCharHost->Release(); if (m_pPrevCharHost->GetForeignData(PHYS_FOREIGN_ID_RAGDOLL) == (void*)(ICharacterInstance*)m_pInstance) { gEnv->pPhysicalWorld->DestroyPhysicalEntity(m_pPrevCharHost); } } if (m_pPrevCharHost = pNewHost) { pNewHost->AddRef(); } } public: IPhysicalEntity* m_pCharPhysics; IPhysicalEntity** m_ppBonePhysics; float m_timeStandingUp; bool m_bBlendFromRagdollFlip : 1; bool m_bHasPhysics : 1; bool m_bHasPhysicsProxies : 1; bool m_bPhysicsAwake : 1; bool m_bPhysicsWasAwake : 1; bool m_bPhysicsRelinquished : 1; private: QuatTS m_location; IPhysicalEntity* m_pPrevCharHost; DynArray<CPhysicsJoint> m_arrPhysicsJoints; Vec3 m_physicsJointRootPosition; struct PhysData { QuatT location; Quat rotation; Ang3 angles; bool bSet : 1; bool bSet2 : 1; }* m_pPhysBuffer; bool m_bPhysicsSynchronize; bool m_bPhysicsSynchronizeFromEntity; bool m_bPhysBufferFilled; struct PhysAuxData { QuatT matrix; Vec3* pPoints; bool bSet : 1; }* m_pPhysAuxBuffer; bool m_bPhysicsSynchronizeAux; struct PhysImpactData { Ang3 angles; // in-out Vec3 pivot; // out Quat q0; // out bool bSet : 1; }* m_pPhysImpactBuffer; Vec3 m_vOffset; mutable int m_iSpineBone[3]; mutable uint32 m_nSpineBones; int m_nAuxPhys; int m_iSurfaceIdx; DynArray<aux_phys_data> m_auxPhys; f32 m_fPhysBlendTime; f32 m_fPhysBlendMaxTime; f32 m_frPhysBlendMaxTime; float m_stiffnessScale; f32 m_fScale; f32 m_fMass; Vec3 m_prevPosPivot; Vec3 m_velPivot; DynArray<QuatT> m_physJoints; DynArray<int> m_physJointsIdx; int m_nPhysJoints; SBatchUpdateValidator* m_pPhysUpdateValidator; struct SExtraPhysInfo { uint32 iJoint; int nLod; CryBonePhysics info; }; DynArray<SExtraPhysInfo> m_extraPhysInfo; // From SkeletonPose private: CCharInstance* m_pInstance; CSkeletonPose* m_pSkeletonPose; CSkeletonAnim* m_pSkeletonAnim; bool m_bLimpRagdoll : 1; bool m_bSetDefaultPoseExecute : 1; bool m_bFullSkeletonUpdate : 1; DynArray<CCGAJoint>* m_arrCGAJoints; const Skeleton::CPoseData& GetPoseData() const; Skeleton::CPoseData& GetPoseDataExplicitWriteable(); Skeleton::CPoseData& GetPoseDataForceWriteable(); Skeleton::CPoseData* GetPoseDataWriteable(); const Skeleton::CPoseData& GetPoseDataDefault() const; int16 GetJointIDByName (const char* szJointName) const; public: size_t SizeOfThis() { size_t TotalSize = 0; TotalSize += m_arrPhysicsJoints.get_alloc_size(); if (m_ppBonePhysics) { TotalSize += GetPoseData().GetJointCount() * sizeof(IPhysicalEntity*); } return TotalSize; } void GetMemoryUsage(ICrySizer* pSizer) const { pSizer->AddContainer(m_arrPhysicsJoints); pSizer->AddContainer(m_auxPhys); } }; #endif // ENABLE_CRY_PHYSICS #endif // CRYINCLUDE_CRYANIMATION_SKELETONPHYSICS_H