|
|
//========== Copyright (c) Valve Corporation. All Rights Reserved. ============
#ifndef AUTHPHYSMODEL_HDR
#define AUTHPHYSMODEL_HDR
#ifdef COMPILER_MSVC
#pragma once
#endif
#include "tier1/utlincrementalvector.h"
#include "tier1/utlstringtoken.h"
#include "resourcefile/resourcestream.h"
#include "mathlib/aabb.h"
#include "mathlib/vertexcolor.h"
#include "rubikon/param_types.h"
#include "mathlib/femodeldesc.h"
#include "mathlib/femodelbuilder.h"
#include "tier1/utlhashtable.h"
#include "bitvec.h"
#include "tier1/utlstringmap.h"
#include "tier1/utlsortvector.h"
#include "mdlobjects/vpropbreakabledata.h"
struct VPhysXBodyPart_t; struct RnSphereDesc_t; struct RnCapsuleDesc_t; struct RnHullDesc_t; struct RnMeshDesc_t; struct RnShapeDesc_t; struct AABB_t; struct RnHull_t; class CToolSceneTraceEnvironment; class CMesh; struct GizmoTransform_t; struct RnHullSimplificationParams_t; struct PhysSoftbodyDesc_t; class CUtlSymbolTable; template <class T >class CUtlStringMap; class CPhysModelSource; /*schema*/ class CAuthPhysBody; class KeyValues; struct VPhysXAggregateData_t; struct VPhysXJoint_t; class CResourceStream; struct VertexPositionNormal_t; struct VertexPositionColor_t; struct AuthHullSimplificationParams_t; class CVClothProxyMeshOptions;
/*schema*/ enum AuthPhysCollisionAttributesModeEnum_t { AUTH_PHYS_COLL_ATTR_IGNORE, META( MPropertyFriendlyName = "Default/Derived" ) AUTH_PHYS_COLL_ATTR_OVERRIDE, META( MPropertyFriendlyName = "Override" ) AUTH_PHYS_COLL_ATTR_APPEND META( MPropertyFriendlyName = "Append" ) }; DECLARE_SCHEMA_ENUM( AuthPhysCollisionAttributesModeEnum_t );
enum AuthPhysFxCollisionTypeEnum_t { AUTH_PHYS_FX_SPHERE, AUTH_PHYS_FX_PLANE };
/*schema*/ class CAuthPhysCollisionAttributesOverride; /*schema*/ struct VPhysXCollisionAttributes_t; class CAuthPhysCompileContext;
/*schema*/ class CAuthPhysCollisionAttributes { public: CAuthPhysCollisionAttributes() { m_CollisionGroup = "default"; } //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysCollisionAttributes )
void ApplyOverride( const CAuthPhysCollisionAttributesOverride &collOverride ); void Compile( CAuthPhysCompileContext &context, VPhysXCollisionAttributes_t &entry )const; CUtlString m_CollisionGroup; META( MPropertyFriendlyName = "Collision Group"; MPropertyChoiceProviderFn = GetCollisionGroupList ); CUtlVector< CUtlString > m_InteractAs; META( MPropertyFriendlyName = "Interact As"; MPropertyChoiceProviderFn = GetInteractionLayerList ); CUtlVector< CUtlString > m_InteractWith; META( MPropertyFriendlyName = "Interact With"; MPropertyChoiceProviderFn = GetInteractionLayerList );
bool operator == ( const CAuthPhysCollisionAttributes & other )const; };
/*schema*/ class CAuthPhysCollisionAttributesOverride: public CAuthPhysCollisionAttributes { public: CAuthPhysCollisionAttributesOverride() { m_nMode = AUTH_PHYS_COLL_ATTR_IGNORE; // ignore by default
} //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysCollisionAttributesOverride )
AuthPhysCollisionAttributesModeEnum_t m_nMode; META( MPropertyFriendlyName = "Mode" ); };
class CLockecResourceHashFunctor { public: uint operator() ( const CLockedResource<char> &res )const { CRC32_t nCrc; CRC32_Init( &nCrc ); CRC32_ProcessBuffer( &nCrc, res, res.Count( ) ); CRC32_Final( &nCrc ); return nCrc; } };
class CLockedResourceEqualFunctor { public: bool operator() ( const CLockedResource<char> &a, const CLockedResource<char> & b )const { return a.Count( ) == b.Count( ) && !V_memcmp( a, b, a.Count( ) ); } };
typedef CUtlHashtable< CLockedResource< char >, empty_t, CLockecResourceHashFunctor, CLockedResourceEqualFunctor > CLockedResourceHashtable;
class CAuthPhysCompileContext { public: CAuthPhysCompileContext( CResourceStream *pStream ) : m_pStream( pStream ), m_DefaultSurfaceProperty( "default" ) {}
int ResolveCollisionAttributesIndex();
const CAuthPhysCollisionAttributes &GetDefaultCollisionAttributes() { return m_DefaultCollisionAttributes; } void ApplyOverrideToDefault( const CAuthPhysCollisionAttributesOverride &collAttr ) { m_DefaultCollisionAttributes.ApplyOverride( collAttr ); } void SetDefaultCollisionAttributes( const CAuthPhysCollisionAttributes &attr ) { m_DefaultCollisionAttributes = attr; }
int GetCollAttrPaletteSize( )const { return m_CollAttrPalette.Count();} const CAuthPhysCollisionAttributes &GetCollAttrPaletteEntry( int i ) { return m_CollAttrPalette[i]; } CResourceStream *GetStream() { return m_pStream; }
CLockedResource<char> WriteString( const char *pString, uint32 *pHashOut = NULL ); // writes a non-unique string (saving space) , returns its hash
template <typename T> CLockedResource< T > FindOrWrite( const T *pData, uint nElements ) { CLockedResource< char > res( ( char* ) pData, nElements * sizeof( T ) ); UtlHashHandle_t hFind = m_WrittenResources.Find( res ); if ( hFind == m_WrittenResources.InvalidHandle( ) ) { CLockedResource<T> written = m_pStream->Allocate< T>( nElements ); V_memcpy( written, pData, sizeof ( T ) *nElements );
m_WrittenResources.Insert( CLockedResource<char>( ( char* ) ( T* ) written, nElements * sizeof( T ) )); return written; } else { CLockedResource<char> found = m_WrittenResources[ hFind ]; return CLockedResource< T >( ( T* ) ( char* ) found, nElements ); // found a copy, no need to write it out again
} }
const CUtlString &GetDefaultSurfaceProperty()const { return m_DefaultSurfaceProperty; } void SetDefaultSurfaceProperty( const char *pSurfacePropertyOverride ){ m_DefaultSurfaceProperty = pSurfacePropertyOverride ; } int ResolveSurfacePropertyIndex();
int GetSurfacePropertyPaletteSize() { return m_SurfacePropPalette.Count(); } const CUtlString &GetSurfacePropertyPaletteEntry( int i ) { return m_SurfacePropPalette[i]; } protected: CAuthPhysCollisionAttributes m_DefaultCollisionAttributes; CResourceStream *m_pStream; CUtlVector< CAuthPhysCollisionAttributes > m_CollAttrPalette;
CLockedResourceHashtable m_WrittenResources; CUtlVector< CUtlString > m_SurfacePropPalette; CUtlString m_DefaultSurfaceProperty; };
class CAuthPhysCollisionAttributeScope { public: CAuthPhysCollisionAttributeScope( CAuthPhysCompileContext* pContext, CAuthPhysCollisionAttributesOverride &collOverride ) { m_pContext = pContext; m_SavedDefaults = pContext->GetDefaultCollisionAttributes(); pContext->ApplyOverrideToDefault( collOverride ); } ~CAuthPhysCollisionAttributeScope() { m_pContext->SetDefaultCollisionAttributes( m_SavedDefaults ); } protected: CAuthPhysCompileContext* m_pContext; CAuthPhysCollisionAttributes m_SavedDefaults; };
class CAuthPhysSurfacePropertyScope { public: CAuthPhysSurfacePropertyScope( CAuthPhysCompileContext* pContext, const CUtlString &surfacePropOverride ) { m_pContext = pContext; m_SavedDefault = pContext->GetDefaultSurfaceProperty(); if( !surfacePropOverride.IsEmpty() ) { pContext->SetDefaultSurfaceProperty( surfacePropOverride ); } } ~CAuthPhysSurfacePropertyScope() { m_pContext->SetDefaultSurfaceProperty( m_SavedDefault ); } protected: CAuthPhysCompileContext* m_pContext; CUtlString m_SavedDefault; };
enum PhysicsShapeType_t;
/*schema*/ enum AuthPhysShapeTypeEnum_t { AUTH_PHYS_SHAPE_SPHERE = SHAPE_SPHERE, META( MPropertyFriendlyName = "Sphere" ) AUTH_PHYS_SHAPE_CAPSULE = SHAPE_CAPSULE, META( MPropertyFriendlyName = "Capsule" ) AUTH_PHYS_SHAPE_HULL = SHAPE_HULL, META( MPropertyFriendlyName = "Convex Hull" ) AUTH_PHYS_SHAPE_MESH = SHAPE_MESH, META( MPropertyFriendlyName = "Triangle Mesh" ) }; DECLARE_SCHEMA_ENUM( AuthPhysShapeTypeEnum_t );
/*schema*/ class CPhysPartBreakableData { //DECLARE_SCHEMA_DATA_CLASS( CPhysPartBreakableData )
CPhysPartBreakableData() { m_bMotionDisabled = false; m_nHealth = 1; m_flBurstScale = 1.0; m_flBurstRandomize = 0.0f; m_nFadeTime = 20.0; m_nFadeMin = 0; m_nFadeMax = 0.0; m_bNoShadows = false; }
CUtlString m_CollisionGroup; META( MPropertyFriendlyName = "Collision Group"; MPropertyChoiceProviderFn = GetCollisionGroupList; ); bool m_bMotionDisabled; META( MPropertyFriendlyName = "Motion Disabled" ); int m_nHealth;META( MPropertyFriendlyName = "Health" ); int m_nFadeTime;META( MPropertyFriendlyName = "Fade Time" ); int m_nFadeMin;META( MPropertyFriendlyName = "Fade Min Distance" ); int m_nFadeMax;META( MPropertyFriendlyName = "Fade Max Distance" ); float m_flBurstScale; META( MPropertyFriendlyName = "Burst Scale" ); float m_flBurstRandomize; META( MPropertyFriendlyName = "Burst Randomize" ); bool m_bNoShadows; META( MPropertyFriendlyName = "Do Not Cast Shadows" ); CUtlString m_SurfaceProp; META( MPropertyFriendlyName = "Surface Prop"; MPropertyChoiceProviderFn = GetSurfacePropertyList; );
CLockedResource< VpropBreakablePartData_t > Compile( CResourceStream *pStream ) { CLockedResource< VpropBreakablePartData_t > pData = pStream->Allocate< VpropBreakablePartData_t >(); pData->m_nCollisionGroupHash = m_CollisionGroup.IsEmpty() ? 0 : MakeStringToken( m_CollisionGroup.Get() ).GetHashCode(); pData->m_bMotionDisabled = m_bMotionDisabled; pData->m_nHealth = m_nHealth; pData->m_nFadeTime = m_nFadeTime; pData->m_nFadeMin = m_nFadeMin; pData->m_nFadeMax = m_nFadeMax; pData->m_flBurstScale = m_flBurstScale; pData->m_flBurstRandomize = m_flBurstRandomize; pData->m_bNoShadows = m_bNoShadows; pData->m_nSurfaceProp = m_SurfaceProp.IsEmpty() ? 0 : MakeStringToken( m_SurfaceProp ).GetHashCode();
return pData; } };
/*schema*/ enum AuthPhysJointTypeEnum_t { AUTH_PHYS_SPHERICAL_JOINT = SPHERICAL_JOINT, META( MPropertyFriendlyName = "Spherical Joint" ) AUTH_PHYS_REVOLUTE_JOINT = REVOLUTE_JOINT, META( MPropertyFriendlyName = "Revolute Joint" ) AUTH_PHYS_PRISMATIC_JOINT = PRISMATIC_JOINT, META( MPropertyFriendlyName = "Prismatic Joint" ) AUTH_PHYS_ORTHOTWIST_JOINT = QUAT_ORTHOTWIST_JOINT, META( MPropertyFriendlyName = "Ragdoll Joint" ) AUTH_PHYS_WELD_JOINT = WELD_JOINT, META( MPropertyFriendlyName = "Weld Joint" ) AUTH_PHYS_NULL_JOINT = NULL_JOINT META( MPropertyFriendlyName = "Null Joint" ) }; DECLARE_SCHEMA_ENUM( AuthPhysJointTypeEnum_t );
struct AuthPhysRange_t { TYPEMETA( MNoScatter ) //DECLARE_SCHEMA_DATA_CLASS( AuthPhysRange_t );
float32 m_flMin; float32 m_flMax;
AuthPhysRange_t() {} AuthPhysRange_t( float flMin, float flMax ) : m_flMin( flMin ) , m_flMax( flMax ) {} };
class CBoneParseParams;
/*schema*/ struct AuthPhysSphereCollision_t { //DECLARE_SCHEMA_DATA_CLASS( AuthPhysSphereCollision_t );
public: AuthPhysSphereCollision_t() { m_bInclusive = false; m_flRadius = 16; m_vOrigin = vec3_origin; m_flStickiness = 0; }
bool m_bInclusive; float m_flRadius; Vector m_vOrigin; float m_flStickiness; };
class CAuthPhysFxRodMap : public CUtlVector < CUtlSortVector< int > * > { public: CAuthPhysFxRodMap(){ } ~CAuthPhysFxRodMap() { PurgeAndDeleteElements(); }
void Init( int nNodes ) { PurgeAndDeleteElements(); SetCount( nNodes ); FillWithValue( NULL ); }
void Append( int nNodeA, int nNodeB ) { CUtlSortVector< int > * &list = ( *this )[ nNodeA ]; if ( !list ) { list = new CUtlSortVector < int > ; list->Insert( nNodeB ); } else { list->InsertIfNotFound( nNodeB ); } } };
/*schema*/ class CAuthPhysFx { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx );
public: CAuthPhysFx( ) { InitDefaults( ); } ~CAuthPhysFx(){}
int Cleanup(); template <typename TBitVec> void AlignNodes( const TBitVec &nodes ); void AlignNodes() { struct IdentityMap_t { bool operator[]( int i ) const { return true; } } identityMap; AlignNodes( identityMap ); } public:
/*schema*/ class CDagEdge {
//DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CDagEdge );
public: CDagEdge( ) { m_nParentBone = -1; m_nChildBone = -1; }
bool UsesNode( int nNode ) const { return m_nParentBone == nNode || m_nChildBone == nNode; }
void ChangeNode( int nOldNode, int nNewNode ) { if ( m_nParentBone == nOldNode ) m_nParentBone = nNewNode; if ( m_nChildBone == nOldNode ) m_nChildBone = nNewNode; } void RebaseNodes( int nBaseNode ) { m_nParentBone += nBaseNode; m_nChildBone += nBaseNode; }
void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nParentBone, remap ); RemapNode( m_nChildBone, remap ); }
bool IsValid( int nNodeCount )const { return m_nParentBone < nNodeCount && m_nChildBone < nNodeCount; }
bool operator == ( const CDagEdge &other ) const { return m_nParentBone == other.m_nParentBone && m_nChildBone == other.m_nChildBone; }
int m_nParentBone; int m_nChildBone; };
/*schema*/ class CCollisionSphere: public CDagEdge { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CCollisionSphere );
public: CCollisionSphere( ) { m_bInclusive = false; m_flRadius = 0; m_vOrigin = vec3_origin; m_flStickiness = 0; }
void Assign( const AuthPhysSphereCollision_t &that ) { m_bInclusive = that.m_bInclusive; m_flRadius = that.m_flRadius; m_vOrigin = that.m_vOrigin; m_flStickiness = that.m_flStickiness; } public: bool m_bInclusive; float m_flRadius; Vector m_vOrigin; float m_flStickiness; };
/*schema*/ class CCollisionPlane: public CDagEdge { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CCollisionPlane );
public: CCollisionPlane( ) { m_Plane.m_vNormal = Vector( 0, 0, 1 ); m_Plane.m_flOffset = 0; m_flStickiness = 0; }
bool operator == ( const CCollisionPlane &other )const { return static_cast< const CDagEdge& >( *this ) == static_cast< const CDagEdge& >( other ) && m_Plane == other.m_Plane;
}
RnPlane_t m_Plane; float m_flStickiness; };
/*schema*/ class CCtrlOffset : public CDagEdge { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CCtrlOffset );
public: CCtrlOffset() { m_vOffset = Vector( 0, 8, 0 ); // zero offset isn't really useful
} bool operator == ( const CCtrlOffset &other )const { return static_cast< const CDagEdge& >( *this ) == static_cast< const CDagEdge& >( other ) && m_vOffset == other.m_vOffset; } operator const FeCtrlOffset_t()const { FeCtrlOffset_t offset; offset.nCtrlChild = m_nChildBone; offset.nCtrlParent = m_nParentBone; offset.vOffset = m_vOffset; return offset; }
Vector m_vOffset; };
/*schema*/ class CBone { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CBone )
public: CBone( ) { m_nParent = -1; m_bVirtual = false; m_bNeedNodeBase = false; m_bHasMassOverride = false; m_bSimulated = true; m_bForceSimulated = false; m_bFreeRotation = true; m_bAnimRotation = false; m_bOsOffset = false; m_Transform = g_TransformIdentity; m_flMass = 1.0f; m_flMassBias = 0.0f; m_bNeedsWorldCollision = false; m_Integrator.Init( ); m_nFollowParent = -1; m_flFollowWeight = 0; m_flWorldFriction = 0; m_flGroundFriction = 0; m_flLegacyStretchForce = 0; m_bUseRods = false; m_flCollisionRadius = 0; m_nCollisionMask = 0xFFFF; m_flLocalForce = 1.0f; m_flLocalRotation = 0.0f; m_flVolumetricSolveAmount = 0.0f; }
CFeModelBuilder::BuildNode_t AsBuildNode()const;
uint32 GetNameHash() { return MakeStringToken( m_Name.Get() ).GetHashCode(); } bool ApplyDotaFlags( const char *pFlags, CBoneParseParams *pParamsOut ); bool ChangeNode( int nOldNode, int nNewNode ) { bool bChanged = false; if ( m_nParent == nOldNode ) { m_nParent = nNewNode; bChanged = true; } if ( m_nFollowParent == nOldNode ) { m_nFollowParent = nNewNode; bChanged = true; } return bChanged; } CTransform GetOffsetTransform( const Vector &vOffset ) { return CTransform( m_Transform.TransformVector( vOffset ), m_Transform.m_orientation ); } void RebaseNodes( int nBaseNode ) { if( m_nFollowParent >= 0 ) m_nFollowParent += nBaseNode; if ( m_nParent >= 0 ) m_nParent += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nFollowParent, remap ); RemapNode( m_nParent, remap ); } public: bool m_bSimulated; // this is an fx particle comprising jiggle bones, chains, cloths, or any other soft body
bool m_bForceSimulated; // if true, this node may not be deduced to be non-simulated
bool m_bFreeRotation; bool m_bAnimRotation; bool m_bVirtual; bool m_bNeedNodeBase; bool m_bNeedsWorldCollision; bool m_bOsOffset; // object-space offset, used for compatibility with S1 cloth
float m_flWorldFriction; META( MPropertyFriendlyName = "Ground NOT-Collide" );// this is not a friction coefficient! this is the "WorldFriction" parameter from source1 cloth
float m_flGroundFriction; float m_flLegacyStretchForce; // premultiplied by invMass here
float m_flMass; float m_flMassBias; int m_nFollowParent; float m_flFollowWeight; float m_flCollisionRadius; FeNodeIntegrator_t m_Integrator; bool m_bHasMassOverride; uint32 m_nCollisionMask; int m_nParent; // parent bone index
CUtlString m_Name; // bone name, the same as in model, the same as used in animation
CTransform m_Transform; META( MPropertySuppressField );// bind pose, relaxed pose
bool m_bUseRods; // UI convenience: when checked, affects generation of quads or rods around this node
float m_flLocalForce; float m_flLocalRotation; float m_flVolumetricSolveAmount; };
/*schema*/ class CConstraint { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CConstraint )
public: CConstraint( int nBone0 = -1, int nBone1 = -1 ) { m_nBones[0] = nBone0; m_nBones[1] = nBone1; }
bool Equals( int nBone0, int nBone1 ) const { return ( m_nBones[0] == nBone0 && m_nBones[1] == nBone1 ) || ( m_nBones[1] == nBone0 && m_nBones[0] == nBone1 ); }
int m_nBones[2]; // bone indices of the connected particles
public: bool UsesNode( int nNode ) const { return m_nBones[ 0 ] == nNode || m_nBones[ 1 ] == nNode; } void ChangeNode( int nOldNode, int nNewNode ) { if ( m_nBones[ 0 ] == nOldNode ) m_nBones[ 0 ] = nNewNode; if ( m_nBones[ 1 ] == nOldNode ) m_nBones[ 1 ] = nNewNode; } void RebaseNodes( int nBaseNode ) { m_nBones[ 0 ] += nBaseNode; m_nBones[ 1 ] += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nBones[ 0 ], remap ); RemapNode( m_nBones[ 1 ], remap ); } };
/*schema*/ class CCapsule { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CCapsule )
public: int m_nBone[2]; Vector m_vCenter[2]; // each capsule center in the corresponding bone's local coordinates
float m_flRadius; public: bool UsesNode( int nNode ) const { return m_nBone[ 0 ] == nNode || m_nBone[ 1 ] == nNode; } void ChangeNode( int nOldNode, int nNewNode ) { if ( m_nBone[ 0 ] == nOldNode ) m_nBone[ 0 ] = nNewNode; if ( m_nBone[ 1 ] == nOldNode ) m_nBone[ 1 ] = nNewNode; } void RebaseNodes( int nBaseNode ) { m_nBone[ 0 ] += nBaseNode; m_nBone[ 1 ] += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nBone[ 0 ], remap ); RemapNode( m_nBone[ 1 ], remap ); } };
/*schema*/ class CQuad { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CQuad )
public: uint m_nNodes[ 4 ]; bool m_bUseRods; CQuad() { m_bUseRods = false; }
CQuad( uint nNode0, uint nNode1, uint nNode2, uint nNode3 ) { m_nNodes[ 0 ] = nNode0; m_nNodes[ 1 ] = nNode1; m_nNodes[ 2 ] = nNode2; m_nNodes[ 3 ] = nNode3; m_bUseRods = false; }
CFeModelBuilder::BuildElem_t AsBuildElem()const;
bool operator == ( const CQuad &right ) const { return m_nNodes[ 0 ] == right.m_nNodes[ 0 ] && m_nNodes[ 1 ] == right.m_nNodes[ 1 ] && m_nNodes[ 2 ] == right.m_nNodes[ 2 ] && m_nNodes[ 3 ] == right.m_nNodes[ 3 ]; } bool UsesNode( uint nNode ) const { return m_nNodes[ 0 ] == nNode || m_nNodes[ 1 ] == nNode || m_nNodes[ 2 ] == nNode || m_nNodes[ 3 ] == nNode; } template <typename TBitVec > bool UsesAnyNode( const TBitVec &nodes ) { return nodes[ m_nNodes[ 0 ] ] || nodes[ m_nNodes[ 1 ] ] || nodes[ m_nNodes[ 2 ] ] || nodes[ m_nNodes[ 3 ] ] ; } void ChangeNode( uint nOldNode, uint nNewNode ) { if ( m_nNodes[ 0 ] == nOldNode ) m_nNodes[ 0 ] = nNewNode; if ( m_nNodes[ 1 ] == nOldNode ) m_nNodes[ 1 ] = nNewNode; if ( m_nNodes[ 2 ] == nOldNode ) m_nNodes[ 2 ] = nNewNode; if ( m_nNodes[ 3 ] == nOldNode ) m_nNodes[ 3 ] = nNewNode; } bool IsValid( uint nNodeCount )const { return m_nNodes[ 0 ] < nNodeCount && m_nNodes[ 1 ] < nNodeCount && m_nNodes[ 2 ] < nNodeCount && m_nNodes[ 3 ] < nNodeCount; } void RebaseNodes( int nBaseNode ) { m_nNodes[ 0 ] += nBaseNode; m_nNodes[ 1 ] += nBaseNode; m_nNodes[ 2 ] += nBaseNode; m_nNodes[ 3 ] += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nNodes[ 0 ], remap ); RemapNode( m_nNodes[ 1 ], remap ); RemapNode( m_nNodes[ 2 ], remap ); RemapNode( m_nNodes[ 3 ], remap ); } };
/*schema*/ class CRod { //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CRod )
public: uint m_nNodes[ 2 ]; float32 m_flMotionBias[ 2 ]; //
float32 m_flRelaxationFactor;
bool m_bExplicitLength; float32 m_flLength; float32 m_flContractionFactor;
CRod( ) { m_bExplicitLength = false; m_flContractionFactor = 0.05f; // in Source1, rods may contract to 0
m_flLength = 0; m_nNodes[ 0 ] = m_nNodes[ 1 ] = 0; m_flRelaxationFactor = 1.0f; m_flMotionBias[ 0 ] = m_flMotionBias[ 1 ] = 1.0f; } CRod( uint nNode0, uint nNode1, float flRelaxationFactor = 1.0f ) { m_nNodes[ 0 ] = nNode0; m_nNodes[ 1 ] = nNode1; m_flRelaxationFactor = flRelaxationFactor; m_flMotionBias[ 0 ] = m_flMotionBias[ 1 ] = 1.0f; } bool operator < ( const CRod &other )const { return m_nNodes[ 0 ] == other.m_nNodes[ 0 ] ? m_nNodes[ 1 ] < other.m_nNodes[ 1 ] : m_nNodes[ 0 ] < other.m_nNodes[ 0 ]; }
bool operator == ( const CRod &other )const { return ( m_nNodes[ 0 ] == other.m_nNodes[ 0 ] && m_nNodes[ 1 ] == other.m_nNodes[ 1 ] ) || ( m_nNodes[ 0 ] == other.m_nNodes[ 1 ] && m_nNodes[ 1 ] == other.m_nNodes[ 0 ] ); } bool Equals( uint nNode0, uint nNode1 )const { return ( m_nNodes[ 0 ] == nNode0 && m_nNodes[ 1 ] == nNode1 ) || ( m_nNodes[ 1 ] == nNode0 && m_nNodes[ 0 ] == nNode1 ); } bool UsesNode( uint nNode ) const { return m_nNodes[ 0 ] == nNode || m_nNodes[ 1 ] == nNode; } void ChangeNode( uint nOldNode, uint nNewNode ) { if ( m_nNodes[ 0 ] == nOldNode ) m_nNodes[ 0 ] = nNewNode; if ( m_nNodes[ 1 ] == nOldNode ) m_nNodes[ 1 ] = nNewNode; } void RebaseNodes( int nBaseNode ) { m_nNodes[ 0 ] += nBaseNode; m_nNodes[ 1 ] += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nNodes[ 0 ], remap ); RemapNode( m_nNodes[ 1 ], remap ); } void Reverse() { ::Swap( m_nNodes[ 0 ], m_nNodes[ 1 ] ); ::Swap( m_flMotionBias[ 0 ], m_flMotionBias[ 1 ] ); } uint GetOtherNode( uint nNode )const { if ( m_nNodes[ 1 ] == nNode ) { return m_nNodes[ 0 ]; } else { Assert( m_nNodes[ 0 ] == nNode ); return m_nNodes[ 1 ]; } } bool IsValid( uint nNodeCount )const { return m_nNodes[ 0 ] < nNodeCount && m_nNodes[ 1 ] < nNodeCount; }
};
/*schema*/ class CSpring { public: //DECLARE_SCHEMA_DATA_CLASS( CAuthPhysFx::CSpring )
uint m_nNodes[ 2 ]; float32 m_flSpringConstant; float32 m_flSpringDamping; float32 m_flStretchiness; // Not Implemented
CSpring( ){} CSpring( uint nNode0, uint nNode1, float flSpringConstant, float flSpringDamping, float flStretchForce, float flStretchiness ) { m_nNodes[ 0 ] = nNode0; m_nNodes[ 1 ] = nNode1; m_flSpringConstant = flSpringConstant + 60 * flStretchForce * flStretchiness; // I think this may be approximately how it effectively works in Source1;;
m_flSpringDamping = flSpringDamping; m_flStretchiness = flStretchiness; // Note: so far this is not used, saving mainly for documentation
} bool operator < ( const CRod &other ) { return m_nNodes[ 0 ] == other.m_nNodes[ 0 ] ? m_nNodes[ 1 ] < other.m_nNodes[ 1 ] : m_nNodes[ 0 ] < other.m_nNodes[ 0 ]; } bool UsesNode( uint nNode ) const { return m_nNodes[ 0 ] == nNode || m_nNodes[ 1 ] == nNode; } void ChangeNode( uint nOldNode, uint nNewNode ) { if ( m_nNodes[ 0 ] == nOldNode ) m_nNodes[ 0 ] = nNewNode; if ( m_nNodes[ 1 ] == nOldNode ) m_nNodes[ 1 ] = nNewNode; } void RebaseNodes( int nBaseNode ) { m_nNodes[ 0 ] += nBaseNode; m_nNodes[ 1 ] += nBaseNode; } void RemapNodes( const CUtlVector< int > &remap ) { RemapNode( m_nNodes[ 0 ], remap ); RemapNode( m_nNodes[ 1 ], remap ); } };
public: bool IsEmpty() const { return m_Quads.IsEmpty() && m_Rods.IsEmpty() && m_Nodes.IsEmpty() && m_CollisionSpheres.IsEmpty() && m_CollisionPlanes.IsEmpty() && m_SphereRigids.IsEmpty() && m_TaperedCapsuleStretches.IsEmpty() && m_TaperedCapsuleRigids.IsEmpty() && m_Capsules.IsEmpty() && m_Constraints.IsEmpty() && m_Springs.IsEmpty(); } bool ImportDotaCloth( const char *pClothFile, CPhysModelSource &physicsModel/*CUtlStringMap< int, CUtlSymbolTable > *pBoneToIndex*/ ); void Load( const CFeModel *pFeModel ); void AddRod( const CUtlVector< CBone > &nodes, uint nNode0, uint nNode1, float flRelaxationFactor );
void SetBones( const CUtlVector< CBone > &bones ); int AddConstraint( int nBone0, int nBone1 ); const CBone *GetBone( int nBone ) const { return &m_Nodes[nBone]; } CBone *GetBone( int nBone ) { return &m_Nodes[nBone]; } int FindNodeIndex( const char *pName ); CBone *GetOrCreateBone( const char *pName ); int GetBoneCount() const { return m_Nodes.Count(); } int GetSimParticleCount()const; int GetStaticParticleCount( )const { return m_Nodes.Count( ) - GetSimParticleCount( ); } CLockedResource< PhysFeModelDesc_t > Compile( CResourceStream *pStream, const CVClothProxyMeshOptions *pOptions = NULL )const; bool IsSimilarTo( const CFeModel *pFeModel )const; bool IsConstraintSimulated( int nConstraint ) const ; bool IsSpringSimulated( int nSpring ) const;
int GetRodCount( ) const { return m_Rods.Count( ); } CRod *GetRod( int i ) { return &m_Rods[ i ]; } float GetRodLength( int nRod )const; int GetQuadCount( ) const { return m_Quads.Count( ); } CQuad *GetQuad( int i ) { return &m_Quads[ i ]; }
int GetConstraintCount() const { return m_Constraints.Count(); } CConstraint* GetConstraint( int i ) { return &m_Constraints[i]; }
int GetSpringCount( ) const { return m_Springs.Count( ); } CSpring* GetSpring( int i ) { return &m_Springs[ i ]; }
int GetCapsuleCount() const { return m_Capsules.Count(); } CCapsule* GetCapsule( int i ) { return &m_Capsules[i]; }
bool IsNewSpringAllowed( int nBone0, int nBone1 ); bool IsNewRodAllowed( int nBone0, int nBone1 );
void SortAndRemoveDuplicates( ); void RemoveRodsConnecting( const CVarBitVec &nodes ); void RemoveQuadsConnecting( const CVarBitVec &nodes );
int BuildIslandMap( CUtlVector< int > &nodeToIsland )const;
void Swap( CAuthPhysFx &other ) { m_Quads.Swap( other.m_Quads ); m_Rods.Swap( other.m_Rods ); m_Springs.Swap( other.m_Springs ); m_Constraints.Swap( other.m_Constraints ); // springs and constraints between fx particles
m_Capsules.Swap( other.m_Capsules ); // capsules repelling the particles
m_Nodes.Swap( other.m_Nodes ); // bones, including dynamic particles
m_TaperedCapsuleRigids.Swap( other.m_TaperedCapsuleRigids ); m_TaperedCapsuleStretches.Swap( other.m_TaperedCapsuleStretches ); m_SphereRigids.Swap( other.m_SphereRigids ); m_CollisionSpheres.Swap( other.m_CollisionSpheres ); m_CollisionPlanes.Swap( other.m_CollisionPlanes ); m_PresetNodeBases.Swap( other.m_PresetNodeBases ); m_FitInfluences.Swap( other.m_FitInfluences );
::Swap( m_flDefaultSurfaceStretch, other.m_flDefaultSurfaceStretch ); ::Swap( m_flDefaultThreadStretch, other.m_flDefaultThreadStretch );
::Swap( m_flDefaultGravityScale, other.m_flDefaultGravityScale ); ::Swap( m_flDefaultVelAirDrag, other.m_flDefaultVelAirDrag ); ::Swap( m_flDefaultExpAirDrag, other.m_flDefaultExpAirDrag ); ::Swap( m_flDefaultVelQuadAirDrag, other.m_flDefaultVelQuadAirDrag ); ::Swap( m_flDefaultExpQuadAirDrag, other.m_flDefaultExpQuadAirDrag ); ::Swap( m_flDefaultVelRodAirDrag, other.m_flDefaultVelRodAirDrag ); ::Swap( m_flDefaultExpRodAirDrag, other.m_flDefaultExpRodAirDrag ); ::Swap( m_flQuadVelocitySmoothRate, other.m_flQuadVelocitySmoothRate ); ::Swap( m_flRodVelocitySmoothRate, other.m_flRodVelocitySmoothRate ); ::Swap( m_flWindage, other.m_flWindage ); ::Swap( m_flWindDrag, other.m_flWindDrag ); ::Swap( m_nQuadVelocitySmoothIterations, other.m_nQuadVelocitySmoothIterations ); ::Swap( m_nRodVelocitySmoothIterations, other.m_nRodVelocitySmoothIterations ); ::Swap( m_flDefaultGroundFriction, other.m_flDefaultGroundFriction ); ::Swap( m_flDefaultWorldCollisionPenetration, other.m_flDefaultWorldCollisionPenetration ); ::Swap( m_bForceWorldCollisionOnAllNodes, other.m_bForceWorldCollisionOnAllNodes ); ::Swap( m_flAddWorldCollisionRadius, other.m_flAddWorldCollisionRadius );
::Swap( m_flAddCurvature, other.m_flAddCurvature ); ::Swap( m_flQuadBendTolerance, other.m_flQuadBendTolerance ); ::Swap( m_flLocalForce, other.m_flLocalForce ); ::Swap( m_flLocalRotation, other.m_flLocalRotation ); ::Swap( m_flVolumetricSolveAmount, other.m_flVolumetricSolveAmount ); ::Swap( m_bFollowTheLead, other.m_bFollowTheLead ); ::Swap( m_bUsePerNodeLocalForceAndRotation, other.m_bUsePerNodeLocalForceAndRotation );
::Swap( m_bUninertialRods, other.m_bUninertialRods ); ::Swap( m_bExplicitMasses, other.m_bExplicitMasses ); ::Swap( m_bCanCollideWithWorldCapsulesAndSpheres, other.m_bCanCollideWithWorldCapsulesAndSpheres ); ::Swap( m_bCanCollideWithWorldHulls, other.m_bCanCollideWithWorldHulls ); ::Swap( m_bCanCollideWithWorldMeshes, other.m_bCanCollideWithWorldMeshes ); ::Swap( m_bUnitlessDamping, other.m_bUnitlessDamping ); ::Swap( m_nMergePriority, other.m_nMergePriority ); ::Swap( m_bNewStyle, other.m_bNewStyle ); ::Swap( m_bAddStiffnessRods, other.m_bAddStiffnessRods ); ::Swap( m_bRigidEdgeHinges, other.m_bRigidEdgeHinges ); }
template <typename T > static void AppendAndRebaseNodes( CUtlVector< T > &arrThis, const CUtlVector< T > &arrThat, int nNodeBase ) { int nScan = arrThis.Count(); arrThis.AddMultipleToTail( arrThat.Count(), arrThat.Base() ); for ( ; nScan < arrThis.Count(); ++nScan ) { arrThis[ nScan ].RebaseNodes( nNodeBase ); } } template <typename T > static void AppendAndRemapNodes( CUtlVector< T > &arrThis, const CUtlVector< T > &arrThat, const CUtlVector< int > &remap ) { int nScan = arrThis.Count(); arrThis.AddMultipleToTail( arrThat.Count(), arrThat.Base() ); for ( ; nScan < arrThis.Count(); ++nScan ) { arrThis[ nScan ].RemapNodes( remap ); } }
void Append( const CAuthPhysFx &other ) { int nBaseNodes = m_Nodes.Count();
if ( m_nMergePriority < other.m_nMergePriority ) { m_flDefaultSurfaceStretch = other.m_flDefaultSurfaceStretch; m_flDefaultThreadStretch = other.m_flDefaultThreadStretch;
m_flDefaultGravityScale = other.m_flDefaultGravityScale; m_flDefaultVelAirDrag = other.m_flDefaultVelAirDrag; m_flDefaultExpAirDrag = other.m_flDefaultExpAirDrag; m_flDefaultVelQuadAirDrag = other.m_flDefaultVelQuadAirDrag; m_flDefaultExpQuadAirDrag = other.m_flDefaultExpQuadAirDrag; m_flDefaultVelRodAirDrag = other.m_flDefaultVelRodAirDrag; m_flDefaultExpRodAirDrag = other.m_flDefaultExpRodAirDrag; m_flQuadVelocitySmoothRate = other.m_flQuadVelocitySmoothRate; m_flRodVelocitySmoothRate = other.m_flRodVelocitySmoothRate; m_flWindage = other.m_flWindage; m_flWindDrag = other.m_flWindage;
m_nQuadVelocitySmoothIterations = other.m_nQuadVelocitySmoothIterations; m_nRodVelocitySmoothIterations = other.m_nRodVelocitySmoothIterations; m_flDefaultGroundFriction = other.m_flDefaultGroundFriction; m_flDefaultWorldCollisionPenetration = other.m_flDefaultWorldCollisionPenetration; m_bForceWorldCollisionOnAllNodes = other.m_bForceWorldCollisionOnAllNodes; m_flAddWorldCollisionRadius = other.m_flAddWorldCollisionRadius;
m_flAddCurvature = other.m_flAddCurvature; m_flQuadBendTolerance = other.m_flQuadBendTolerance; m_flLocalForce = other.m_flLocalForce; m_flLocalRotation = other.m_flLocalRotation; m_flVolumetricSolveAmount = other.m_flVolumetricSolveAmount; m_bFollowTheLead = other.m_bFollowTheLead; m_bUsePerNodeLocalForceAndRotation = other.m_bUsePerNodeLocalForceAndRotation; m_bUninertialRods = other.m_bUninertialRods; m_bExplicitMasses = other.m_bExplicitMasses; m_bCanCollideWithWorldHulls = other.m_bCanCollideWithWorldHulls; m_bCanCollideWithWorldMeshes = other.m_bCanCollideWithWorldMeshes; m_bCanCollideWithWorldCapsulesAndSpheres = other.m_bCanCollideWithWorldCapsulesAndSpheres; m_bUnitlessDamping = other.m_bUnitlessDamping; m_nMergePriority = other.m_nMergePriority; m_bNewStyle = other.m_bNewStyle; m_bAddStiffnessRods = other.m_bAddStiffnessRods; m_bRigidEdgeHinges = other.m_bRigidEdgeHinges; }
CUtlVector< int > remap; remap.SetCount( other.m_Nodes.Count() ); // merge the Nodes
m_Nodes.EnsureCapacity( m_Nodes.Count() + other.m_Nodes.Count() ); for ( int nOtherNode = 0; nOtherNode < other.m_Nodes.Count(); ++nOtherNode ) { const CBone &otherNode = other.m_Nodes[ nOtherNode ]; int nMapNode = -1; if ( !otherNode.m_Name.IsEmpty() ) { nMapNode = FindNodeIndex( otherNode.m_Name ); } if ( nMapNode < 0 ) { // couldn't find node to map, create a new one
remap[ nOtherNode ] = m_Nodes.AddToTail( otherNode ); } else { remap[ nOtherNode ] = nMapNode; } } // the remap array is ready; use it to remap all the node indices
for ( int nNewNode = nBaseNodes; nNewNode < m_Nodes.Count(); ++nNewNode ) { m_Nodes[ nNewNode ].RemapNodes( remap ); } AppendAndRemapNodes( m_Quads, other.m_Quads, remap ); AppendAndRemapNodes( m_Rods, other.m_Rods, remap ); AppendAndRemapNodes( m_Springs, other.m_Springs, remap ); AppendAndRemapNodes( m_Constraints, other.m_Constraints, remap ); // springs and constraints between fx particles
AppendAndRemapNodes( m_Capsules, other.m_Capsules, remap ); // capsules repelling the particles
AppendAndRemapNodes( m_TaperedCapsuleRigids, other.m_TaperedCapsuleRigids, remap ); AppendAndRemapNodes( m_TaperedCapsuleStretches, other.m_TaperedCapsuleStretches, remap ); AppendAndRemapNodes( m_SphereRigids, other.m_SphereRigids, remap ); AppendAndRemapNodes( m_CollisionSpheres, other.m_CollisionSpheres, remap ); AppendAndRemapNodes( m_CollisionPlanes, other.m_CollisionPlanes, remap ); AppendAndRemapNodes( m_PresetNodeBases, other.m_PresetNodeBases, remap ); AppendAndRemapNodes( m_FitInfluences, other.m_FitInfluences, remap ); }
void Purge( ) { m_Quads.Purge(); m_Rods.Purge(); m_Springs.Purge(); m_Constraints.Purge(); // springs and constraints between fx particles
m_Capsules.Purge(); // capsules repelling the particles
m_Nodes.Purge(); // bones, including dynamic particles
m_TaperedCapsuleRigids.Purge(); m_TaperedCapsuleStretches.Purge(); m_SphereRigids.Purge(); m_CollisionSpheres.Purge(); m_CollisionPlanes.Purge(); m_PresetNodeBases.Purge(); m_FitInfluences.Purge(); InitDefaults(); }
void InitDefaults() { m_flDefaultSurfaceStretch = 0; m_flDefaultThreadStretch = 0; m_flLocalForce = 1.0f; m_flLocalRotation = 0.0f; m_flVolumetricSolveAmount = 0.0f; m_bUninertialRods = false; m_bExplicitMasses = false; m_bCanCollideWithWorldHulls = false; m_bCanCollideWithWorldMeshes = false; m_bCanCollideWithWorldCapsulesAndSpheres = false; m_bUnitlessDamping = true; m_bFollowTheLead = false; m_bUsePerNodeLocalForceAndRotation = false; m_flAddCurvature = 0; m_flQuadBendTolerance = 0.05f;
m_flDefaultGravityScale = 1.0f; m_flDefaultVelAirDrag = 0; m_flDefaultExpAirDrag = 0; m_flDefaultVelQuadAirDrag = 0; m_flDefaultExpQuadAirDrag = 0; m_flDefaultVelRodAirDrag = 0; m_flDefaultExpRodAirDrag = 0; m_flQuadVelocitySmoothRate = 0; m_flRodVelocitySmoothRate = 0; m_flWindage = 1.0f; m_flWindDrag = 0;
m_nQuadVelocitySmoothIterations = 0; m_nRodVelocitySmoothIterations = 0; m_bForceWorldCollisionOnAllNodes = false; m_flDefaultGroundFriction = 0; m_flDefaultWorldCollisionPenetration = 0; m_flAddWorldCollisionRadius = 2.0f;
m_nMergePriority = 0; m_bNewStyle = true; m_bAddStiffnessRods = true; m_bRigidEdgeHinges = false; }
void CreateRodMap( CAuthPhysFxRodMap &rodMap ) { rodMap.Init( GetBoneCount() ); for ( int nRod = 0; nRod < m_Rods.Count(); ++nRod ) { rodMap.Append( m_Rods[ nRod ].m_nNodes[ 0 ], nRod ); rodMap.Append( m_Rods[ nRod ].m_nNodes[ 1 ], nRod ); } }
void CreateConnMap( CAuthPhysFxRodMap &connMap ) { connMap.Init( GetBoneCount() ); for ( int nRod = 0; nRod < m_Rods.Count(); ++nRod ) { const uint *n = m_Rods[ nRod ].m_nNodes; //if ( filter( n[ 0 ] ) && filter( n[ 1 ] ) )
{ connMap.Append( n[ 0 ], n[ 1 ] ); connMap.Append( n[ 1 ], n[ 0 ] ); } } for ( const CQuad &quad : m_Quads ) { for ( int i = 0; i < 3; ++i ) { uint n0 = quad.m_nNodes[ i ]; for ( int j = i + 1; j < 4; ++j ) { uint n1 = quad.m_nNodes[ j ]; if ( n0 != n1 ) { connMap.Append( n0, n1 ); connMap.Append( n1, n0 ); } } } } }
CBone *GetDriverBone( int fxBone ) { CAuthPhysFx::CBone *pFxBone; for ( ;; ) { AssertDbg( fxBone >= 0 && fxBone < GetBoneCount() ); pFxBone = GetBone( fxBone ); // bones that move by themselves are driving themselves
if ( pFxBone->m_bSimulated ) break; if ( pFxBone->m_bFreeRotation ) break;
// try to find the true parent that controls all movements of this bone
if ( pFxBone->m_nParent >= 0 ) { fxBone = pFxBone->m_nParent; } else if ( pFxBone->m_nFollowParent >= 0 && pFxBone->m_flFollowWeight >= 1.0f ) { fxBone = pFxBone->m_nFollowParent; } else break; // didn't find true parent
} return pFxBone; }
public: CUtlVector< CQuad > m_Quads; CUtlVector< CRod > m_Rods; CUtlVector< CSpring > m_Springs; CUtlVector< CConstraint > m_Constraints; // springs and constraints between fx particles
CUtlVector< CCapsule > m_Capsules; // capsules repelling the particles
CUtlVector< CBone > m_Nodes; // bones, including dynamic particles
CUtlVector< CCollisionSphere > m_CollisionSpheres; CUtlVector< CCollisionPlane > m_CollisionPlanes; CUtlVector< FeNodeBase_t > m_PresetNodeBases; CUtlVector< FeTaperedCapsuleStretch_t > m_TaperedCapsuleStretches; CUtlVector< FeTaperedCapsuleRigid_t > m_TaperedCapsuleRigids; CUtlVector< FeSphereRigid_t > m_SphereRigids; CUtlVector< CCtrlOffset > m_CtrlOffsets; CUtlVector< FeFitInfluence_t > m_FitInfluences; float m_flDefaultSurfaceStretch; float m_flDefaultThreadStretch;
float m_flDefaultGravityScale; float m_flDefaultVelAirDrag; float m_flDefaultExpAirDrag; float m_flDefaultVelQuadAirDrag; float m_flDefaultExpQuadAirDrag; float m_flDefaultVelRodAirDrag; float m_flDefaultExpRodAirDrag; float m_flQuadVelocitySmoothRate; float m_flRodVelocitySmoothRate; float m_flWindage; float m_flWindDrag; int m_nQuadVelocitySmoothIterations; int m_nRodVelocitySmoothIterations; float m_flDefaultGroundFriction; float m_flDefaultWorldCollisionPenetration; META( MPropertyFriendlyName = "World Velocity Penetration (Source1) 0.0 = velocity goes to 0 on contact" ); float m_flAddWorldCollisionRadius;
float m_flLocalForce; float m_flLocalRotation; float m_flVolumetricSolveAmount; float m_flAddCurvature; float m_flQuadBendTolerance; META( MPropertyFriendlyName = "Triangulate Quads bent more than" ); bool m_bFollowTheLead; bool m_bUsePerNodeLocalForceAndRotation; bool m_bUninertialRods; bool m_bExplicitMasses; bool m_bUnitlessDamping; bool m_bForceWorldCollisionOnAllNodes; // convenience function: just slam all nodes' world collision flag, useful for quick testing
int m_nMergePriority; bool m_bNewStyle;
bool m_bCanCollideWithWorldMeshes; bool m_bCanCollideWithWorldCapsulesAndSpheres; bool m_bCanCollideWithWorldHulls;
bool m_bAddStiffnessRods; bool m_bRigidEdgeHinges; };
// typedef CAuthPhysFx::CQuad CAuthPhysFxQuad;
// typedef CAuthPhysFx::CRod CAuthPhysFxRod;
// typedef CAuthPhysFx::CSpring CAuthPhysFxSpring ;
// typedef CAuthPhysFx::CConstraint CAuthPhysFxConstraint ;
// typedef CAuthPhysFx::CCapsule CAuthPhysFxCapsule ;
// typedef CAuthPhysFx::CBone CAuthPhysFxBone ;
// typedef CAuthPhysFx::CCollisionSphere CAuthPhysFxCollisionSphere ;
// typedef CAuthPhysFx::CCollisionPlane CAuthPhysFxCollisionPlane ;
class CBoneParseParams { public: CBoneParseParams( KeyValues *pSubKey, int nCompatibilityMode ); typedef CAuthPhysFx::CBone CBone; void ApplyDefaultParams( CBone &node ); bool ApplyDotaFlags( CAuthPhysFx::CBone &bone, const char *pszParms ); public: float m_flWorldFriction; float m_flAnimationForceAttraction; float m_flAnimationVertexAttraction; float m_flDamping; float m_flFixedPointDamping; float m_flSpringStretchiness; float m_flRelaxationFactor; float m_flStretchForce; float m_flStructSpringConstant; float m_flStructSpringDamping; float m_flGravityScale; public: bool m_bPrevColumnParent; Vector m_vOffset; // offset relative to the animation transform
const char *m_pBonePrefix; int m_nNominalColumnCount; int m_nRowCount; int m_nVirtColumnCount;
float m_flFollowRootBegin; float m_flFollowRootEnd; bool m_bIsRopeS1; int m_nBoneIndex;
typedef CAuthPhysFx::CCollisionPlane CCollisionPlane; typedef CAuthPhysFx::CCollisionSphere CCollisionSphere; CUtlVector< CCollisionSphere > *m_pCollisionSpheres; CUtlVector< CCollisionPlane > *m_pCollisionPlanes; };
class CNodeIdx { public: CNodeIdx( uint nBase, uint nRows, uint nColumns ): m_nBase( nBase ), m_nRows( nRows ), m_nColumns( nColumns ) {} uint operator() ( uint nRow, uint nColumn )const { AssertDbg( nRow < m_nRows && nColumn < m_nColumns ); return m_nBase + nRow * m_nColumns + nColumn; } protected: uint m_nBase; uint m_nRows; uint m_nColumns; };
class CAuthClothParser: public CAuthPhysFx { public: void SetBones( CPhysModelSource &physicsModel ); bool Parse( KeyValues *kv );
bool ParseDefaults( KeyValues *pSubkey ); bool ParsePiece( KeyValues *pSubkey ); void ParseExplicitDefinitions( KeyValues *pSubkey, CBoneParseParams &parseParm ); bool ParseLegacyDotaNodeGrid( KeyValues *pSubKey, CBoneParseParams &parseParms, const CNodeIdx &nodeIdx ); bool CreateLegacyDotaRodGrid( CBoneParseParams &parseParms, const CNodeIdx &nodeIdx, int ); bool TieModelToNewNode( int nNewNode );
void ReconstructHierarchy( );
void ParseExplicitNode( KeyValues *kv, CBoneParseParams &parseParm ); void ParseExplicitElem( KeyValues *kv, CBoneParseParams &parseParm ); template <typename T> void ParseExplicitColl( KeyValues *kv, CBoneParseParams &parseParm, CUtlVector< T > &collArray );
int FindNodeByName( const char *pName ); void AddDotaRod( uint nNode0, uint nNode1, CBoneParseParams &parseParm ); protected: int m_nDefaultCompatibilityMode; int m_nCompatibilityMode;
CUtlStringMap< int > m_NodeNameMap; int m_nNodeNameMapNodes;
CUtlStringMap< int > m_BoneToIndex; CUtlVector< int > m_BoneToParent; CUtlVector< int > m_ModelBoneToNode; CUtlVector< CTransform >m_BoneTransforms; };
struct AuthHullSimplificationParams_t: public RnHullSimplificationParams_t { float m_flMinSkinWeight; bool m_bIncludSubtree;
AuthHullSimplificationParams_t( ) { m_bIncludSubtree = false; m_flMinSkinWeight = 0.5f; } };
template <typename TBitVec> void CAuthPhysFx::AlignNodes( const TBitVec &useNodes ) { CUtlVectorAligned< CFeModelBuilder::BuildNode_t > nodes; nodes.SetCount( m_Nodes.Count() ); for ( int nNode = 0; nNode < nodes.Count(); ++nNode ) { nodes[ nNode ] = m_Nodes[ nNode ].AsBuildNode(); } CUtlVector< CFeModelBuilder::BuildElem_t > elems; elems.EnsureCapacity( m_Quads.Count() ); for ( int nQuad = 0; nQuad < m_Quads.Count(); ++nQuad ) { if ( m_Quads[ nQuad ].UsesAnyNode( useNodes ) ) { elems.AddToTail( m_Quads[ nQuad ].AsBuildElem() ); } } if ( !elems.IsEmpty() ) { CUtlVector < FeNodeBase_t > presets, bases; CUtlVectorOfPointers< CUtlSortVector< int > > neighbors; CFeModelBuilder::BuildNodeBases( nodes, elems, presets, bases, neighbors ); for ( const FeNodeBase_t &base : bases ) { if ( useNodes[ base.nNode ] ) { CBone &bone = m_Nodes[ base.nNode ]; bone.m_Transform.m_orientation = bone.m_Transform.m_orientation * Conjugate( base.qAdjust ); // qAdjust = ~predict * old_orient; so, to make qAdjust = idenity we need to make new_orient = predict = old_orient * ~(~predict * old_orient )
} } } }
#endif
|