diff --git a/.gitignore b/.gitignore index de0eca030..fff8f4c02 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ waf3*/ .depproj/ source-engine.sln *.save +*.save.* diff --git a/vphysics-physx/main.cpp.save b/vphysics-physx/main.cpp.save deleted file mode 100644 index b10627214..000000000 --- a/vphysics-physx/main.cpp.save +++ /dev/null @@ -1,260 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#include "cbase.h" -#include "interface.h" -#include "vphysics/object_hash.h" -#include "vphysics/collision_set.h" -#include "tier1/tier1.h" -#include "ivu_vhash.hxx" -#include "PxPhysicsAPI.h" - -using namespace physx; - -#if defined(_WIN32) && !defined(_X360) -#define WIN32_LEAN_AND_MEAN -#include -#endif // _WIN32 && !_X360 - -#include "vphysics_interfaceV30.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -static void ivu_string_print_function( const char *str ) -{ - Msg("%s", str); -} - -class PhysErrorCallback : public PxErrorCallback -{ -public: - virtual void reportError(PxErrorCode::Enum code, const char* message, const char* file, - int line) - { - // error processing implementation - Warning("Px: %s %s:%d\n", message, file, line); - } -}; - -PhysErrorCallback gPxErrorCallback; -PxDefaultAllocator gPxAllocatorCallback; - -PxFoundation *gPxFoundation = NULL; -PxPvd *gPxPvd = NULL; -PxPhysics *gPxPhysics = NULL; -PxCoocking - -// simple 32x32 bit array -class CPhysicsCollisionSet : public IPhysicsCollisionSet -{ -public: - ~CPhysicsCollisionSet() {} - CPhysicsCollisionSet() - { - memset( m_bits, 0, sizeof(m_bits) ); - } - void EnableCollisions( int index0, int index1 ) - { - Assert(index0<32&&index1<32); - m_bits[index0] |= 1< -{ -public: - CPhysicsInterface() : m_pCollisionSetHash(NULL) {} - virtual InitReturnVal_t Init(); - virtual void Shutdown(); - virtual void *QueryInterface( const char *pInterfaceName ); - virtual IPhysicsEnvironment *CreateEnvironment( void ); - virtual void DestroyEnvironment( IPhysicsEnvironment *pEnvironment ); - virtual IPhysicsEnvironment *GetActiveEnvironmentByIndex( int index ); - virtual IPhysicsObjectPairHash *CreateObjectPairHash(); - virtual void DestroyObjectPairHash( IPhysicsObjectPairHash *pHash ); - virtual IPhysicsCollisionSet *FindOrCreateCollisionSet( unsigned int id, int maxElementCount ); - virtual IPhysicsCollisionSet *FindCollisionSet( unsigned int id ); - virtual void DestroyAllCollisionSets(); - - typedef CTier1AppSystem BaseClass; -private: - CUtlVector m_envList; - CUtlVector m_collisionSets; - IVP_VHash_Store *m_pCollisionSetHash; -}; - - -//----------------------------------------------------------------------------- -// Expose singleton -//----------------------------------------------------------------------------- -static CPhysicsInterface g_MainDLLInterface; -IPhysics *g_PhysicsInternal = &g_MainDLLInterface; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPhysicsInterface, IPhysics, VPHYSICS_INTERFACE_VERSION, g_MainDLLInterface ); - -#define PVD_HOST "localhost" - -InitReturnVal_t CPhysicsInterface::Init() -{ - InitReturnVal_t nRetVal = BaseClass::Init(); - if ( nRetVal != INIT_OK ) - return nRetVal; - - bool recordMemoryAllocations = true; - - MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); - - gPxFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gPxAllocatorCallback, gPxErrorCallback); - - if( !gPxFoundation ) - { - Error("PxCreateFoundation failed!\n"); - return INIT_FAILED; - } - - gPxPvd = PxCreatePvd(*gPxFoundation); - PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate(PVD_HOST, 5425, 10000); - if(transport) - Msg("PxDefaultPvdSocketTransportCreate success\n"); - - gPxPvd->connect(*transport,PxPvdInstrumentationFlag::eALL); - - gPxPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gPxFoundation, PxTolerancesScale(), recordMemoryAllocations, gPxPvd); - - if( !gPxPhysics ) - { - Error("PxCreatePhysics failed!\n"); - return INIT_FAILED; - } - - return INIT_OK; -} - - -void CPhysicsInterface::Shutdown() -{ - if( gPxPhysics ) - gPxPhysics->release(); - - if( gPxFoundation ) - gPxFoundation->release(); - - - BaseClass::Shutdown( ); -} - - -//----------------------------------------------------------------------------- -// Query interface -//----------------------------------------------------------------------------- -void *CPhysicsInterface::QueryInterface( const char *pInterfaceName ) -{ - // Loading the datacache DLL mounts *all* interfaces - // This includes the backward-compatible interfaces + other vphysics interfaces - CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary - return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing. -} - - -//----------------------------------------------------------------------------- -// Implementation of IPhysics -//----------------------------------------------------------------------------- -IPhysicsEnvironment *CPhysicsInterface::CreateEnvironment( void ) -{ - IPhysicsEnvironment *pEnvironment = CreatePhysicsEnvironment(); - m_envList.AddToTail( pEnvironment ); - return pEnvironment; -} - -void CPhysicsInterface::DestroyEnvironment( IPhysicsEnvironment *pEnvironment ) -{ - m_envList.FindAndRemove( pEnvironment ); - delete pEnvironment; -} - -IPhysicsEnvironment *CPhysicsInterface::GetActiveEnvironmentByIndex( int index ) -{ - if ( index < 0 || index >= m_envList.Count() ) - return NULL; - - return m_envList[index]; -} - -IPhysicsObjectPairHash *CPhysicsInterface::CreateObjectPairHash() -{ - return ::CreateObjectPairHash(); -} - -void CPhysicsInterface::DestroyObjectPairHash( IPhysicsObjectPairHash *pHash ) -{ - delete pHash; -} -// holds a cache of these by id. -// NOTE: This is stuffed into vphysics.dll as a sneaky way of sharing the memory between -// client and server in single player. So you can't have different client/server rules. -IPhysicsCollisionSet *CPhysicsInterface::FindOrCreateCollisionSet( unsigned int id, int maxElementCount ) -{ - if ( !m_pCollisionSetHash ) - { - m_pCollisionSetHash = new IVP_VHash_Store(256); - } - Assert( id != 0 ); - Assert( maxElementCount <= 32 ); - if ( maxElementCount > 32 ) - return NULL; - - IPhysicsCollisionSet *pSet = FindCollisionSet( id ); - if ( pSet ) - return pSet; - intp index = m_collisionSets.AddToTail(); - m_pCollisionSetHash->add_elem( (void *)(intp)id, (void *)(intp)(index+1) ); - return &m_collisionSets[index]; -} - -IPhysicsCollisionSet *CPhysicsInterface::FindCollisionSet( unsigned int id ) -{ - if ( m_pCollisionSetHash ) - { - intp index = (intp)m_pCollisionSetHash->find_elem( (void *)(intp)id ); - if ( index > 0 ) - { - Assert( index <= m_collisionSets.Count() ); - if ( index <= m_collisionSets.Count() ) - { - return &m_collisionSets[index-1]; - } - } - } - return NULL; -} - -void CPhysicsInterface::DestroyAllCollisionSets() -{ - m_collisionSets.Purge(); - delete m_pCollisionSetHash; - m_pCollisionSetHash = NULL; -} - diff --git a/vphysics-physx/physics_collide.cpp.save b/vphysics-physx/physics_collide.cpp.save deleted file mode 100644 index 1278393e9..000000000 --- a/vphysics-physx/physics_collide.cpp.save +++ /dev/null @@ -1,2132 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#include "cbase.h" - -#include "ivp_surbuild_pointsoup.hxx" -#include "ivp_surbuild_ledge_soup.hxx" -#include "ivp_surman_polygon.hxx" -#include "ivp_compact_surface.hxx" -#include "ivp_compact_ledge.hxx" -#include "ivp_compact_ledge_solver.hxx" -#include "ivp_halfspacesoup.hxx" -#include "ivp_surbuild_halfspacesoup.hxx" -#include "ivp_template_surbuild.hxx" -#include "hk_mopp/ivp_surbuild_mopp.hxx" -#include "hk_mopp/ivp_surman_mopp.hxx" -#include "hk_mopp/ivp_compact_mopp.hxx" -#include "ivp_surbuild_polygon_convex.hxx" -#include "ivp_templates_intern.hxx" - -#include "cmodel.h" -#include "physics_trace.h" -#include "vcollide_parse_private.h" -#include "physics_virtualmesh.h" - -#include "mathlib/polyhedron.h" -#include "tier1/byteswap.h" -#include "physics_globals.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -class CPhysCollideCompactSurface; -struct bboxcache_t -{ - Vector mins; - Vector maxs; - CPhysCollideCompactSurface *pCollide; -}; - -class CPhysicsCollision : public IPhysicsCollision -{ -public: - CPhysicsCollision() - { - } - CPhysConvex *ConvexFromVerts( Vector **pVerts, int vertCount ); - CPhysConvex *ConvexFromVertsFast( Vector **pVerts, int vertCount ); - CPhysConvex *ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance ); - CPhysConvex *ConvexFromConvexPolyhedron( const CPolyhedron &ConvexPolyhedron ); - void ConvexesFromConvexPolygon( const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput ); - CPhysConvex *RebuildConvexFromPlanes( CPhysConvex *pConvex, float mergeDistance ); - float ConvexVolume( CPhysConvex *pConvex ); - float ConvexSurfaceArea( CPhysConvex *pConvex ); - CPhysCollide *ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount ); - CPhysCollide *ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams ); - - - CPolyhedron *PolyhedronFromConvex( CPhysConvex * const pConvex, bool bUseTempPolyhedron ); - int GetConvexesUsedInCollideable( const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit ); - - // store game-specific data in a convex solid - void SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData ); - void ConvexFree( CPhysConvex *pConvex ); - - CPhysPolysoup *PolysoupCreate( void ); - void PolysoupDestroy( CPhysPolysoup *pSoup ); - void PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits ); - CPhysCollide *ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP = true ); - - int CollideSize( CPhysCollide *pCollide ); - int CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap = false ); - // Get the AABB of an oriented collide - virtual void CollideGetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles ); - virtual Vector CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction ); - // compute the volume of a collide - virtual float CollideVolume( CPhysCollide *pCollide ); - virtual float CollideSurfaceArea( CPhysCollide *pCollide ); - - // Free a collide that was created with ConvertConvexToCollide() - // UNDONE: Move this up near the other Collide routines when the version is changed - virtual void DestroyCollide( CPhysCollide *pCollide ); - - CPhysCollide *BBoxToCollide( const Vector &mins, const Vector &maxs ); - CPhysConvex *BBoxToConvex( const Vector &mins, const Vector &maxs ); - - // loads a set of solids into a vcollide_t - virtual void VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int size, bool swap ); - // destroyts the set of solids created by VCollideLoad - virtual void VCollideUnload( vcollide_t *pVCollide ); - - // Trace an AABB against a collide - void TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ); - void TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ); - void TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ); - // Trace one collide against another - void TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ); - bool IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone ); - - // begins parsing a vcollide. NOTE: This keeps pointers to the text - // If you delete the text and call members of IVPhysicsKeyParser, it will crash - virtual IVPhysicsKeyParser *VPhysicsKeyParserCreate( const char *pKeyData ); - // Free the parser created by VPhysicsKeyParserCreate - virtual void VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser ); - - // creates a list of verts from a collision mesh - int CreateDebugMesh( const CPhysCollide *pCollisionModel, Vector **outVerts ); - // destroy the list of verts created by CreateDebugMesh - void DestroyDebugMesh( int vertCount, Vector *outVerts ); - // create a queryable version of the collision model - ICollisionQuery *CreateQueryModel( CPhysCollide *pCollide ); - // destroy the queryable version - void DestroyQueryModel( ICollisionQuery *pQuery ); - - virtual IPhysicsCollision *ThreadContextCreate( void ); - virtual void ThreadContextDestroy( IPhysicsCollision *pThreadContex ); - virtual unsigned int ReadStat( int statID ) { return 0; } - virtual void CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter ); - virtual void CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter ); - - virtual int CollideIndex( const CPhysCollide *pCollide ); - virtual Vector CollideGetOrthographicAreas( const CPhysCollide *pCollide ); - virtual void OutputDebugInfo( const CPhysCollide *pCollide ); - virtual CPhysCollide *CreateVirtualMesh(const virtualmeshparams_t ¶ms) { return ::CreateVirtualMesh(params); } - virtual bool GetBBoxCacheSize( int *pCachedSize, int *pCachedCount ); - - virtual bool SupportsVirtualMesh() { return true; } - - virtual CPhysCollide *UnserializeCollide( char *pBuffer, int size, int index ); - virtual void CollideSetOrthographicAreas( CPhysCollide *pCollide, const Vector &areas ); - -private: - void InitBBoxCache(); - bool IsBBoxCache( CPhysCollide *pCollide ); - void AddBBoxCache( CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs ); - CPhysCollideCompactSurface *GetBBoxCache( const Vector &mins, const Vector &maxs ); - CPhysCollideCompactSurface *FastBboxCollide( const CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs ); - -private: - CPhysicsTrace m_traceapi; - CUtlVector m_bboxCache; - byte m_bboxVertMap[8]; -}; - -CPhysicsCollision g_PhysicsCollision; -IPhysicsCollision *physcollision = &g_PhysicsCollision; -EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPhysicsCollision, IPhysicsCollision, VPHYSICS_COLLISION_INTERFACE_VERSION, g_PhysicsCollision ); - - -//----------------------------------------------------------------------------- -// Abstract compact_surface vs. compact_mopp -//----------------------------------------------------------------------------- -#define IVP_COMPACT_SURFACE_ID MAKEID('I','V','P','S') -#define IVP_COMPACT_SURFACE_ID_SWAPPED MAKEID('S','P','V','I') -#define IVP_COMPACT_MOPP_ID MAKEID('M','O','P','P') -#define VPHYSICS_COLLISION_ID MAKEID('V','P','H','Y') -#define VPHYSICS_COLLISION_VERSION 0x0100 -// You can disable all of the havok Mopp collision model building by undefining this symbol -#define ENABLE_IVP_MOPP 0 - -struct ivpcompactledge_t { - DECLARE_BYTESWAP_DATADESC() - - int c_point_offset; // byte offset from 'this' to (ledge) point array - union { - int ledgetree_node_offset; - int client_data; // if indicates a non terminal ledge - }; - - union { - int bf1; - - struct { - uint has_chilren_flag:2; - int is_compact_flag:2; // if false than compact ledge uses points outside this piece of memory - uint dummy:4; - uint size_div_16:24; - }; - }; - - short n_triangles; - short for_future_use; -}; - -// 48 bytes -// Just like a btCompoundShape. -struct ivpcompactsurface_t { - DECLARE_BYTESWAP_DATADESC() - - float mass_center[3]; - float rotation_inertia[3]; - float upper_limit_radius; - - union { - int bf1; // HACK: Allow datamap to take address of this bitfield - - struct { - int max_deviation : 8; - int byte_size : 24; - }; - }; - - int offset_ledgetree_root; - int dummy[3]; // dummy[2] is "IVPS" or 0 -}; - -struct ivpcompactedge_t { - DECLARE_BYTESWAP_DATADESC() - - union { - int bf1; - - struct { - uint start_point_index:16; // point index - int opposite_index:15; // rel to this // maybe extra array, 3 bits more tha> - uint is_virtual:1; - }; - }; -}; - -struct ivpcompactledgenode_t { - DECLARE_BYTESWAP_DATADESC() - - int offset_right_node; // (if != 0 than children - int offset_compact_ledge; // (if != 0, pointer to hull that contains all subelements - float center[3]; // in object_coords - float radius; // size of sphere - unsigned char box_sizes[3]; - unsigned char free_0; - - // Functions - - const ivpcompactledge_t *GetCompactLedge() const { - Assert(this->offset_right_node == 0); - return (ivpcompactledge_t *)((char *)this + this->offset_compact_ledge); - } - - const ivpcompactledgenode_t *GetLeftSon() const { - Assert(this->offset_right_node); - return this + 1; - } - - const ivpcompactledgenode_t *GetRightSon() const { - Assert(this->offset_right_node); - return (ivpcompactledgenode_t *)((char *)this + this->offset_right_node); - } - - bool IsTerminal() const { - return (this->offset_right_node == 0); - } - - const ivpcompactledge_t *GetCompactHull() const { - if (this->offset_compact_ledge) - return (ivpcompactledge_t *)((char *)this + this->offset_compact_ledge); - else - return NULL; - } -}; - - -struct physcollideheader_t -{ - DECLARE_BYTESWAP_DATADESC(); - int size; - int vphysicsID; - short version; - short modelType; - - void Defaults( short inputModelType ) - { - vphysicsID = VPHYSICS_COLLISION_ID; - - version = VPHYSICS_COLLISION_VERSION; - modelType = inputModelType; - } -}; - -struct compactsurfaceheader_t : public physcollideheader_t -{ - DECLARE_BYTESWAP_DATADESC(); - int surfaceSize; - Vector dragAxisAreas; - int axisMapSize; - - void CompactSurface( const IVP_Compact_Surface *pSurface, const Vector &orthoAreas ) - { - Defaults( COLLIDE_POLY ); - surfaceSize = pSurface->byte_size; - dragAxisAreas = orthoAreas; - axisMapSize = 0; // NOTE: not yet supported - } -}; - -BEGIN_BYTESWAP_DATADESC( physcollideheader_t ) - DEFINE_FIELD( vphysicsID, FIELD_INTEGER ), - DEFINE_FIELD( version, FIELD_SHORT), - DEFINE_FIELD( modelType, FIELD_SHORT ), -END_BYTESWAP_DATADESC() - -BEGIN_BYTESWAP_DATADESC_( compactsurfaceheader_t, physcollideheader_t ) - DEFINE_FIELD( surfaceSize, FIELD_INTEGER ), - DEFINE_FIELD( dragAxisAreas, FIELD_VECTOR ), - DEFINE_FIELD( axisMapSize, FIELD_INTEGER ), -END_BYTESWAP_DATADESC() - -#if ENABLE_IVP_MOPP -struct moppheader_t : public physcollideheader_t -{ - int moppSize; - void Mopp( const IVP_Compact_Mopp *pMopp ) - { - Defaults( COLLIDE_MOPP ); - moppSize = pMopp->byte_size; - } -}; -#endif - -#if ENABLE_IVP_MOPP -class CPhysCollideMopp : public CPhysCollide -{ -public: - CPhysCollideMopp( const moppheader_t *pHeader ); - CPhysCollideMopp( IVP_Compact_Mopp *pMopp ); - CPhysCollideMopp( const char *pBuffer, unsigned int size ); - ~CPhysCollideMopp(); - - void Init( const char *pBuffer, unsigned int size ); - - // IPhysCollide - virtual int GetVCollideIndex() const { return 0; } - virtual IVP_SurfaceManager *CreateSurfaceManager( short & ) const; - virtual void GetAllLedges( IVP_U_BigVector &ledges ) const; - virtual unsigned int GetSerializationSize() const; - virtual Vector GetMassCenter() const; - virtual void SetMassCenter( const Vector &massCenter ); - virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const; - virtual void OutputDebugInfo() const; - -private: - IVP_Compact_Mopp *m_pMopp; -}; -#endif - -class CPhysCollideCompactSurface : public CPhysCollide -{ -public: - ~CPhysCollideCompactSurface(); - CPhysCollideCompactSurface( const char *pBuffer, unsigned int size, int index, bool swap = false ); - CPhysCollideCompactSurface( const compactsurfaceheader_t *pHeader, int index, bool swap = false ); - CPhysCollideCompactSurface( IVP_Compact_Surface *pSurface ); - - void Init( const char *pBuffer, unsigned int size, int index, bool swap = false ); - - // IPhysCollide - virtual int GetVCollideIndex() const { return m_pCompactSurface->dummy[0]; } - virtual IVP_SurfaceManager *CreateSurfaceManager( short & ) const; - virtual void GetAllLedges( IVP_U_BigVector &ledges ) const; - virtual unsigned int GetSerializationSize() const; - virtual Vector GetMassCenter() const; - virtual void SetMassCenter( const Vector &massCenter ); - virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const; - virtual Vector GetOrthographicAreas() const; - void SetOrthographicAreas( const Vector &areas ); - virtual void ComputeOrthographicAreas( float epsilon ); - virtual void OutputDebugInfo() const; - - const IVP_Compact_Surface *GetCompactSurface() const { return m_pCompactSurface; } - virtual const collidemap_t *GetCollideMap() const { return m_pCollideMap; } - -private: - - struct hullinfo_t - { - hullinfo_t() - { - hasOuterHull = false; - convexCount = 0; - } - bool hasOuterHull; - int convexCount; - }; - - void ComputeHullInfo_r( hullinfo_t *pOut, const IVP_Compact_Ledgetree_Node *node ) const; - void InitCollideMap(); - - IVP_Compact_Surface *m_pCompactSurface; - Vector m_orthoAreas; - collidemap_t *m_pCollideMap; -}; - - -static const IVP_Compact_Surface *ConvertPhysCollideToCompactSurface( const CPhysCollide *pCollide ) -{ - return pCollide->GetCompactSurface(); -} - -IVP_SurfaceManager *CreateSurfaceManager( const CPhysCollide *pCollisionModel, short &collideType ) -{ - return pCollisionModel ? pCollisionModel->CreateSurfaceManager( collideType ) : NULL; -} - -void OutputCollideDebugInfo( const CPhysCollide *pCollisionModel ) -{ - pCollisionModel->OutputDebugInfo(); -} - - -CPhysCollide *CPhysCollide::UnserializeFromBuffer( const char *pBuffer, unsigned int size, int index, bool swap ) -{ - const physcollideheader_t *pHeader = reinterpret_cast(pBuffer); - if ( pHeader->vphysicsID == VPHYSICS_COLLISION_ID ) - { - Assert(pHeader->version == VPHYSICS_COLLISION_VERSION); - switch( pHeader->modelType ) - { - case COLLIDE_POLY: - return new CPhysCollideCompactSurface( (compactsurfaceheader_t *)pHeader, index, swap ); - case COLLIDE_MOPP: -#if ENABLE_IVP_MOPP - return new CPhysCollideMopp( (moppheader_t *)pHeader ); -#else - DevMsg( 2, "Null physics model\n"); - return NULL; -#endif - default: - Assert(0); - return NULL; - } - } - const IVP_Compact_Surface *pSurface = reinterpret_cast(pBuffer); - if ( pSurface->dummy[2] == IVP_COMPACT_MOPP_ID ) - { -#if ENABLE_IVP_MOPP - return new CPhysCollideMopp( pBuffer, size ); -#else - Assert(0); - return NULL; -#endif - } - if ( pSurface->dummy[2] == IVP_COMPACT_SURFACE_ID || - pSurface->dummy[2] == IVP_COMPACT_SURFACE_ID_SWAPPED || - pSurface->dummy[2] == 0 ) - { - if ( pSurface->dummy[2] == 0 ) - { - // UNDONE: Print a name here? - DevMsg( 1, "Old format .PHY file loaded!!!\n" ); - } - return new CPhysCollideCompactSurface( pBuffer, size, index, swap ); - } - - Assert(0); - return NULL; -} - -#if ENABLE_IVP_MOPP - -void CPhysCollideMopp::Init( const char *pBuffer, unsigned int size ) -{ - m_pMopp = (IVP_Compact_Mopp *)ivp_malloc_aligned( size, 32 ); - memcpy( m_pMopp, pBuffer, size ); -} - -CPhysCollideMopp::CPhysCollideMopp( const char *pBuffer, unsigned int size ) -{ - Init( pBuffer, size ); -} - -CPhysCollideMopp::CPhysCollideMopp( const moppheader_t *pHeader ) -{ - Init( (const char *)(pHeader+1), pHeader->moppSize ); -} - -CPhysCollideMopp::CPhysCollideMopp( IVP_Compact_Mopp *pMopp ) -{ - m_pMopp = pMopp; - pMopp->dummy = IVP_COMPACT_MOPP_ID; -} - -CPhysCollideMopp::~CPhysCollideMopp() -{ - ivp_free_aligned(m_pMopp); -} - -void CPhysCollideMopp::GetAllLedges( IVP_U_BigVector &ledges ) const -{ - IVP_Compact_Ledge_Solver::get_all_ledges( m_pMopp, &ledges ); -} - -IVP_SurfaceManager *CPhysCollideMopp::CreateSurfaceManager( short &collideType ) const -{ - collideType = COLLIDE_MOPP; - return new IVP_SurfaceManager_Mopp( m_pMopp ); -} - -unsigned int CPhysCollideMopp::GetSerializationSize() const -{ - return m_pMopp->byte_size + sizeof(moppheader_t); -} - -unsigned int CPhysCollideMopp::SerializeToBuffer( char *pDest, bool bSwap ) const -{ - moppheader_t header; - header.Mopp( m_pMopp ); - memcpy( pDest, &header, sizeof(header) ); - pDest += sizeof(header); - memcpy( pDest, m_pMopp, m_pMopp->byte_size ); - return GetSerializationSize(); -} - -Vector CPhysCollideMopp::GetMassCenter() const -{ - Vector massCenterHL; - ConvertPositionToHL( m_pMopp->mass_center, massCenterHL ); - return massCenterHL; -} - -void CPhysCollideMopp::SetMassCenter( const Vector &massCenterHL ) -{ - ConvertPositionToIVP( massCenterHL, m_pMopp->mass_center ); -} - -void CPhysCollideMopp::OutputDebugInfo() const -{ - Msg("CollisionModel: MOPP\n"); -} -#endif - -void CPhysCollideCompactSurface::InitCollideMap() -{ - m_pCollideMap = NULL; - if ( m_pCompactSurface ) - { - IVP_U_BigVector ledges; - GetAllLedges( ledges ); - // don't make these for really large models because there's a linear search involved in using this atm. - if ( !ledges.len() || ledges.len() > 32 ) - return; - int allocSize = sizeof(collidemap_t) + ((ledges.len()-1) * sizeof(leafmap_t)); - m_pCollideMap = (collidemap_t *)malloc(allocSize); - m_pCollideMap->leafCount = ledges.len(); - for ( int i = 0; i < ledges.len(); i++ ) - { - InitLeafmap( ledges.element_at(i), &m_pCollideMap->leafmap[i] ); - } - } -} - -void CPhysCollideCompactSurface::Init( const char *pBuffer, unsigned int size, int index, bool bSwap ) -{ - m_pCompactSurface = (IVP_Compact_Surface *)ivp_malloc_aligned( size, 32 ); - memcpy( m_pCompactSurface, pBuffer, size ); - if ( bSwap ) - { - m_pCompactSurface->byte_swap_all(); - } - m_pCompactSurface->dummy[0] = index; - m_orthoAreas.Init(1,1,1); - InitCollideMap(); -} - -CPhysCollideCompactSurface::CPhysCollideCompactSurface( const char *pBuffer, unsigned int size, int index, bool swap ) -{ - Init( pBuffer, size, index, swap ); -} -CPhysCollideCompactSurface::CPhysCollideCompactSurface( const compactsurfaceheader_t *pHeader, int index, bool swap ) -{ - Init( (const char *)(pHeader+1), pHeader->surfaceSize, index, swap ); - m_orthoAreas = pHeader->dragAxisAreas; -} - -CPhysCollideCompactSurface::CPhysCollideCompactSurface( IVP_Compact_Surface *pSurface ) -{ - m_pCompactSurface = pSurface; - pSurface->dummy[2] = IVP_COMPACT_SURFACE_ID; - m_pCompactSurface->dummy[0] = 0; - m_orthoAreas.Init(1,1,1); - InitCollideMap(); -} - -CPhysCollideCompactSurface::~CPhysCollideCompactSurface() -{ - ivp_free_aligned(m_pCompactSurface); - if ( m_pCollideMap ) - { - free(m_pCollideMap); - } -} - -IVP_SurfaceManager *CPhysCollideCompactSurface::CreateSurfaceManager( short &collideType ) const -{ - collideType = COLLIDE_POLY; - return new IVP_SurfaceManager_Polygon( m_pCompactSurface ); -} - -void CPhysCollideCompactSurface::GetAllLedges( IVP_U_BigVector &ledges ) const -{ - IVP_Compact_Ledge_Solver::get_all_ledges( m_pCompactSurface, &ledges ); -} - -unsigned int CPhysCollideCompactSurface::GetSerializationSize() const -{ - return m_pCompactSurface->byte_size + sizeof(compactsurfaceheader_t); -} - -unsigned int CPhysCollideCompactSurface::SerializeToBuffer( char *pDest, bool bSwap ) const -{ - compactsurfaceheader_t header; - header.CompactSurface( m_pCompactSurface, m_orthoAreas ); - if ( bSwap ) - { - CByteswap swap; - swap.ActivateByteSwapping( true ); - swap.SwapFieldsToTargetEndian( &header ); - } - memcpy( pDest, &header, sizeof(header) ); - pDest += sizeof(header); - int surfaceSize = m_pCompactSurface->byte_size; - int serializationSize = GetSerializationSize(); - if ( bSwap ) - { - m_pCompactSurface->byte_swap_all(); - } - memcpy( pDest, m_pCompactSurface, surfaceSize ); - return serializationSize; -} - -Vector CPhysCollideCompactSurface::GetMassCenter() const -{ - Vector massCenterHL; - ConvertPositionToHL( m_pCompactSurface->mass_center, massCenterHL ); - return massCenterHL; -} - -void CPhysCollideCompactSurface::SetMassCenter( const Vector &massCenterHL ) -{ - ConvertPositionToIVP( massCenterHL, m_pCompactSurface->mass_center ); -} - -Vector CPhysCollideCompactSurface::GetOrthographicAreas() const -{ - return m_orthoAreas; -} - -void CPhysCollideCompactSurface::SetOrthographicAreas( const Vector &areas ) -{ - m_orthoAreas = areas; -} - - -void CPhysCollideCompactSurface::ComputeOrthographicAreas( float epsilon ) -{ - Vector mins, maxs, areas; - - physcollision->CollideGetAABB( &mins, &maxs, this, vec3_origin, vec3_angle ); - float side = sqrt( epsilon ); - if ( side < 1e-4f ) - side = 1e-4f; - Vector size = maxs-mins; - - m_orthoAreas.Init(1,1,1); - trace_t tr; - for ( int axis = 0; axis < 3; axis++ ) - { - int u = (axis+1)%3; - int v = (axis+2)%3; - int hits = 0; - int total = 0; - float halfSide = side * 0.5; - for ( float u0 = mins[u] + halfSide; u0 < maxs[u]; u0 += side ) - { - for ( float v0 = mins[v] + halfSide; v0 < maxs[v]; v0 += side ) - { - Vector start, end; - start[axis] = mins[axis]-1; - end[axis] = maxs[axis]+1; - start[u] = u0; - end[u] = u0; - start[v] = v0; - end[v] = v0; - - physcollision->TraceBox( start, end, vec3_origin, vec3_origin, this, vec3_origin, vec3_angle, &tr ); - if ( tr.DidHit() ) - { - hits++; - } - total++; - } - } - - if ( total <= 0 ) - total = 1; - m_orthoAreas[axis] = (float)hits / (float)total; - } -} - - -void CPhysCollideCompactSurface::ComputeHullInfo_r( hullinfo_t *pOut, const IVP_Compact_Ledgetree_Node *node ) const -{ - if ( !node->is_terminal() ) - { - if ( node->get_compact_hull() ) - pOut->hasOuterHull = true; - - ComputeHullInfo_r( pOut, node->left_son() ); - ComputeHullInfo_r( pOut, node->right_son() ); - } - else - { - // terminal node, add one ledge - pOut->convexCount++; - } -} - - -void CPhysCollideCompactSurface::OutputDebugInfo() const -{ - hullinfo_t info; - - ComputeHullInfo_r( &info, m_pCompactSurface->get_compact_ledge_tree_root() ); - const char *pOuterHull = info.hasOuterHull ? "with" : "no"; - Msg("CollisionModel: Compact Surface: %d convex pieces %s outer hull\n", info.convexCount, pOuterHull ); -} - -//----------------------------------------------------------------------------- - - -//----------------------------------------------------------------------------- -// Purpose: Create a convex element from a point cloud -// Input : **pVerts - array of points -// vertCount - length of array -// Output : opaque pointer to convex element -//----------------------------------------------------------------------------- -CPhysConvex *CPhysicsCollision::ConvexFromVertsFast( Vector **pVerts, int vertCount ) -{ - IVP_U_Vector points; - int i; - - for ( i = 0; i < vertCount; i++ ) - { - IVP_U_Point *tmp = new IVP_U_Point; - - ConvertPositionToIVP( *pVerts[i], *tmp ); - - BEGIN_IVP_ALLOCATION(); - points.add( tmp ); - END_IVP_ALLOCATION(); - } - - BEGIN_IVP_ALLOCATION(); - IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge( &points ); - END_IVP_ALLOCATION(); - - for ( i = 0; i < points.len(); i++ ) - { - delete points.element_at(i); - } - points.clear(); - - return reinterpret_cast(pLedge); -} - -CPhysConvex *CPhysicsCollision::RebuildConvexFromPlanes( CPhysConvex *pConvex, float mergeTolerance ) -{ - if ( !pConvex ) - return NULL; - - IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex; - int triangleCount = pLedge->get_n_triangles(); - - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - IVP_U_Hesse plane; - IVP_Halfspacesoup halfspaces; - - for ( int j = 0; j < triangleCount; j++ ) - { - const IVP_Compact_Edge *pEdge = pTri->get_edge( 0 ); - const IVP_U_Float_Point *p0 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge, pLedge); - const IVP_U_Float_Point *p2 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge->get_next(), pLedge); - const IVP_U_Float_Point *p1 = IVP_Compact_Ledge_Solver::give_object_coords(pEdge->get_prev(), pLedge); - plane.calc_hesse(p0, p2, p1); - float testLen = plane.real_length(); - // if the triangle is less than 1mm on each side then skip it - if ( testLen > 1e-6f ) - { - plane.normize(); - halfspaces.add_halfspace( &plane ); - } - - pTri = pTri->get_next_tri(); - } - - IVP_Compact_Ledge *pLedgeOut = IVP_SurfaceBuilder_Halfspacesoup::convert_halfspacesoup_to_compact_ledge( &halfspaces, mergeTolerance ); - return reinterpret_cast( pLedgeOut ); -} - -CPhysConvex *CPhysicsCollision::ConvexFromVerts( Vector **pVerts, int vertCount ) -{ - CPhysConvex *pConvex = ConvexFromVertsFast( pVerts, vertCount ); - CPhysConvex *pReturn = RebuildConvexFromPlanes( pConvex, 0.01f ); // remove interior coplanar verts! - if ( pReturn ) - { - ConvexFree( pConvex ); - return pReturn; - } - return pConvex; -} - -// produce a convex element from planes (csg of planes) -CPhysConvex *CPhysicsCollision::ConvexFromPlanes( float *pPlanes, int planeCount, float mergeDistance ) -{ - // NOTE: We're passing in planes with outward-facing normals - // Ipion expects inward facing ones; we'll need to reverse plane directon - struct listplane_t - { - float normal[3]; - float dist; - }; - - listplane_t *pList = (listplane_t *)pPlanes; - IVP_U_Hesse plane; - IVP_Halfspacesoup halfspaces; - - mergeDistance = ConvertDistanceToIVP( mergeDistance ); - - for ( int i = 0; i < planeCount; i++ ) - { - Vector tmp( -pList[i].normal[0], -pList[i].normal[1], -pList[i].normal[2] ); - ConvertPlaneToIVP( tmp, -pList[i].dist, plane ); - halfspaces.add_halfspace( &plane ); - } - - IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Halfspacesoup::convert_halfspacesoup_to_compact_ledge( &halfspaces, mergeDistance ); - return reinterpret_cast( pLedge ); -} - - - -CPhysConvex *CPhysicsCollision::ConvexFromConvexPolyhedron( const CPolyhedron &ConvexPolyhedron ) -{ - IVP_Template_Polygon polyTemplate(ConvexPolyhedron.iVertexCount, ConvexPolyhedron.iLineCount, ConvexPolyhedron.iPolygonCount ); - - //convert/copy coordinates - for( int i = 0; i != ConvexPolyhedron.iVertexCount; ++i ) - ConvertPositionToIVP( ConvexPolyhedron.pVertices[i], polyTemplate.points[i] ); - - //copy lines - for( int i = 0; i != ConvexPolyhedron.iLineCount; ++i ) - polyTemplate.lines[i].set( ConvexPolyhedron.pLines[i].iPointIndices[0], ConvexPolyhedron.pLines[i].iPointIndices[1] ); - - //copy polygons - for( int i = 0; i != ConvexPolyhedron.iPolygonCount; ++i ) - { - polyTemplate.surfaces[i].init_surface( ConvexPolyhedron.pPolygons[i].iIndexCount ); //num vertices in a convex polygon == num lines - polyTemplate.surfaces[i].templ_poly = &polyTemplate; - - ConvertPositionToIVP( ConvexPolyhedron.pPolygons[i].polyNormal, polyTemplate.surfaces[i].normal ); - - Polyhedron_IndexedLineReference_t *pLineReferences = &ConvexPolyhedron.pIndices[ConvexPolyhedron.pPolygons[i].iFirstIndex]; - for( int j = 0; j != ConvexPolyhedron.pPolygons[i].iIndexCount; ++j ) - { - polyTemplate.surfaces[i].lines[j] = pLineReferences[j].iLineIndex; - polyTemplate.surfaces[i].revert_line[j] = pLineReferences[j].iEndPointIndex; - } - } - - //final conversion - IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Polygon_Convex::convert_template_to_ledge(&polyTemplate); - - //cleanup - for( int i = 0; i != ConvexPolyhedron.iPolygonCount; ++i ) - polyTemplate.surfaces[i].close_surface(); - - return reinterpret_cast(pLedge); -} - - - - - -struct PolyhedronMesh_Triangle -{ - struct - { - int iPointIndices[2]; - } Edges[3]; -}; - - - -//TODO: Optimize the returned polyhedron to get away from the triangulated mesh -CPolyhedron *CPhysicsCollision::PolyhedronFromConvex( CPhysConvex * const pConvex, bool bUseTempPolyhedron ) -{ - IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex; - int iTriangles = pLedge->get_n_triangles(); - - PolyhedronMesh_Triangle *pTriangles = (PolyhedronMesh_Triangle *)stackalloc( iTriangles * sizeof( PolyhedronMesh_Triangle ) ); - - int iHighestPointIndex = 0; - const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - for( int i = 0; i != iTriangles; ++i ) - { - //reverse point ordering while creating edges - pTriangles[i].Edges[2].iPointIndices[1] = pTriangles[i].Edges[0].iPointIndices[0] = pTri->get_edge( 2 )->get_start_point_index(); - pTriangles[i].Edges[0].iPointIndices[1] = pTriangles[i].Edges[1].iPointIndices[0] = pTri->get_edge( 1 )->get_start_point_index(); - pTriangles[i].Edges[1].iPointIndices[1] = pTriangles[i].Edges[2].iPointIndices[0] = pTri->get_edge( 0 )->get_start_point_index(); - - for( int j = 0; j != 3; ++j ) - { - //get_n_points() has a whole bunch of ifdefs that apparently disable it in this case, detect number of points - if( pTriangles[i].Edges[j].iPointIndices[0] > iHighestPointIndex ) - iHighestPointIndex = pTriangles[i].Edges[j].iPointIndices[0]; - } - - pTri = pTri->get_next_tri(); - } - - ++iHighestPointIndex; - - //apparently points might be shared between ledges and not all points will be used. So now we get to compress them into a smaller set - int *pPointRemapping = (int *)stackalloc( iHighestPointIndex * sizeof( int ) ); - memset( pPointRemapping, 0, iHighestPointIndex * sizeof( int ) ); - for( int i = 0; i != iTriangles; ++i ) - { - for( int j = 0; j != 3; ++j ) - ++(pPointRemapping[pTriangles[i].Edges[j].iPointIndices[0]]); - } - - int iInsertIndex = 0; - - for( int i = 0; i != iHighestPointIndex; ++i ) - { - if( pPointRemapping[i] ) - { - pPointRemapping[i] = iInsertIndex; - ++iInsertIndex; - } - else - { - pPointRemapping[i] = -1; - } - } - - const int iNumPoints = iInsertIndex; - - for( int i = 0; i != iTriangles; ++i ) - { - for( int j = 0; j != 3; ++j ) - { - for( int k = 0; k != 2; ++k ) - pTriangles[i].Edges[j].iPointIndices[k] = pPointRemapping[pTriangles[i].Edges[j].iPointIndices[k]]; - } - } - - - bool *bLinks = (bool *)stackalloc( iNumPoints * iNumPoints * sizeof( bool ) ); - memset( bLinks, 0, iNumPoints * iNumPoints * sizeof( bool ) ); - - int iLinkCount = 0; - for( int i = 0; i != iTriangles; ++i ) - { - for( int j = 0; j != 3; ++j ) - { - const int *pIndices = pTriangles[i].Edges[j].iPointIndices; - int iLow = ((pIndices[0] > pIndices[1])?1:(0)); - ++iLinkCount; //this will technically make the link count double the actual number - bLinks[(pIndices[iLow] * iNumPoints) + pIndices[1-iLow]] = true; - } - } - - iLinkCount /= 2; //cut the link count in half since we overcounted - - CPolyhedron *pReturn; - if( bUseTempPolyhedron ) - pReturn = GetTempPolyhedron( iNumPoints, iLinkCount, iLinkCount * 2, iTriangles ); - else - pReturn = CPolyhedron_AllocByNew::Allocate( iNumPoints, iLinkCount, iLinkCount * 2, iTriangles ); - - //copy/convert vertices - const IVP_Compact_Poly_Point *pLedgePoints = pLedge->get_point_array(); - Vector *pWriteVertices = pReturn->pVertices; - for( int i = 0; i != iHighestPointIndex; ++i ) - { - if( pPointRemapping[i] != -1 ) - ConvertPositionToHL( pLedgePoints[i], pWriteVertices[pPointRemapping[i]] ); - } - - - //convert lines - iInsertIndex = 0; - for( int i = 0; i != iNumPoints; ++i ) - { - for( int j = i + 1; j != iNumPoints; ++j ) - { - if( bLinks[(i * iNumPoints) + j] ) - { - pReturn->pLines[iInsertIndex].iPointIndices[0] = i; - pReturn->pLines[iInsertIndex].iPointIndices[1] = j; - ++iInsertIndex; - } - } - } - - - int *pStartIndices = (int *)stackalloc( iNumPoints * sizeof( int ) ); //for quicker lookup of which edges to use in polygons - - pStartIndices[0] = 0; //the lowest index point drives links, so if the first point isn't the first link, then something is extremely messed up - Assert( pReturn->pLines[0].iPointIndices[0] == 0 ); - iInsertIndex = 1; - for( int i = 1; i != iNumPoints; ++i ) - { - for( int j = iInsertIndex; j != iLinkCount; ++j ) - { - if( pReturn->pLines[j].iPointIndices[0] == i ) - { - pStartIndices[i] = j; - iInsertIndex = j + 1; - break; - } - } - } - - //convert polygons and setup line references as a subtask - iInsertIndex = 0; - for( int i = 0; i != iTriangles; ++i ) - { - pReturn->pPolygons[i].iFirstIndex = iInsertIndex; - pReturn->pPolygons[i].iIndexCount = 3; - - Vector *p1, *p2, *p3; - p1 = &pReturn->pVertices[pTriangles[i].Edges[0].iPointIndices[0]]; - p2 = &pReturn->pVertices[pTriangles[i].Edges[1].iPointIndices[0]]; - p3 = &pReturn->pVertices[pTriangles[i].Edges[2].iPointIndices[0]]; - - Vector v1to2, v1to3; - - v1to2 = *p2 - *p1; - v1to3 = *p3 - *p1; - - pReturn->pPolygons[i].polyNormal = v1to3.Cross( v1to2 ); - pReturn->pPolygons[i].polyNormal.NormalizeInPlace(); - - for( int j = 0; j != 3; ++j, ++iInsertIndex ) - { - const int *pIndices = pTriangles[i].Edges[j].iPointIndices; - int iLow = (pIndices[0] > pIndices[1])?1:0; - int iLineIndex; - for( iLineIndex = pStartIndices[pIndices[iLow]]; iLineIndex != iLinkCount; ++iLineIndex ) - { - if( (pReturn->pLines[iLineIndex].iPointIndices[0] == pIndices[iLow]) && - (pReturn->pLines[iLineIndex].iPointIndices[1] == pIndices[1 - iLow]) ) - { - break; - } - } - - pReturn->pIndices[iInsertIndex].iLineIndex = iLineIndex; - pReturn->pIndices[iInsertIndex].iEndPointIndex = 1 - iLow; - } - } - - return pReturn; -} - - -int CPhysicsCollision::GetConvexesUsedInCollideable( const CPhysCollide *pCollideable, CPhysConvex **pOutputArray, int iOutputArrayLimit ) -{ - IVP_U_BigVector ledges; - pCollideable->GetAllLedges( ledges ); - - int iLedgeCount = ledges.len(); - if( iLedgeCount > iOutputArrayLimit ) - iLedgeCount = iOutputArrayLimit; - - for( int i = 0; i != iLedgeCount; ++i ) - { - IVP_Compact_Ledge *pLedge = ledges.element_at(i); //doing as a 2 step since a single convert seems more error prone (without compile error) in this case - pOutputArray[i] = (CPhysConvex *)pLedge; - } - - return iLedgeCount; -} - -void CPhysicsCollision::ConvexesFromConvexPolygon( const Vector &vPolyNormal, const Vector *pPoints, int iPointCount, CPhysConvex **pOutput ) -{ - IVP_U_Point *pIVP_Points = (IVP_U_Point *)stackalloc( sizeof( IVP_U_Point ) * iPointCount ); - IVP_U_Point **pTriangulator = (IVP_U_Point **)stackalloc( sizeof( IVP_U_Point * ) * iPointCount ); - IVP_U_Point **pRead = pTriangulator; - IVP_U_Point **pWrite = pTriangulator; - - //convert coordinates - { - for( int i = 0; i != iPointCount; ++i ) - ConvertPositionToIVP( pPoints[i], pIVP_Points[i] ); - } - - int iOutputCount = 0; - - //chunk this out like a triangle strip - int iForwardCounter = 1; - int iReverseCounter = iPointCount - 1; //guaranteed to be >= 2 to start - - *pWrite = &pIVP_Points[0]; - ++pWrite; - *pWrite = &pIVP_Points[iReverseCounter]; - ++pWrite; - --iReverseCounter; - - do - { - //forward - *pWrite = &pIVP_Points[iForwardCounter]; - ++iForwardCounter; - - pOutput[iOutputCount] = reinterpret_cast(IVP_SurfaceBuilder_Pointsoup::convert_triangle_to_compace_ledge( pRead[0], pRead[1], pRead[2] )); - Assert( pOutput[iOutputCount] ); - ++iOutputCount; - if( iForwardCounter > iReverseCounter ) - break; - - ++pRead; - ++pWrite; - - - - //backward - *pWrite = &pIVP_Points[iReverseCounter]; - --iReverseCounter; - - pOutput[iOutputCount] = reinterpret_cast(IVP_SurfaceBuilder_Pointsoup::convert_triangle_to_compace_ledge( pRead[0], pRead[1], pRead[2] )); - Assert( pOutput[iOutputCount] ); - ++iOutputCount; - - if( iForwardCounter > iReverseCounter ) - break; - - ++pRead; - ++pWrite; - } while( true ); -} - - -//----------------------------------------------------------------------------- -// Purpose: copies the first vert int pLedge to out -// Input : *pLedge - compact ledge -// *out - destination float array for the vert -//----------------------------------------------------------------------------- -static void LedgeInsidePoint( IVP_Compact_Ledge *pLedge, Vector& out ) -{ - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - const IVP_Compact_Edge *pEdge = pTri->get_edge( 0 ); - const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge ); - ConvertPositionToHL( *pPoint, out ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Calculate the volume of a tetrahedron with these vertices -// Input : p0 - points of tetrahedron -// p1 - -// p2 - -// p3 - -// Output : float (volume in units^3) -//----------------------------------------------------------------------------- -static float TetrahedronVolume( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3 ) -{ - Vector a, b, c, cross; - float volume = 1.0f / 6.0f; - - a = p1 - p0; - b = p2 - p0; - c = p3 - p0; - cross = CrossProduct( b, c ); - - volume *= DotProduct( a, cross ); - if ( volume < 0 ) - return -volume; - return volume; -} - - -static float TriangleArea( const Vector &p0, const Vector &p1, const Vector &p2 ) -{ - Vector e0 = p1 - p0; - Vector e1 = p2 - p0; - Vector cross; - - CrossProduct( e0, e1, cross ); - return 0.5 * cross.Length(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Tetrahedronalize this ledge and compute it's volume in BSP space -// Input : convex - the ledge -// Output : float - volume in HL units (in^3) -//----------------------------------------------------------------------------- -float CPhysicsCollision::ConvexVolume( CPhysConvex *pConvex ) -{ - IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex; - int triangleCount = pLedge->get_n_triangles(); - - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - - Vector vert; - float volume = 0; - // vert is in HL units - LedgeInsidePoint( pLedge, vert ); - - for ( int j = 0; j < triangleCount; j++ ) - { - Vector points[3]; - for ( int k = 0; k < 3; k++ ) - { - const IVP_Compact_Edge *pEdge = pTri->get_edge( k ); - const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge ); - ConvertPositionToHL( *pPoint, points[k] ); - } - volume += TetrahedronVolume( vert, points[0], points[1], points[2] ); - - pTri = pTri->get_next_tri(); - } - - return volume; -} - - -float CPhysicsCollision::ConvexSurfaceArea( CPhysConvex *pConvex ) -{ - IVP_Compact_Ledge *pLedge = (IVP_Compact_Ledge *)pConvex; - int triangleCount = pLedge->get_n_triangles(); - - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - - float area = 0; - - for ( int j = 0; j < triangleCount; j++ ) - { - Vector points[3]; - for ( int k = 0; k < 3; k++ ) - { - const IVP_Compact_Edge *pEdge = pTri->get_edge( k ); - const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge ); - ConvertPositionToHL( *pPoint, points[k] ); - } - area += TriangleArea( points[0], points[1], points[2] ); - - pTri = pTri->get_next_tri(); - } - - return area; -} - -// Convert an array of convex elements to a compiled collision model (this deletes the convex elements) -CPhysCollide *CPhysicsCollision::ConvertConvexToCollide( CPhysConvex **pConvex, int convexCount ) -{ - convertconvexparams_t convertParams; - convertParams.Defaults(); - return ConvertConvexToCollideParams( pConvex, convexCount, convertParams ); -} - -CPhysCollide *CPhysicsCollision::ConvertConvexToCollideParams( CPhysConvex **pConvex, int convexCount, const convertconvexparams_t &convertParams ) -{ - if ( !convexCount || !pConvex ) - return NULL; - - int validConvex = 0; - BEGIN_IVP_ALLOCATION(); - IVP_SurfaceBuilder_Ledge_Soup builder; - IVP_Compact_Surface *pSurface = NULL; - - for ( int i = 0; i < convexCount; i++ ) - { - if ( pConvex[i] ) - { - validConvex++; - builder.insert_ledge( (IVP_Compact_Ledge *)pConvex[i] ); - } - } - // if the outside code does something stupid, don't crash - if ( validConvex ) - { - IVP_Template_Surbuild_LedgeSoup params; - params.force_convex_hull = (IVP_Compact_Ledge *)convertParams.pForcedOuterHull; - params.build_root_convex_hull = convertParams.buildOuterConvexHull ? IVP_TRUE : IVP_FALSE; - - // NOTE: THIS FREES THE LEDGES in pConvex!!! - pSurface = builder.compile( ¶ms ); - CPhysCollide *pCollide = new CPhysCollideCompactSurface( pSurface ); - if ( convertParams.buildDragAxisAreas ) - { - pCollide->ComputeOrthographicAreas( convertParams.dragAreaEpsilon ); - } - - END_IVP_ALLOCATION(); - return pCollide; - } - - END_IVP_ALLOCATION(); - - return NULL; -} - -static void InitBoxVerts( Vector *boxVerts, Vector **ppVerts, const Vector &mins, const Vector &maxs ) -{ - for (int i = 0; i < 8; ++i) - { - boxVerts[i][0] = (i & 0x1) ? maxs[0] : mins[0]; - boxVerts[i][1] = (i & 0x2) ? maxs[1] : mins[1]; - boxVerts[i][2] = (i & 0x4) ? maxs[2] : mins[2]; - if ( ppVerts ) - { - ppVerts[i] = &boxVerts[i]; - } - } -} - - -#define FAST_BBOX 1 -CPhysCollideCompactSurface *CPhysicsCollision::FastBboxCollide( const CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs ) -{ - Vector boxVerts[8]; - InitBoxVerts( boxVerts, NULL, mins, maxs ); - // copy the compact ledge at bboxCache 0 - // stuff the verts in there - const IVP_Compact_Surface *pSurface = ConvertPhysCollideToCompactSurface( pCollide ); - Assert( pSurface ); - const IVP_Compact_Ledgetree_Node *node = pSurface->get_compact_ledge_tree_root(); - Assert( node->is_terminal() == IVP_TRUE ); - const IVP_Compact_Ledge *pLedge = node->get_compact_ledge(); - int ledgeSize = pLedge->get_size(); - IVP_Compact_Ledge *pNewLedge = (IVP_Compact_Ledge *)ivp_malloc_aligned( ledgeSize, 16 ); - memcpy( pNewLedge, pLedge, ledgeSize ); - pNewLedge->set_client_data(0); - IVP_Compact_Poly_Point *pPoints = pNewLedge->get_point_array(); - for ( int i = 0; i < 8; i++ ) - { - IVP_U_Float_Hesse ivp; - ConvertPositionToIVP( boxVerts[m_bboxVertMap[i]], ivp ); - ivp.hesse_val = 0; - pPoints[i].set4(&ivp); - } - CPhysConvex *pConvex = (CPhysConvex *)pNewLedge; - return (CPhysCollideCompactSurface *)ConvertConvexToCollide( &pConvex, 1 ); -} - -void CPhysicsCollision::InitBBoxCache() -{ - Vector boxVerts[8], *ppVerts[8]; - Vector mins(-16,-16,0), maxs(16,16,72); - // init with the player box - InitBoxVerts( boxVerts, ppVerts, mins, maxs ); - // Generate a convex hull from the verts - CPhysConvex *pConvex = ConvexFromVertsFast( ppVerts, 8 ); - IVP_Compact_Poly_Point *pPoints = reinterpret_cast(pConvex)->get_point_array(); - for ( int i = 0; i < 8; i++ ) - { - int nearest = -1; - float minDist = 0.1; - Vector tmp; - ConvertPositionToHL( pPoints[i], tmp ); - for ( int j = 0; j < 8; j++ ) - { - float dist = (boxVerts[j] - tmp).Length(); - if ( dist < minDist ) - { - minDist = dist; - nearest = j; - } - } - - m_bboxVertMap[i] = nearest; - -#if _DEBUG - for ( int k = 0; k < i; k++ ) - { - Assert( m_bboxVertMap[k] != m_bboxVertMap[i] ); - } -#endif - // NOTE: If this is wrong, you can disable FAST_BBOX above to fix - AssertMsg( nearest != -1, "CPhysCollide: Vert map is wrong\n" ); - } - CPhysCollide *pCollide = ConvertConvexToCollide( &pConvex, 1 ); - AddBBoxCache( (CPhysCollideCompactSurface *)pCollide, mins, maxs ); -} - - -CPhysConvex *CPhysicsCollision::BBoxToConvex( const Vector &mins, const Vector &maxs ) -{ - Vector boxVerts[8], *ppVerts[8]; - InitBoxVerts( boxVerts, ppVerts, mins, maxs ); - // Generate a convex hull from the verts - return ConvexFromVertsFast( ppVerts, 8 ); -} - -CPhysCollide *CPhysicsCollision::BBoxToCollide( const Vector &mins, const Vector &maxs ) -{ - // can't create a collision model for an empty box ! - if ( mins == maxs ) - { - Assert(0); - return NULL; - } - - // find this bbox in the cache - CPhysCollide *pCollide = GetBBoxCache( mins, maxs ); - if ( pCollide ) - return pCollide; - - // FAST_BBOX: uses an existing compact ledge as a template for fast generation - // building convex hulls from points is slow -#if FAST_BBOX - if ( m_bboxCache.Count() == 0 ) - { - InitBBoxCache(); - } - pCollide = FastBboxCollide( m_bboxCache[0].pCollide, mins, maxs ); -#else - CPhysConvex *pConvex = BBoxToConvex( mins, maxs ); - pCollide = ConvertConvexToCollide( &pConvex, 1 ); -#endif - AddBBoxCache( (CPhysCollideCompactSurface *)pCollide, mins, maxs ); - return pCollide; -} - -bool CPhysicsCollision::IsBBoxCache( CPhysCollide *pCollide ) -{ - // UNDONE: Sort the list so it can be searched spatially instead of linearly? - for ( int i = m_bboxCache.Count()-1; i >= 0; i-- ) - { - if ( m_bboxCache[i].pCollide == pCollide ) - return true; - } - return false; -} - -void CPhysicsCollision::AddBBoxCache( CPhysCollideCompactSurface *pCollide, const Vector &mins, const Vector &maxs ) -{ - int index = m_bboxCache.AddToTail(); - bboxcache_t *pCache = &m_bboxCache[index]; - pCache->pCollide = pCollide; - pCache->mins = mins; - pCache->maxs = maxs; -} - -CPhysCollideCompactSurface *CPhysicsCollision::GetBBoxCache( const Vector &mins, const Vector &maxs ) -{ - for ( int i = m_bboxCache.Count()-1; i >= 0; i-- ) - { - if ( m_bboxCache[i].mins == mins && m_bboxCache[i].maxs == maxs ) - return m_bboxCache[i].pCollide; - } - return NULL; -} - - -void CPhysicsCollision::ConvexFree( CPhysConvex *pConvex ) -{ - if ( !pConvex ) - return; - ivp_free_aligned( pConvex ); -} - -// Get the size of the collision model for serialization -int CPhysicsCollision::CollideSize( CPhysCollide *pCollide ) -{ - return pCollide->GetSerializationSize(); -} - -int CPhysicsCollision::CollideWrite( char *pDest, CPhysCollide *pCollide, bool bSwap ) -{ - return pCollide->SerializeToBuffer( pDest, bSwap ); -} - -CPhysCollide *CPhysicsCollision::UnserializeCollide( char *pBuffer, int size, int index ) -{ - return CPhysCollide::UnserializeFromBuffer( pBuffer, size, index ); -} - -class CPhysPolysoup -{ -public: - CPhysPolysoup(); -#if ENABLE_IVP_MOPP - IVP_SurfaceBuilder_Mopp m_builder; -#endif - IVP_SurfaceBuilder_Ledge_Soup m_builderSoup; - IVP_U_Vector m_points; - IVP_U_Point m_triangle[3]; - - bool m_isValid; -}; - -CPhysPolysoup::CPhysPolysoup() -{ - m_isValid = false; - m_points.add( &m_triangle[0] ); - m_points.add( &m_triangle[1] ); - m_points.add( &m_triangle[2] ); -} - -CPhysPolysoup *CPhysicsCollision::PolysoupCreate( void ) -{ - return new CPhysPolysoup; -} - -void CPhysicsCollision::PolysoupDestroy( CPhysPolysoup *pSoup ) -{ - delete pSoup; -} - -void CPhysicsCollision::PolysoupAddTriangle( CPhysPolysoup *pSoup, const Vector &a, const Vector &b, const Vector &c, int materialIndex7bits ) -{ - pSoup->m_isValid = true; - ConvertPositionToIVP( a, pSoup->m_triangle[0] ); - ConvertPositionToIVP( b, pSoup->m_triangle[1] ); - ConvertPositionToIVP( c, pSoup->m_triangle[2] ); - IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge(&pSoup->m_points); - if ( !pLedge ) - { - Warning("Degenerate Triangle\n"); - Warning("(%.2f, %.2f, %.2f), ", a.x, a.y, a.z ); - Warning("(%.2f, %.2f, %.2f), ", b.x, b.y, b.z ); - Warning("(%.2f, %.2f, %.2f)\n", c.x, c.y, c.z ); - return; - } - IVP_Compact_Triangle *pTriangle = pLedge->get_first_triangle(); - pTriangle->set_material_index( materialIndex7bits ); -#if ENABLE_IVP_MOPP - pSoup->m_builder.insert_ledge(pLedge); -#endif - pSoup->m_builderSoup.insert_ledge(pLedge); -} - -CPhysCollide *CPhysicsCollision::ConvertPolysoupToCollide( CPhysPolysoup *pSoup, bool useMOPP ) -{ - if ( !pSoup->m_isValid ) - return NULL; - - CPhysCollide *pCollide = NULL; -#if ENABLE_IVP_MOPP - if ( useMOPP ) - { - IVP_Compact_Mopp *pSurface = pSoup->m_builder.compile(); - pCollide = new CPhysCollideMopp( pSurface ); - } - else -#endif - { - IVP_Compact_Surface *pSurface = pSoup->m_builderSoup.compile(); - pCollide = new CPhysCollideCompactSurface( pSurface ); - } - - Assert(pCollide); - - // There's a bug in IVP where the duplicated triangles (for 2D) - // don't get the materials set properly, so copy them - IVP_U_BigVector ledges; - pCollide->GetAllLedges( ledges ); - - for ( int i = 0; i < ledges.len(); i++ ) - { - IVP_Compact_Ledge *pLedge = ledges.element_at( i ); - int triangleCount = pLedge->get_n_triangles(); - - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - int materialIndex = pTri->get_material_index(); - if ( !materialIndex ) - { - for ( int j = 0; j < triangleCount; j++ ) - { - if ( pTri->get_material_index() != 0 ) - { - materialIndex = pTri->get_material_index(); - } - pTri = pTri->get_next_tri(); - } - } - for ( int j = 0; j < triangleCount; j++ ) - { - pTri->set_material_index( materialIndex ); - pTri = pTri->get_next_tri(); - } - } - - return pCollide; -} - -int CPhysicsCollision::CreateDebugMesh( const CPhysCollide *pCollisionModel, Vector **outVerts ) -{ - int i; - - IVP_U_BigVector ledges; - pCollisionModel->GetAllLedges( ledges ); - - int vertCount = 0; - - for ( i = 0; i < ledges.len(); i++ ) - { - IVP_Compact_Ledge *pLedge = ledges.element_at( i ); - vertCount += pLedge->get_n_triangles() * 3; - } - Vector *verts = new Vector[ vertCount ]; - - int vertIndex = 0; - for ( i = 0; i < ledges.len(); i++ ) - { - IVP_Compact_Ledge *pLedge = ledges.element_at( i ); - int triangleCount = pLedge->get_n_triangles(); - - IVP_Compact_Triangle *pTri = pLedge->get_first_triangle(); - for ( int j = 0; j < triangleCount; j++ ) - { - for ( int k = 2; k >= 0; k-- ) - { - const IVP_Compact_Edge *pEdge = pTri->get_edge( k ); - const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge ); - - Vector* pVec = verts + vertIndex; - ConvertPositionToHL( *pPoint, *pVec ); - vertIndex++; - } - pTri = pTri->get_next_tri(); - } - } - - *outVerts = verts; - return vertCount; -} - - -void CPhysicsCollision::DestroyDebugMesh( int vertCount, Vector *outVerts ) -{ - delete[] outVerts; -} - - -void CPhysicsCollision::SetConvexGameData( CPhysConvex *pConvex, unsigned int gameData ) -{ - IVP_Compact_Ledge *pLedge = reinterpret_cast( pConvex ); - pLedge->set_client_data( gameData ); -} - - -void CPhysicsCollision::TraceBox( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) -{ - m_traceapi.SweepBoxIVP( start, end, mins, maxs, pCollide, collideOrigin, collideAngles, ptr ); -} - -void CPhysicsCollision::TraceBox( const Ray_t &ray, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) -{ - TraceBox( ray, MASK_ALL, NULL, pCollide, collideOrigin, collideAngles, ptr ); -} - -void CPhysicsCollision::TraceBox( const Ray_t &ray, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) -{ - m_traceapi.SweepBoxIVP( ray, contentsMask, pConvexInfo, pCollide, collideOrigin, collideAngles, ptr ); -} - -// Trace one collide against another -void CPhysicsCollision::TraceCollide( const Vector &start, const Vector &end, const CPhysCollide *pSweepCollide, const QAngle &sweepAngles, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, trace_t *ptr ) -{ - m_traceapi.SweepIVP( start, end, pSweepCollide, sweepAngles, pCollide, collideOrigin, collideAngles, ptr ); -} - -void CPhysicsCollision::CollideGetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles ) -{ - m_traceapi.GetAABB( pMins, pMaxs, pCollide, collideOrigin, collideAngles ); -} - - -Vector CPhysicsCollision::CollideGetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction ) -{ - if ( !pCollide ) - return collideOrigin; - - return m_traceapi.GetExtent( pCollide, collideOrigin, collideAngles, direction ); -} - -bool CPhysicsCollision::IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone ) -{ - return m_traceapi.IsBoxIntersectingCone( boxAbsMins, boxAbsMaxs, cone ); -} - -// Free a collide that was created with ConvertConvexToCollide() -void CPhysicsCollision::DestroyCollide( CPhysCollide *pCollide ) -{ - if ( !IsBBoxCache( pCollide ) ) - { - delete pCollide; - } -} - -// calculate the volume of a collide by calling ConvexVolume on its parts -float CPhysicsCollision::CollideVolume( CPhysCollide *pCollide ) -{ - IVP_U_BigVector ledges; - pCollide->GetAllLedges( ledges ); - - float volume = 0; - for ( int i = 0; i < ledges.len(); i++ ) - { - volume += ConvexVolume( (CPhysConvex *)ledges.element_at(i) ); - } - - return volume; -} - -// calculate the volume of a collide by calling ConvexVolume on its parts -float CPhysicsCollision::CollideSurfaceArea( CPhysCollide *pCollide ) -{ - IVP_U_BigVector ledges; - pCollide->GetAllLedges( ledges ); - - float area = 0; - for ( int i = 0; i < ledges.len(); i++ ) - { - area += ConvexSurfaceArea( (CPhysConvex *)ledges.element_at(i) ); - } - - return area; -} - -static void GetAllIVPSLedges(const ivpcompactledgenode_t *node, CUtlVector *vecOut) -{ - if (!node || !vecOut) return; - - if (node->IsTerminal()) { - vecOut->AddToTail(node->GetCompactLedge()); - } else { - const ivpcompactledgenode_t *rs = node->GetRightSon(); - const ivpcompactledgenode_t *ls = node->GetLeftSon(); - GetAllIVPSLedges(rs, vecOut); - GetAllIVPSLedges(ls, vecOut); - } -} - -static CPhysCollide *LoadIVPS(void *pSolid, bool swap) { - // Parse IVP Surface header (which is right after the compact surface header) - //const compactsurfaceheader_t *compactSurface = (compactsurfaceheader_t *)((char *)pSolid + sizeof(collideheader_t)); - const ivpcompactsurface_t *ivpsurface = (ivpcompactsurface_t *)((char *)pSolid + sizeof(physcollideheader_t) + sizeof(compactsurfaceheader_t)); - -// if (ivpsurface->dummy[2] != IVP_COMPACT_SURFACE_ID) { -// return NULL; -// } - - // Add all of the ledges up - CUtlVector ledges; - GetAllIVPSLedges((const ivpcompactledgenode_t *)((char *)ivpsurface + ivpsurface->offset_ledgetree_root), &ledges); - -// btCompoundShape *pCompound = NULL; - -// if (ledges.Count() == 1) -// pCompound = new btCompoundShape(false); // Pointless for an AABB tree if it's just one convex -// else -// pCompound = new btCompoundShape(); - -// CPhysCollide *pCollide = new CPhysCollide; - -// btVector3 massCenter; -// ConvertIVPPosToBull(ivpsurface->mass_center, massCenter); -// pCollide->SetMassCenter(massCenter); - - // No conversion necessary (IVP in meters and we don't need to flip any axes) -// pCollide->SetRotationInertia(btVector3(ivpsurface->rotation_inertia[0], ivpsurface->rotation_inertia[1], ivpsurface->rotation_inertia[2])); - -// pCompound->setMargin(COLLISION_MARGIN); - - printf("ledges = %d\n", ledges.Count()); - -/* - for (int i = 0; i < ledges.Count(); i++) { - const ivpcompactledge_t *ledge = ledges[i]; - - btTransform offsetTrans(btMatrix3x3::getIdentity(), -pCollide->GetMassCenter()); - pCompound->addChildShape(offsetTrans, LedgeToConvex(ledge)); - }*/ - - return NULL; -} - -// loads a set of solids into a vcollide_t -void CPhysicsCollision::VCollideLoad( vcollide_t *pOutput, int solidCount, const char *pBuffer, int bufferSize, bool swap ) -{ - memset( pOutput, 0, sizeof(*pOutput) ); - - // TODO: This - // In practice, this is never true on a Windows PC (and most likely not a linux dedicated server either) - if (swap) { - Warning("VCollideLoad - Abort loading, swap is true\n"); - Assert(0); - return; - } - - Msg("\nCPhysicsCollision::VCollideLoad %d\n", solidCount); - - pOutput->solidCount = solidCount; - pOutput->solids = new CPhysCollide *[solidCount]; - - int position = 0; - for (int i = 0; i < solidCount; i++) { - // Size of this solid, excluding the size int itself - int size = *(int *)(pBuffer + position); - - pOutput->solids[i] = (CPhysCollide *)(pBuffer + position); - position += size + 4; - - // May fail if we're reading a corrupted file. - Assert(position < bufferSize && position >= 0); - } - - Assert(bufferSize - position > 0); - - // The rest of the buffer is the key values for the collision mesh - pOutput->pKeyValues = new char[bufferSize - position]; - memcpy(pOutput->pKeyValues, pBuffer + position, bufferSize - position); - - // swap argument means byte swap - we must byte swap all of the collision shapes before loading them if true! - // DevMsg("VPhysics: VCollideLoad with %d solids, swap is %s\n", solidCount, swap ? "true" : "false"); - - // Now for the fun part: - // We must convert all of the ivp shapes into something we can use. - for (int i = 0; i < solidCount; i++) { - const physcollideheader_t &surfaceheader = *(physcollideheader_t *)pOutput->solids[i]; - - if (surfaceheader.vphysicsID != VPHYSICS_COLLISION_ID - || surfaceheader.version != 0x100) { - pOutput->solids[i] = NULL; - Warning("VCollideLoad: Skipped solid %d due to invalid id/version (magic: %d version: %d)\n", i+1, surfaceheader.vphysicsID, surfaceheader.version); - continue; - } - - CPhysCollide *pShape = NULL; - - // NOTE: modelType 0 is IVPS, 1 is (mostly unused) MOPP format - if (surfaceheader.modelType == 0x0) { - pShape = LoadIVPS(pOutput->solids[i], swap); - } else if (surfalceheader.modelType == 0x1) { - // One big use of mopps is in old map displacement data - // The use is terribly unoptimized (each triangle is its own convex shape) - //pShape = LoadMOPP(pOutput->solids[i], swap); - - // If we leave this as NULL, the game will use CreateVirtualMesh instead. - } else { - Warning("VCollideLoad: Unknown modelType %d (solid %d). Skipped!\n", surfaceheader.modelType, i+1); - } - - pOutput->solids[i] = pShape; - } -} - -// destroys the set of solids created by VCollideCreateCPhysCollide -void CPhysicsCollision::VCollideUnload( vcollide_t *pVCollide ) -{ - for ( int i = 0; i < pVCollide->solidCount; i++ ) - { -#if _DEBUG - // HACKHACK: 1024 is just "some big number" - // GetActiveEnvironmentByIndex() will eventually return NULL when there are no more environments. - // In HL2 & TF2, there are only 2 environments - so j > 1 is probably an error! - for ( int j = 0; j < 1024; j++ ) - { - IPhysicsEnvironment *pEnv = g_PhysicsInternal->GetActiveEnvironmentByIndex( j ); - if ( !pEnv ) - break; - - if ( pEnv->IsCollisionModelUsed( (CPhysCollide *)pVCollide->solids[i] ) ) - { - AssertMsg(0, "Freed collision model while in use!!!\n"); - return; - } - } -#endif - delete pVCollide->solids[i]; - } - delete[] pVCollide->solids; - delete[] pVCollide->pKeyValues; - memset( pVCollide, 0, sizeof(*pVCollide) ); -} - -// begins parsing a vcollide. NOTE: This keeps pointers to the vcollide_t -// If you delete the vcollide_t and call members of IVCollideParse, it will crash -IVPhysicsKeyParser *CPhysicsCollision::VPhysicsKeyParserCreate( const char *pKeyData ) -{ - return CreateVPhysicsKeyParser( pKeyData ); -} - -// Free the parser created by VPhysicsKeyParserCreate -void CPhysicsCollision::VPhysicsKeyParserDestroy( IVPhysicsKeyParser *pParser ) -{ - DestroyVPhysicsKeyParser( pParser ); -} - -IPhysicsCollision *CPhysicsCollision::ThreadContextCreate( void ) -{ - return this; -} - -void CPhysicsCollision::ThreadContextDestroy( IPhysicsCollision *pThreadContext ) -{ -} - - -void CPhysicsCollision::CollideGetMassCenter( CPhysCollide *pCollide, Vector *pOutMassCenter ) -{ - *pOutMassCenter = pCollide->GetMassCenter(); -} - -void CPhysicsCollision::CollideSetMassCenter( CPhysCollide *pCollide, const Vector &massCenter ) -{ - pCollide->SetMassCenter( massCenter ); -} - -int CPhysicsCollision::CollideIndex( const CPhysCollide *pCollide ) -{ - if ( !pCollide ) - return 0; - return pCollide->GetVCollideIndex(); -} - -Vector CPhysicsCollision::CollideGetOrthographicAreas( const CPhysCollide *pCollide ) -{ - if ( !pCollide ) - return vec3_origin; - return pCollide->GetOrthographicAreas(); -} - -void CPhysicsCollision::CollideSetOrthographicAreas( CPhysCollide *pCollide, const Vector &areas ) -{ - if ( pCollide ) - pCollide->SetOrthographicAreas( areas ); -} - -// returns true if this collide has an outer hull built -void CPhysicsCollision::OutputDebugInfo( const CPhysCollide *pCollide ) -{ - pCollide->OutputDebugInfo(); -} - -bool CPhysicsCollision::GetBBoxCacheSize( int *pCachedSize, int *pCachedCount ) -{ - *pCachedSize = 0; - *pCachedCount = m_bboxCache.Count(); - for ( int i = 0; i < *pCachedCount; i++ ) - { - *pCachedSize += m_bboxCache[i].pCollide->GetSerializationSize(); - } - return true; -} - -class CCollisionQuery : public ICollisionQuery -{ -public: - CCollisionQuery( CPhysCollide *pCollide ); - ~CCollisionQuery( void ) {} - - // number of convex pieces in the whole solid - virtual int ConvexCount( void ); - // triangle count for this convex piece - virtual int TriangleCount( int convexIndex ); - - // get the stored game data - virtual unsigned int GetGameData( int convexIndex ); - - // Gets the triangle's verts to an array - virtual void GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts ); - - // UNDONE: This doesn't work!!! - virtual void SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts ); - - // returns the 7-bit material index - virtual int GetTriangleMaterialIndex( int convexIndex, int triangleIndex ); - // sets a 7-bit material index for this triangle - virtual void SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits ); - -private: - IVP_Compact_Triangle *Triangle( IVP_Compact_Ledge *pLedge, int triangleIndex ); - - IVP_U_BigVector m_ledges; -}; - - -// create a queryable version of the collision model -ICollisionQuery *CPhysicsCollision::CreateQueryModel( CPhysCollide *pCollide ) -{ - return new CCollisionQuery( pCollide ); -} - - // destroy the queryable version -void CPhysicsCollision::DestroyQueryModel( ICollisionQuery *pQuery ) -{ - delete pQuery; -} - - -CCollisionQuery::CCollisionQuery( CPhysCollide *pCollide ) -{ - pCollide->GetAllLedges( m_ledges ); -} - - - // number of convex pieces in the whole solid -int CCollisionQuery::ConvexCount( void ) -{ - return m_ledges.len(); -} - - // triangle count for this convex piece -int CCollisionQuery::TriangleCount( int convexIndex ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at(convexIndex); - if ( pLedge ) - { - return pLedge->get_n_triangles(); - } - - return 0; -} - - -unsigned int CCollisionQuery::GetGameData( int convexIndex ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex ); - if ( pLedge ) - return pLedge->get_client_data(); - return 0; -} - - // Gets the triangle's verts to an array -void CCollisionQuery::GetTriangleVerts( int convexIndex, int triangleIndex, Vector *verts ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex ); - IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex ); - - int vertIndex = 0; - for ( int k = 2; k >= 0; k-- ) - { - const IVP_Compact_Edge *pEdge = pTriangle->get_edge( k ); - const IVP_U_Float_Point *pPoint = pEdge->get_start_point( pLedge ); - - Vector* pVec = verts + vertIndex; - ConvertPositionToHL( *pPoint, *pVec ); - vertIndex++; - } -} - -// UNDONE: This doesn't work!!! -void CCollisionQuery::SetTriangleVerts( int convexIndex, int triangleIndex, const Vector *verts ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex ); - Triangle( pLedge, triangleIndex ); -} - - -int CCollisionQuery::GetTriangleMaterialIndex( int convexIndex, int triangleIndex ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex ); - IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex ); - - return pTriangle->get_material_index(); -} - -void CCollisionQuery::SetTriangleMaterialIndex( int convexIndex, int triangleIndex, int index7bits ) -{ - IVP_Compact_Ledge *pLedge = m_ledges.element_at( convexIndex ); - IVP_Compact_Triangle *pTriangle = Triangle( pLedge, triangleIndex ); - - pTriangle->set_material_index( index7bits ); -} - -IVP_Compact_Triangle *CCollisionQuery::Triangle( IVP_Compact_Ledge *pLedge, int triangleIndex ) -{ - if ( !pLedge ) - return NULL; - - return pLedge->get_first_triangle() + triangleIndex; -} - - -#if 0 -void TestCubeVolume( void ) -{ - float volume = 0; - Vector verts[8]; - typedef struct - { - int a, b, c; - } triangle_t; - - triangle_t triangles[12] = - { - {0,1,3}, // front 0123 - {0,3,2}, - {4,5,1}, // top 4501 - {4,1,0}, - {2,3,7}, // bottom 2367 - {2,7,6}, - {1,5,7}, // right 1537 - {1,7,3}, - {4,0,2}, // left 4062 - {4,2,6}, - {5,4,6}, // back 5476 - {5,6,7} - }; - - int i = 0; - for ( int x = -1; x <= 1; x +=2 ) - for ( int y = -1; y <= 1; y +=2 ) - for ( int z = -1; z <= 1; z +=2 ) - { - verts[i][0] = x; - verts[i][1] = y; - verts[i][2] = z; - i++; - } - - - for ( i = 0; i < 12; i++ ) - { - triangle_t *pTri = triangles + i; - volume += TetrahedronVolume( verts[0], verts[pTri->a], verts[pTri->b], verts[pTri->c] ); - } - // should report a volume of 8. This is a cube that is 2 on a side - printf("Test volume %.4f\n", volume ); -} -#endif - - diff --git a/vphysics-physx/physics_object.cpp.save b/vphysics-physx/physics_object.cpp.save deleted file mode 100644 index 4d1f3b948..000000000 --- a/vphysics-physx/physics_object.cpp.save +++ /dev/null @@ -1,2011 +0,0 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// -#include "cbase.h" -#include "ivp_surman_polygon.hxx" -#include "ivp_compact_ledge.hxx" -#include "ivp_compact_ledge_solver.hxx" -#include "ivp_mindist.hxx" -#include "ivp_mindist_intern.hxx" -#include "ivp_friction.hxx" -#include "ivp_phantom.hxx" -#include "ivp_listener_collision.hxx" -#include "ivp_clustering_visualizer.hxx" -#include "ivp_anomaly_manager.hxx" -#include "ivp_collision_filter.hxx" - -#include "hk_mopp/ivp_surman_mopp.hxx" -#include "hk_mopp/ivp_compact_mopp.hxx" - -#include "ivp_compact_surface.hxx" -#include "physics_trace.h" -#include "physics_shadow.h" -#include "physics_friction.h" -#include "physics_constraint.h" -#include "bspflags.h" -#include "vphysics/player_controller.h" -#include "vphysics/friction.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -extern IPhysicsCollision *physcollision; - -// UNDONE: Make this a stack variable / member variable of some save/load object or function? -// NOTE: This keeps a list of objects who were saved while asleep, but not created asleep -// So some info will be lost unless it's regenerated after loading. -struct postrestore_objectlist_t -{ - CPhysicsObject *pObject; - bool growFriction; - bool enableCollisions; - - void Defaults() - { - pObject = NULL; - growFriction = false; - enableCollisions = false; - } -}; - -static CUtlVector g_PostRestoreObjectList; - -// This angular basis is the integral of each differential drag area's torque over the whole OBB -// For each axis, each face, the integral is (1/Iaxis) * (1/3 * w^2l^3 + 1/2 * w^4l + lw^2h^2) -// l,w, & h are half widths - where l is in the direction of the axis, w is in the plane (l/w plane) of the face, -// and h is perpendicular to the face. So for each axis, you sum up this integral over 2 pairs of faces -// (this function returns the integral for one pair of opposite faces, not one face) -static float AngDragIntegral( float invInertia, float l, float w, float h ) -{ - float w2 = w*w; - float l2 = l*l; - float h2 = h*h; - - return invInertia * ( (1.f/3.f)*w2*l*l2 + 0.5 * w2*w2*l + l*w2*h2 ); -} - - -CPhysicsObject::CPhysicsObject( void ) -{ -#ifdef _WIN32 - void *pData = ((char *)this) + sizeof(void *); // offset beyond vtable - int dataSize = sizeof(*this) - sizeof(void *); - - Assert( pData == &m_pGameData ); - - memset( pData, 0, dataSize ); -#elif POSIX - - //!!HACK HACK - rework this if we ever change compiler versions (from gcc 3.2!!!) - void *pData = ((char *)this) + sizeof(void *); // offset beyond vtable - int dataSize = sizeof(*this) - sizeof(void *); - - Assert( pData == &m_pGameData ); - - memset( pData, 0, dataSize ); -#else -#error -#endif - - // HACKHACK: init this as a sphere until someone attaches a surfacemanager - m_collideType = COLLIDE_BALL; - m_contentsMask = CONTENTS_SOLID; - m_hasTouchedDynamic = 0; -} - -void CPhysicsObject::Init( const CPhysCollide *pCollisionModel, IVP_Real_Object *pObject, int materialIndex, float volume, float drag, float angDrag ) -{ - m_pCollide = pCollisionModel; - m_materialIndex = materialIndex; - m_pObject = pObject; - pObject->client_data = (void *)this; - m_pGameData = NULL; - m_gameFlags = 0; - m_gameIndex = 0; - m_sleepState = OBJ_SLEEP; // objects start asleep - m_callbacks = CALLBACK_GLOBAL_COLLISION|CALLBACK_GLOBAL_FRICTION|CALLBACK_FLUID_TOUCH|CALLBACK_GLOBAL_TOUCH|CALLBACK_GLOBAL_COLLIDE_STATIC|CALLBACK_DO_FLUID_SIMULATION; - m_activeIndex = 0xFFFF; - m_pShadow = NULL; - m_shadowTempGravityDisable = false; - m_forceSilentDelete = false; - m_dragBasis = vec3_origin; - m_angDragBasis = vec3_origin; - - if ( !IsStatic() && GetCollide() ) - { - RecomputeDragBases(); - } - else - { - drag = 0; - angDrag = 0; - } - - m_dragCoefficient = drag; - m_angDragCoefficient = angDrag; - - SetVolume( volume ); -} - -CPhysicsObject::~CPhysicsObject( void ) -{ - RemoveShadowController(); - - if ( m_pObject ) - { - // prevents callbacks to the game code / unlink from this object - m_callbacks = 0; - m_pGameData = 0; - m_pObject->client_data = 0; - - IVP_Core *pCore = m_pObject->get_core(); - if ( pCore->physical_unmoveable == IVP_TRUE && pCore->controllers_of_core.n_elems ) - { - // go ahead and notify them if this happens in the real world - for(int i = pCore->controllers_of_core.len()-1; i >=0 ;i-- ) - { - IVP_Controller *my_controller = pCore->controllers_of_core.element_at(i); - my_controller->core_is_going_to_be_deleted_event(pCore); - Assert(my_controller==pCore->environment->get_gravity_controller()); - } - } - - // UNDONE: Don't free the surface manager here - // UNDONE: Remove reference to it by calling something in physics_collide - IVP_SurfaceManager *pSurman = GetSurfaceManager(); - CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment(); - - // BUGBUG: Sometimes IVP will call a "revive" on the object we're deleting! - MEM_ALLOC_CREDIT(); - if ( m_forceSilentDelete || (pVEnv && pVEnv->ShouldQuickDelete()) || !m_hasTouchedDynamic ) - { - m_pObject->delete_silently(); - } - else - { - m_pObject->delete_and_check_vicinity(); - } - delete pSurman; - } -} - -void CPhysicsObject::Wake( void ) -{ - m_pObject->ensure_in_simulation(); -} - -void CPhysicsObject::WakeNow( void ) -{ - m_pObject->ensure_in_simulation_now(); -} - -// supported -void CPhysicsObject::Sleep( void ) -{ - m_pObject->disable_simulation(); -} - - -bool CPhysicsObject::IsAsleep() const -{ - if ( m_sleepState == OBJ_AWAKE ) - return false; - - // double-check that we aren't pending - if ( m_pObject->get_core()->is_in_wakeup_vec ) - return false; - - return true; -} - -void CPhysicsObject::NotifySleep( void ) -{ - if ( m_sleepState == OBJ_AWAKE ) - { - m_sleepState = OBJ_STARTSLEEP; - } - else - { - // UNDONE: This fails sometimes and we get sleep calls for a sleeping object, debug? - //Assert(m_sleepState==OBJ_STARTSLEEP); - m_sleepState = OBJ_SLEEP; - } -} - - -void CPhysicsObject::NotifyWake( void ) -{ - m_asleepSinceCreation = false; - m_sleepState = OBJ_AWAKE; -} - - -void CPhysicsObject::SetCallbackFlags( unsigned short callbackflags ) -{ -#if IVP_ENABLE_VISUALIZER - unsigned short changedFlags = m_callbacks ^ callbackflags; - if ( changedFlags & CALLBACK_MARKED_FOR_TEST ) - { - if ( callbackflags & CALLBACK_MARKED_FOR_TEST ) - { - ENABLE_SHORTRANGE_VISUALIZATION(m_pObject); - ENABLE_LONGRANGE_VISUALIZATION(m_pObject); - } - else - { - DISABLE_SHORTRANGE_VISUALIZATION(m_pObject); - DISABLE_LONGRANGE_VISUALIZATION(m_pObject); - } - } -#endif - m_callbacks = callbackflags; - -} - - -unsigned short CPhysicsObject::GetCallbackFlags() const -{ - return m_callbacks; -} - - -void CPhysicsObject::SetGameFlags( unsigned short userFlags ) -{ - m_gameFlags = userFlags; -} - -unsigned short CPhysicsObject::GetGameFlags() const -{ - return m_gameFlags; -} - - -void CPhysicsObject::SetGameIndex( unsigned short gameIndex ) -{ - m_gameIndex = gameIndex; -} - -unsigned short CPhysicsObject::GetGameIndex() const -{ - return m_gameIndex; -} - -bool CPhysicsObject::IsStatic() const -{ - if ( m_pObject->get_core()->physical_unmoveable ) - return true; - - return false; -} - - -void CPhysicsObject::EnableCollisions( bool enable ) -{ - if ( enable ) - { - m_callbacks |= CALLBACK_ENABLING_COLLISION; - BEGIN_IVP_ALLOCATION(); - m_pObject->enable_collision_detection( IVP_TRUE ); - END_IVP_ALLOCATION(); - m_callbacks &= ~CALLBACK_ENABLING_COLLISION; - } - else - { - if ( IsCollisionEnabled() ) - { - // Delete all contact points with this physics object because it's collision is becoming disabled - IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot(); - while ( pSnapshot->IsValid() ) - { - pSnapshot->MarkContactForDelete(); - pSnapshot->NextFrictionData(); - } - pSnapshot->DeleteAllMarkedContacts( true ); - DestroyFrictionSnapshot( pSnapshot ); - } - - m_pObject->enable_collision_detection( IVP_FALSE ); - } -} - -void CPhysicsObject::RecheckCollisionFilter() -{ - if ( CallbackFlags() & CALLBACK_MARKED_FOR_DELETE ) - return; - - m_callbacks |= CALLBACK_ENABLING_COLLISION; - BEGIN_IVP_ALLOCATION(); - m_pObject->recheck_collision_filter(); - // UNDONE: do a RecheckContactPoints() here? - END_IVP_ALLOCATION(); - m_callbacks &= ~CALLBACK_ENABLING_COLLISION; -} - -void CPhysicsObject::RecheckContactPoints() -{ - IVP_Environment *pEnv = m_pObject->get_environment(); - IVP_Collision_Filter *coll_filter = pEnv->get_collision_filter(); - IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot(); - while ( pSnapshot->IsValid() ) - { - CPhysicsObject *pOther = static_cast(pSnapshot->GetObject(1)); - if ( !coll_filter->check_objects_for_collision_detection( m_pObject, pOther->m_pObject ) ) - { - pSnapshot->MarkContactForDelete(); - } - pSnapshot->NextFrictionData(); - } - pSnapshot->DeleteAllMarkedContacts( true ); - DestroyFrictionSnapshot( pSnapshot ); -} - -CPhysicsEnvironment *CPhysicsObject::GetVPhysicsEnvironment() -{ - return (CPhysicsEnvironment *) (m_pObject->get_environment()->client_data); -} - -const CPhysicsEnvironment *CPhysicsObject::GetVPhysicsEnvironment() const -{ - return (CPhysicsEnvironment *) (m_pObject->get_environment()->client_data); -} - - -bool CPhysicsObject::IsControlling( const IVP_Controller *pController ) const -{ - IVP_Core *pCore = m_pObject->get_core(); - for ( int i = 0; i < pCore->controllers_of_core.len(); i++ ) - { - // already controlling this core? - if ( pCore->controllers_of_core.element_at(i) == pController ) - return true; - } - - return false; -} - -bool CPhysicsObject::IsGravityEnabled() const -{ - if ( !IsStatic() ) - { - return IsControlling( m_pObject->get_core()->environment->get_gravity_controller() ); - } - - return false; -} - -bool CPhysicsObject::IsDragEnabled() const -{ - if ( !IsStatic() ) - { - return IsControlling( GetVPhysicsEnvironment()->GetDragController() ); - } - - return false; -} - - -bool CPhysicsObject::IsMotionEnabled() const -{ - return m_pObject->get_core()->pinned ? false : true; -} - - -bool CPhysicsObject::IsMoveable() const -{ - if ( IsStatic() || !IsMotionEnabled() ) - return false; - return true; -} - - -void CPhysicsObject::EnableGravity( bool enable ) -{ - if ( IsStatic() ) - return; - - - bool isEnabled = IsGravityEnabled(); - - if ( enable == isEnabled ) - return; - - IVP_Controller *pGravity = m_pObject->get_core()->environment->get_gravity_controller(); - if ( enable ) - { - m_pObject->get_core()->add_core_controller( pGravity ); - } - else - { - m_pObject->get_core()->rem_core_controller( pGravity ); - } -} - -void CPhysicsObject::EnableDrag( bool enable ) -{ - if ( IsStatic() ) - return; - - bool isEnabled = IsDragEnabled(); - - if ( enable == isEnabled ) - return; - - IVP_Controller *pDrag = GetVPhysicsEnvironment()->GetDragController(); - - if ( enable ) - { - m_pObject->get_core()->add_core_controller( pDrag ); - } - else - { - m_pObject->get_core()->rem_core_controller( pDrag ); - } -} - - -void CPhysicsObject::SetDragCoefficient( float *pDrag, float *pAngularDrag ) -{ - if ( pDrag ) - { - m_dragCoefficient = *pDrag; - } - if ( pAngularDrag ) - { - m_angDragCoefficient = *pAngularDrag; - } - - EnableDrag( m_dragCoefficient || m_angDragCoefficient ); -} - - -void CPhysicsObject::RecomputeDragBases() -{ - if ( IsStatic() || !GetCollide() ) - return; - - // Basically we are computing drag as an OBB. Get OBB extents for projection - // scale those extents by appropriate mass/inertia to compute velocity directly (not force) - // in the controller - // NOTE: Compute these even if drag coefficients are zero, because the drag coefficient could change later - - // Get an AABB for this object and use the area of each side as a basis for approximating cross-section area for drag - Vector dragMins, dragMaxs; - // NOTE: coordinates in/out of physcollision are in HL units, not IVP - // PERFORMANCE: Cache this? Expensive. - physcollision->CollideGetAABB( &dragMins, &dragMaxs, GetCollide(), vec3_origin, vec3_angle ); - - Vector areaFractions = physcollision->CollideGetOrthographicAreas( GetCollide() ); - Vector delta = dragMaxs - dragMins; - ConvertPositionToIVP( delta.x, delta.y, delta.z ); - delta.x = fabsf(delta.x); - delta.y = fabsf(delta.y); - delta.z = fabsf(delta.z); - // dragBasis is now the area of each side - m_dragBasis.x = delta.y * delta.z * areaFractions.x; - m_dragBasis.y = delta.x * delta.z * areaFractions.y; - m_dragBasis.z = delta.x * delta.y * areaFractions.z; - m_dragBasis *= GetInvMass(); - - const IVP_U_Float_Point *pInvRI = m_pObject->get_core()->get_inv_rot_inertia(); - - // This angular basis is the integral of each differential drag area's torque over the whole OBB - // need half lengths for this integral - delta *= 0.5; - // rotation about the x axis - m_angDragBasis.x = areaFractions.z * AngDragIntegral( pInvRI->k[0], delta.x, delta.y, delta.z ) + areaFractions.y * AngDragIntegral( pInvRI->k[0], delta.x, delta.z, delta.y ); - // rotation about the y axis - m_angDragBasis.y = areaFractions.z * AngDragIntegral( pInvRI->k[1], delta.y, delta.x, delta.z ) + areaFractions.x * AngDragIntegral( pInvRI->k[1], delta.y, delta.z, delta.x ); - // rotation about the z axis - m_angDragBasis.z = areaFractions.y * AngDragIntegral( pInvRI->k[2], delta.z, delta.x, delta.y ) + areaFractions.x * AngDragIntegral( pInvRI->k[2], delta.z, delta.y, delta.x ); -} - - - -void CPhysicsObject::EnableMotion( bool enable ) -{ - if ( IsStatic() ) - return; - - bool isMoveable = IsMotionEnabled(); - - // no change - if ( isMoveable == enable ) - return; - - BEGIN_IVP_ALLOCATION(); - m_pObject->set_pinned( enable ? IVP_FALSE : IVP_TRUE ); - END_IVP_ALLOCATION(); - - if ( enable && IsHinged() ) - { - BecomeHinged( m_hingedAxis-1 ); - } - RecheckCollisionFilter(); - RecheckContactPoints(); -} - -bool CPhysicsObject::IsControlledByGame() const -{ - if (m_pShadow && !m_pShadow->IsPhysicallyControlled()) - return true; - - if ( CallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER ) - return true; - - return false; -} - -IPhysicsFrictionSnapshot *CPhysicsObject::CreateFrictionSnapshot() -{ - return ::CreateFrictionSnapshot( m_pObject ); -} - -void CPhysicsObject::DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot ) -{ - ::DestroyFrictionSnapshot(pSnapshot); -} - -bool CPhysicsObject::IsMassCenterAtDefault() const -{ - // this is the actual mass center of the object as created - Vector massCenterHL = GetMassCenterLocalSpace(); - - // Get the default mass center to see if it has been changed - IVP_U_Float_Point massCenterIVPDefault; - Vector massCenterHLDefault; - GetObject()->get_surface_manager()->get_mass_center( &massCenterIVPDefault ); - ConvertPositionToHL( massCenterIVPDefault, massCenterHLDefault ); - float delta = (massCenterHLDefault - massCenterHL).Length(); - - return ( delta <= g_PhysicsUnits.collisionSweepIncrementalEpsilon ) ? true : false; -} - -Vector CPhysicsObject::GetMassCenterLocalSpace() const -{ - if ( m_pObject->flags.shift_core_f_object_is_zero ) - return vec3_origin; - - Vector out; - ConvertPositionToHL( *m_pObject->get_shift_core_f_object(), out ); - // core shift is what you add to the mass center to get the origin - // so we want the negative core shift (origin relative position of the mass center) - return -out; -} - - -void CPhysicsObject::SetGameData( void *pGameData ) -{ - m_pGameData = pGameData; -} - -void *CPhysicsObject::GetGameData( void ) const -{ - return m_pGameData; -} - -void CPhysicsObject::SetMass( float mass ) -{ - bool reset = false; - - if ( !IsMoveable() ) - { - reset = true; - EnableMotion(true); - } - - Assert( mass > 0 ); - - mass = clamp( mass, 1.f, VPHYSICS_MAX_MASS ); - m_pObject->change_mass( mass ); - SetVolume( m_volume ); - RecomputeDragBases(); - if ( reset ) - { - EnableMotion(false); - } -} - -float CPhysicsObject::GetMass( void ) const -{ - return m_pObject->get_core()->get_mass(); -} - -float CPhysicsObject::GetInvMass( void ) const -{ - return m_pObject->get_core()->get_inv_mass(); -} - -Vector CPhysicsObject::GetInertia( void ) const -{ - const IVP_U_Float_Point *pRI = m_pObject->get_core()->get_rot_inertia(); - - Vector hlInertia; - ConvertDirectionToHL( *pRI, hlInertia ); - VectorAbs( hlInertia, hlInertia ); - return hlInertia; -} - -Vector CPhysicsObject::GetInvInertia( void ) const -{ - const IVP_U_Float_Point *pRI = m_pObject->get_core()->get_inv_rot_inertia(); - - Vector hlInvInertia; - ConvertDirectionToHL( *pRI, hlInvInertia ); - VectorAbs( hlInvInertia, hlInvInertia ); - return hlInvInertia; -} - - - -void CPhysicsObject::SetInertia( const Vector &inertia ) -{ - IVP_U_Float_Point ri; ConvertDirectionToIVP( inertia, ri ); - ri.k[0] = IVP_Inline_Math::fabsd(ri.k[0]); - ri.k[1] = IVP_Inline_Math::fabsd(ri.k[1]); - ri.k[2] = IVP_Inline_Math::fabsd(ri.k[2]); - - m_pObject->get_core()->set_rotation_inertia( &ri ); -} - - -void CPhysicsObject::GetDamping( float *speed, float *rot ) const -{ - IVP_Core *pCore = m_pObject->get_core(); - if ( speed ) - { - *speed = pCore->speed_damp_factor; - } - if ( rot ) - { - *rot = pCore->rot_speed_damp_factor.k[0]; - } -} - -void CPhysicsObject::SetDamping( const float *speed, const float *rot ) -{ - IVP_Core *pCore = m_pObject->get_core(); - if ( speed ) - { - pCore->speed_damp_factor = *speed; - } - if ( rot ) - { - pCore->rot_speed_damp_factor.set( *rot, *rot, *rot ); - } -} - -void CPhysicsObject::SetVolume( float volume ) -{ - m_volume = volume; - if ( volume != 0.f ) - { - // minimum volume is 5 cubic inches - otherwise buoyancy can get unstable - if ( volume < 5.0f ) - { - volume = 5.0f; - } - volume *= HL2IVP_FACTOR*HL2IVP_FACTOR*HL2IVP_FACTOR; - float density = GetMass() / volume; - float matDensity; - physprops->GetPhysicsProperties( GetMaterialIndexInternal(), &matDensity, NULL, NULL, NULL ); - m_buoyancyRatio = density / matDensity; - } - else - { - m_buoyancyRatio = 1.0f; - } -} - -float CPhysicsObject::GetVolume() const -{ - return m_volume; -} - - -void CPhysicsObject::SetBuoyancyRatio( float ratio ) -{ - m_buoyancyRatio = ratio; -} - -void CPhysicsObject::SetContents( unsigned int contents ) -{ - m_contentsMask = contents; -} - -// converts HL local units to HL world units -void CPhysicsObject::LocalToWorld( Vector *worldPosition, const Vector &localPosition ) const -{ - matrix3x4_t matrix; - GetPositionMatrix( &matrix ); - // copy in case the src == dest - VectorTransform( Vector(localPosition), matrix, *worldPosition ); -} - -// Converts world HL units to HL local/object units -void CPhysicsObject::WorldToLocal( Vector *localPosition, const Vector &worldPosition ) const -{ - matrix3x4_t matrix; - GetPositionMatrix( &matrix ); - // copy in case the src == dest - VectorITransform( Vector(worldPosition), matrix, *localPosition ); -} - -void CPhysicsObject::LocalToWorldVector( Vector *worldVector, const Vector &localVector ) const -{ - matrix3x4_t matrix; - GetPositionMatrix( &matrix ); - // copy in case the src == dest - VectorRotate( Vector(localVector), matrix, *worldVector ); -} - -void CPhysicsObject::WorldToLocalVector( Vector *localVector, const Vector &worldVector ) const -{ - matrix3x4_t matrix; - GetPositionMatrix( &matrix ); - // copy in case the src == dest - VectorIRotate( Vector(worldVector), matrix, *localVector ); -} - - -// Apply force impulse (momentum) to the object -void CPhysicsObject::ApplyForceCenter( const Vector &forceVector ) -{ - if ( !IsMoveable() ) - return; - - IVP_U_Float_Point tmp; - - ConvertForceImpulseToIVP( forceVector, tmp ); - IVP_Core *core = m_pObject->get_core(); - tmp.mult( core->get_inv_mass() ); - m_pObject->async_add_speed_object_ws( &tmp ); - ClampVelocity(); -} - -void CPhysicsObject::ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition ) -{ - if ( !IsMoveable() ) - return; - - IVP_U_Point pos; - IVP_U_Float_Point force; - - ConvertForceImpulseToIVP( forceVector, force ); - ConvertPositionToIVP( worldPosition, pos ); - - IVP_Core *core = m_pObject->get_core(); - core->async_push_core_ws( &pos, &force ); - Wake(); - ClampVelocity(); -} - -void CPhysicsObject::CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) const -{ - IVP_U_Point pos; - IVP_U_Float_Point force; - - ConvertPositionToIVP( forceVector, force ); - ConvertPositionToIVP( worldPosition, pos ); - - IVP_Core *core = m_pObject->get_core(); - - const IVP_U_Matrix *m_world_f_core = core->get_m_world_f_core_PSI(); - - IVP_U_Float_Point point_d_ws; - point_d_ws.subtract(&pos, m_world_f_core->get_position()); - - IVP_U_Float_Point cross_point_dir; - - cross_point_dir.calc_cross_product( &point_d_ws, &force); - m_world_f_core->inline_vimult3( &cross_point_dir, &cross_point_dir); - - ConvertAngularImpulseToHL( cross_point_dir, *centerTorque ); - ConvertForceImpulseToHL( force, *centerForce ); -} - -void CPhysicsObject::CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) const -{ - IVP_U_Point pos; - IVP_U_Float_Point force; - - ConvertForceImpulseToIVP( forceVector, force ); - ConvertPositionToIVP( worldPosition, pos ); - - IVP_Core *core = m_pObject->get_core(); - - const IVP_U_Matrix *m_world_f_core = core->get_m_world_f_core_PSI(); - - IVP_U_Float_Point point_d_ws; - point_d_ws.subtract(&pos, m_world_f_core->get_position()); - - IVP_U_Float_Point cross_point_dir; - - cross_point_dir.calc_cross_product( &point_d_ws, &force); - m_world_f_core->inline_vimult3( &cross_point_dir, &cross_point_dir); - - cross_point_dir.set_pairwise_mult( &cross_point_dir, core->get_inv_rot_inertia()); - ConvertAngularImpulseToHL( cross_point_dir, *centerAngularVelocity ); - force.set_multiple( &force, core->get_inv_mass() ); - ConvertForceImpulseToHL( force, *centerVelocity ); -} - -void CPhysicsObject::ApplyTorqueCenter( const AngularImpulse &torqueImpulse ) -{ - if ( !IsMoveable() ) - return; - IVP_U_Float_Point ivpTorque; - ConvertAngularImpulseToIVP( torqueImpulse, ivpTorque ); - IVP_Core *core = m_pObject->get_core(); - core->async_rot_push_core_multiple_ws( &ivpTorque, 1.0 ); - Wake(); - ClampVelocity(); -} - -void CPhysicsObject::GetPosition( Vector *worldPosition, QAngle *angles ) const -{ - IVP_U_Matrix matrix; - m_pObject->get_m_world_f_object_AT( &matrix ); - if ( worldPosition ) - { - ConvertPositionToHL( matrix.vv, *worldPosition ); - } - - if ( angles ) - { - ConvertRotationToHL( matrix, *angles ); - } -} - - -void CPhysicsObject::GetPositionMatrix( matrix3x4_t *positionMatrix ) const -{ - IVP_U_Matrix matrix; - m_pObject->get_m_world_f_object_AT( &matrix ); - ConvertMatrixToHL( matrix, *positionMatrix ); -} - - -void CPhysicsObject::GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const -{ - if ( !velocity && !angularVelocity ) - return; - - IVP_Core *core = m_pObject->get_core(); - if ( velocity ) - { - // just convert the cached dx - ConvertPositionToHL( core->delta_world_f_core_psis, *velocity ); - } - - if ( angularVelocity ) - { - // compute the relative transform that was actually integrated in the last psi - IVP_U_Quat q_core_f_core; - q_core_f_core.set_invert_mult( &core->q_world_f_core_last_psi, &core->q_world_f_core_next_psi); - - // now convert that to an axis/angle pair - Quaternion q( q_core_f_core.x, q_core_f_core.y, q_core_f_core.z, q_core_f_core.w ); - AngularImpulse axis; - float angle; - QuaternionAxisAngle( q, axis, angle ); - - // scale it by the timestep to get a velocity - angle *= core->i_delta_time; - - // ConvertDirectionToHL() - convert this ipion direction (in HL type) to HL coords - float tmpY = axis.z; - angularVelocity->z = -axis.y; - angularVelocity->y = tmpY; - angularVelocity->x = axis.x; - - // now scale the axis by the angle to return the data in the correct format - (*angularVelocity) *= angle; - } -} - -void CPhysicsObject::GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const -{ - if ( !velocity && !angularVelocity ) - return; - - IVP_Core *core = m_pObject->get_core(); - if ( velocity ) - { - IVP_U_Float_Point speed; - speed.add( &core->speed, &core->speed_change ); - ConvertPositionToHL( speed, *velocity ); - } - - if ( angularVelocity ) - { - IVP_U_Float_Point rotSpeed; - rotSpeed.add( &core->rot_speed, &core->rot_speed_change ); - // xform to HL space - ConvertAngularImpulseToHL( rotSpeed, *angularVelocity ); - } -} - -void CPhysicsObject::GetVelocityAtPoint( const Vector &worldPosition, Vector *pVelocity ) const -{ - IVP_Core *core = m_pObject->get_core(); - IVP_U_Point pos; - ConvertPositionToIVP( worldPosition, pos ); - - IVP_U_Float_Point rotSpeed; - rotSpeed.add( &core->rot_speed, &core->rot_speed_change ); - - IVP_U_Float_Point av_ws; - core->get_m_world_f_core_PSI()->vmult3( &rotSpeed, &av_ws); - - IVP_U_Float_Point pos_rel; - pos_rel.subtract( &pos, core->get_position_PSI()); - IVP_U_Float_Point cross; - cross.inline_calc_cross_product(&av_ws,&pos_rel); - - IVP_U_Float_Point speed; - speed.add(&core->speed, &cross); - speed.add(&core->speed_change); - - ConvertPositionToHL( speed, *pVelocity ); -} - - -// UNDONE: Limit these? -void CPhysicsObject::AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) -{ - Assert(IsMoveable()); - if ( !IsMoveable() ) - return; - IVP_Core *core = m_pObject->get_core(); - - Wake(); - - if ( velocity ) - { - IVP_U_Float_Point ivpVelocity; - ConvertPositionToIVP( *velocity, ivpVelocity ); - core->speed_change.add( &ivpVelocity ); - } - - if ( angularVelocity ) - { - IVP_U_Float_Point ivpAngularVelocity; - ConvertAngularImpulseToIVP( *angularVelocity, ivpAngularVelocity ); - - core->rot_speed_change.add(&ivpAngularVelocity); - } - ClampVelocity(); -} - -void CPhysicsObject::SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport ) -{ - IVP_U_Quat rot; - IVP_U_Point pos; - - if ( m_pShadow ) - { - UpdateShadow( worldPosition, angles, false, 0 ); - } - ConvertPositionToIVP( worldPosition, pos ); - - ConvertRotationToIVP( angles, rot ); - - if ( m_pObject->is_collision_detection_enabled() && isTeleport ) - { - EnableCollisions( false ); - m_pObject->beam_object_to_new_position( &rot, &pos, IVP_FALSE ); - EnableCollisions( true ); - } - else - { - m_pObject->beam_object_to_new_position( &rot, &pos, IVP_FALSE ); - } -} - -void CPhysicsObject::SetPositionMatrix( const matrix3x4_t& matrix, bool isTeleport ) -{ - if ( m_pShadow ) - { - Vector worldPosition; - QAngle angles; - MatrixAngles( matrix, angles ); - MatrixGetColumn( matrix, 3, worldPosition ); - UpdateShadow( worldPosition, angles, false, 0 ); - } - - IVP_U_Quat rot; - IVP_U_Matrix mat; - - ConvertMatrixToIVP( matrix, mat ); - - rot.set_quaternion( &mat ); - - if ( m_pObject->is_collision_detection_enabled() && isTeleport ) - { - EnableCollisions( false ); - m_pObject->beam_object_to_new_position( &rot, &mat.vv, IVP_FALSE ); - EnableCollisions( true ); - } - else - { - m_pObject->beam_object_to_new_position( &rot, &mat.vv, IVP_FALSE ); - } -} - -void CPhysicsObject::SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity ) -{ - Assert(IsMoveable()); - if ( !IsMoveable() ) - return; - IVP_Core *core = m_pObject->get_core(); - - WakeNow(); - - if ( velocity ) - { - ConvertPositionToIVP( *velocity, core->speed ); - core->speed_change.set_to_zero(); - } - - if ( angularVelocity ) - { - ConvertAngularImpulseToIVP( *angularVelocity, core->rot_speed ); - core->rot_speed_change.set_to_zero(); - } - ClampVelocity(); -} - -void CPhysicsObject::SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity ) -{ - if ( !IsMoveable() ) - return; - IVP_Core *core = m_pObject->get_core(); - - Wake(); - - if ( velocity ) - { - ConvertPositionToIVP( *velocity, core->speed_change ); - core->speed.set_to_zero(); - } - - if ( angularVelocity ) - { - ConvertAngularImpulseToIVP( *angularVelocity, core->rot_speed_change ); - core->rot_speed.set_to_zero(); - } - ClampVelocity(); -} - - -void CPhysicsObject::ClampVelocity() -{ - if ( m_pShadow ) - return; - - m_pObject->get_core()->apply_velocity_limit(); -} - -void GetWorldCoordFromSynapse( IVP_Synapse_Friction *pfriction, IVP_U_Point &world ) -{ - world.set(pfriction->get_contact_point()->get_contact_point_ws()); -} - -bool CPhysicsObject::GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) const -{ - IVP_Synapse_Friction *pfriction = m_pObject->get_first_friction_synapse(); - if ( !pfriction ) - return false; - - if ( contactPoint ) - { - IVP_U_Point world; - GetWorldCoordFromSynapse( pfriction, world ); - ConvertPositionToHL( world, *contactPoint ); - } - if ( contactObject ) - { - IVP_Real_Object *pivp = GetOppositeSynapseObject( pfriction ); - *contactObject = static_cast(pivp->client_data); - } - return true; -} - -void CPhysicsObject::SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation ) -{ - if ( m_pShadow ) - { - m_pShadow->MaxSpeed( maxSpeed, maxAngularSpeed ); - } - else - { - m_shadowTempGravityDisable = false; - - CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment(); - m_pShadow = pVEnv->CreateShadowController( this, allowPhysicsMovement, allowPhysicsRotation ); - m_pShadow->MaxSpeed( maxSpeed, maxAngularSpeed ); - // This really should be in the game code, but do this here because the game may (does) use - // shadow/AI control as a collision filter indicator. - RecheckCollisionFilter(); - } -} - -void CPhysicsObject::UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset ) -{ - if ( tempDisableGravity != m_shadowTempGravityDisable ) - { - m_shadowTempGravityDisable = tempDisableGravity; - if ( !m_pShadow || m_pShadow->AllowsTranslation() ) - { - EnableGravity( !m_shadowTempGravityDisable ); - } - } - if ( m_pShadow ) - { - m_pShadow->Update( targetPosition, targetAngles, timeOffset ); - } -} - - -void CPhysicsObject::RemoveShadowController() -{ - if ( m_pShadow ) - { - CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment(); - pVEnv->DestroyShadowController( m_pShadow ); - m_pShadow = NULL; - } -} - -// Back door to allow save/restore of backlink between shadow controller and physics object -void CPhysicsObject::RestoreShadowController( IPhysicsShadowController *pShadowController ) -{ - Assert( !m_pShadow ); - m_pShadow = pShadowController; -} - -int CPhysicsObject::GetShadowPosition( Vector *position, QAngle *angles ) const -{ - IVP_U_Matrix matrix; - - IVP_Environment *pEnv = m_pObject->get_environment(); - double psi = pEnv->get_next_PSI_time().get_seconds(); - m_pObject->calc_at_matrix( psi, &matrix ); - if ( angles ) - { - ConvertRotationToHL( matrix, *angles ); - } - if ( position ) - { - ConvertPositionToHL( matrix.vv, *position ); - } - - return 1; -} - - -IPhysicsShadowController *CPhysicsObject::GetShadowController( void ) const -{ - return m_pShadow; -} - -const CPhysCollide *CPhysicsObject::GetCollide( void ) const -{ - return m_pCollide; -} - - -IVP_SurfaceManager *CPhysicsObject::GetSurfaceManager( void ) const -{ - if ( m_collideType != COLLIDE_BALL ) - { - return m_pObject->get_surface_manager(); - } - return NULL; -} - - -float CPhysicsObject::GetDragInDirection( const IVP_U_Float_Point &velocity ) const -{ - IVP_U_Float_Point local; - - const IVP_U_Matrix *m_world_f_core = m_pObject->get_core()->get_m_world_f_core_PSI(); - m_world_f_core->vimult3( &velocity, &local ); - - return m_dragCoefficient * IVP_Inline_Math::fabsd( local.k[0] * m_dragBasis.x ) + - IVP_Inline_Math::fabsd( local.k[1] * m_dragBasis.y ) + - IVP_Inline_Math::fabsd( local.k[2] * m_dragBasis.z ); -} - -float CPhysicsObject::GetAngularDragInDirection( const IVP_U_Float_Point &angVelocity ) const -{ - return m_angDragCoefficient * IVP_Inline_Math::fabsd( angVelocity.k[0] * m_angDragBasis.x ) + - IVP_Inline_Math::fabsd( angVelocity.k[1] * m_angDragBasis.y ) + - IVP_Inline_Math::fabsd( angVelocity.k[2] * m_angDragBasis.z ); -} - -const char *CPhysicsObject::GetName() const -{ - return m_pObject->get_name(); -} - -void CPhysicsObject::SetMaterialIndex( int materialIndex ) -{ - if ( m_materialIndex == materialIndex ) - return; - - m_materialIndex = materialIndex; - IVP_Material *pMaterial = physprops->GetIVPMaterial( materialIndex ); - Assert(pMaterial); - m_pObject->l_default_material = pMaterial; - m_callbacks |= CALLBACK_ENABLING_COLLISION; - BEGIN_IVP_ALLOCATION(); - m_pObject->recompile_material_changed(); - END_IVP_ALLOCATION(); - m_callbacks &= ~CALLBACK_ENABLING_COLLISION; - if ( GetShadowController() ) - { - GetShadowController()->ObjectMaterialChanged( materialIndex ); - } -} - -// convert square velocity magnitude from IVP to HL -float CPhysicsObject::GetEnergy() const -{ - IVP_Core *pCore = m_pObject->get_core(); - IVP_FLOAT energy = 0.0f; - IVP_U_Float_Point tmp; - - energy = 0.5f * pCore->get_mass() * pCore->speed.dot_product(&pCore->speed); // 1/2mvv - tmp.set_pairwise_mult(&pCore->rot_speed, pCore->get_rot_inertia()); // wI - energy += 0.5f * tmp.dot_product(&pCore->rot_speed); // 1/2mvv + 1/2wIw - - return ConvertEnergyToHL( energy ); -} - -float CPhysicsObject::ComputeShadowControl( const hlshadowcontrol_params_t ¶ms, float secondsToArrival, float dt ) -{ - return ComputeShadowControllerHL( this, params, secondsToArrival, dt ); -} - -float CPhysicsObject::GetSphereRadius() const -{ - if ( m_collideType != COLLIDE_BALL ) - return 0; - - return ConvertDistanceToHL( m_pObject->to_ball()->get_radius() ); -} - -float CPhysicsObject::CalculateLinearDrag( const Vector &unitDirection ) const -{ - IVP_U_Float_Point ivpDir; - ConvertDirectionToIVP( unitDirection, ivpDir ); - - return GetDragInDirection( ivpDir ); -} - -float CPhysicsObject::CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const -{ - IVP_U_Float_Point ivpAxis; - ConvertDirectionToIVP( objectSpaceRotationAxis, ivpAxis ); - - // drag factor is per-radian, convert to per-degree - return GetAngularDragInDirection( ivpAxis ) * DEG2RAD(1.0); -} - - -void CPhysicsObject::BecomeTrigger() -{ - if ( IsTrigger() ) - return; - - if ( GetShadowController() ) - { - // triggers won't have the standard collisions, so the material change is no longer necessary - // also: This will fix problems with surfaceprops if the trigger becomes a fluid. - GetShadowController()->UseShadowMaterial( false ); - } - EnableDrag( false ); - EnableGravity( false ); - - // UNDONE: Use defaults here? Do we want object sets by default? - IVP_Template_Phantom trigger; - trigger.manage_intruding_cores = IVP_TRUE; // manage a list of intruded objects - trigger.manage_sleeping_cores = IVP_TRUE; // don't untouch/touch on sleep/wake - trigger.dont_check_for_unmoveables = IVP_TRUE; - trigger.exit_policy_extra_radius = 0.1f; // relatively strict exit check [m] - - bool enableCollisions = IsCollisionEnabled(); - EnableCollisions( false ); - BEGIN_IVP_ALLOCATION(); - m_pObject->convert_to_phantom( &trigger ); - END_IVP_ALLOCATION(); - // hook up events - CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment(); - pVEnv->PhantomAdd( this ); - - - EnableCollisions( enableCollisions ); -} - - -void CPhysicsObject::RemoveTrigger() -{ - IVP_Controller_Phantom *pController = m_pObject->get_controller_phantom(); - - // NOTE: This will remove the back-link in the object - delete pController; -} - - -bool CPhysicsObject::IsTrigger() const -{ - return m_pObject->get_controller_phantom() != NULL ? true : false; -} - -bool CPhysicsObject::IsFluid() const -{ - IVP_Controller_Phantom *pController = m_pObject->get_controller_phantom(); - if ( pController ) - { - // UNDONE: Make a base class for triggers? IPhysicsTrigger? - // and derive fluids and any other triggers from that class - // then you can ask that class what to do here. - if ( pController->client_data ) - return true; - } - - return false; -} - -// sets the object to be hinged. Fixed it place, but able to rotate around one axis. -void CPhysicsObject::BecomeHinged( int localAxis ) -{ - - if ( IsMoveable() ) - { - float savedMass = GetMass(); - - IVP_U_Float_Hesse *iri = (IVP_U_Float_Hesse *)m_pObject->get_core()->get_inv_rot_inertia(); - - float savedRI[3]; - for ( int i = 0; i < 3; i++ ) - savedRI[i] = iri->k[i]; - - SetMass( VPHYSICS_MAX_MASS ); - IVP_U_Float_Hesse tmp = *iri; - -#if 0 - for ( i = 0; i < 3; i++ ) - tmp.k[i] = savedRI[i]; -#else - int localAxisIVP = ConvertCoordinateAxisToIVP(localAxis); - tmp.k[localAxisIVP] = savedRI[localAxisIVP]; -#endif - - SetMass( savedMass ); - *iri = tmp; - } - m_hingedAxis = localAxis+1; -} - -void CPhysicsObject::RemoveHinged() -{ - m_hingedAxis = 0; - m_pObject->get_core()->calc_calc(); -} - -// dumps info about the object to Msg() -void CPhysicsObject::OutputDebugInfo() const -{ - Msg("-----------------\nObject: %s\n", m_pObject->get_name()); - Msg("Mass: %.3e (inv %.3e)\n", GetMass(), GetInvMass() ); - Vector inertia = GetInertia(); - Vector invInertia = GetInvInertia(); - Msg("Inertia: %.3e, %.3e, %.3e (inv %.3e, %.3e, %.3e)\n", inertia.x, inertia.y, inertia.z, invInertia.x, invInertia.y, invInertia.z ); - - Vector speed, angSpeed; - GetVelocity( &speed, &angSpeed ); - Msg("Velocity: %.2f, %.2f, %.2f \n", speed.x, speed.y, speed.z ); - Msg("Ang Velocity: %.2f, %.2f, %.2f \n", angSpeed.x, angSpeed.y, angSpeed.z ); - - float damp, angDamp; - GetDamping( &damp, &angDamp ); - Msg("Damping %.3e linear, %.3e angular\n", damp, angDamp ); - - Msg("Linear Drag: %.2f, %.2f, %.2f (factor %.2f)\n", m_dragBasis.x, m_dragBasis.y, m_dragBasis.z, m_dragCoefficient ); - Msg("Angular Drag: %.2f, %.2f, %.2f (factor %.2f)\n", m_angDragBasis.x, m_angDragBasis.y, m_angDragBasis.z, m_angDragCoefficient ); - - if ( IsHinged() ) - { - const char *pAxisNames[] = {"x", "y", "z"}; - Msg("Hinged on %s axis\n", pAxisNames[m_hingedAxis-1] ); - } - Msg("attached to %d controllers\n", m_pObject->get_core()->controllers_of_core.len() ); - for (int k = m_pObject->get_core()->controllers_of_core.len()-1; k>=0;k--) - { - // NOTE: Set a breakpoint here and take a look at what it's hooked to - IVP_Controller *pController = m_pObject->get_core()->controllers_of_core.element_at(k); - Msg("%d) %s\n", k, pController->get_controller_name() ); - } - Msg("State: %s, Collision %s, Motion %s, %sFlags %04X (game %04x, index %d)\n", - IsAsleep() ? "Asleep" : "Awake", - IsCollisionEnabled() ? "Enabled" : "Disabled", - IsStatic() ? "Static" : (IsMotionEnabled() ? "Enabled" : "Disabled"), - (GetCallbackFlags() & CALLBACK_MARKED_FOR_TEST) ? "Debug! " : "", - (int)GetCallbackFlags(), (int)GetGameFlags(), (int)GetGameIndex() ); - - float matDensity = 0; - float matThickness = 0; - float matFriction = 0; - float matElasticity = 0; - physprops->GetPhysicsProperties( GetMaterialIndexInternal(), &matDensity, &matThickness, &matFriction, &matElasticity ); - Msg("Material: %s : density(%.1f), thickness(%.2f), friction(%.2f), elasticity(%.2f)\n", physprops->GetPropName(GetMaterialIndexInternal()), - matDensity, matThickness, matFriction, matElasticity ); - if ( GetCollide() ) - { - OutputCollideDebugInfo( GetCollide() ); - } -} - -bool CPhysicsObject::IsAttachedToConstraint( bool bExternalOnly ) const -{ - if ( m_pObject ) - { - for (int k = m_pObject->get_core()->controllers_of_core.len()-1; k>=0;k--) - { - IVP_Controller *pController = m_pObject->get_core()->controllers_of_core.element_at(k); - if ( pController->get_controller_priority() == IVP_CP_CONSTRAINTS ) - { - if ( !bExternalOnly || IsExternalConstraint(pController, GetGameData()) ) - return true; - } - } - } - return false; -} - -static void InitObjectTemplate( IVP_Template_Real_Object &objectTemplate, int materialIndex, objectparams_t *pParams, bool isStatic ) -{ - objectTemplate.mass = clamp( pParams->mass, VPHYSICS_MIN_MASS, VPHYSICS_MAX_MASS ); - - if ( materialIndex >= 0 ) - { - objectTemplate.material = physprops->GetIVPMaterial( materialIndex ); - } - else - { - materialIndex = physprops->GetSurfaceIndex( "default" ); - objectTemplate.material = physprops->GetIVPMaterial( materialIndex ); - } - - // HACKHACK: Do something with this name? - BEGIN_IVP_ALLOCATION(); - if ( IsPC() ) - { - objectTemplate.set_name(pParams->pName); - } - END_IVP_ALLOCATION(); -#if USE_COLLISION_GROUP_STRING - objectTemplate.set_nocoll_group_ident( NULL ); -#endif - - objectTemplate.physical_unmoveable = isStatic ? IVP_TRUE : IVP_FALSE; - objectTemplate.rot_inertia_is_factor = IVP_TRUE; - - float inertia = pParams->inertia; - - // don't allow <=0 inertia!!!! - if ( inertia <= 0 ) - inertia = 1.0; - - if ( inertia > 1e14f ) - inertia = 1e14f; - - objectTemplate.rot_inertia.set(inertia, inertia, inertia); - objectTemplate.rot_speed_damp_factor.set(pParams->rotdamping, pParams->rotdamping, pParams->rotdamping); - objectTemplate.speed_damp_factor = pParams->damping; - objectTemplate.auto_check_rot_inertia = pParams->rotInertiaLimit; -} - -CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle& angles, objectparams_t *pParams, bool isStatic ) -{ - if ( materialIndex < 0 ) - { - materialIndex = physprops->GetSurfaceIndex( "default" ); - } - AssertOnce(materialIndex>=0 && materialIndex<127); - IVP_Template_Real_Object objectTemplate; - IVP_U_Quat rotation; - IVP_U_Point pos; - - Assert( position.IsValid() ); - Assert( angles.IsValid() ); - -#if _WIN32 - if ( !position.IsValid() || !angles.IsValid() ) - { - DebuggerBreakIfDebugging(); - Warning("Invalid initial position on %s\n", pParams->pName ); - - Vector *pPos = (Vector *)&position; - QAngle *pRot = (QAngle *)&angles; - if ( !pPos->IsValid() ) - pPos->Init(); - if ( !pRot->IsValid() ) - pRot->Init(); - } -#endif - - ConvertRotationToIVP( angles, rotation ); - ConvertPositionToIVP( position, pos ); - - InitObjectTemplate( objectTemplate, materialIndex, pParams, isStatic ); - - IVP_U_Matrix massCenterMatrix; - massCenterMatrix.init(); - if ( pParams->massCenterOverride ) - { - IVP_U_Point center; - ConvertPositionToIVP( *pParams->massCenterOverride, center ); - massCenterMatrix.shift_os( ¢er ); - objectTemplate.mass_center_override = &massCenterMatrix; - } - - CPhysicsObject *pObject = new CPhysicsObject(); - short collideType; - IVP_SurfaceManager *pSurman = CreateSurfaceManager( pCollisionModel, collideType ); - if ( !pSurman ) - return NULL; - pObject->m_collideType = collideType; - pObject->m_asleepSinceCreation = true; - - BEGIN_IVP_ALLOCATION(); - - IVP_Polygon *realObject = pEnvironment->GetIVPEnvironment()->create_polygon(pSurman, &objectTemplate, &rotation, &pos); - - pObject->Init( pCollisionModel, realObject, materialIndex, pParams->volume, pParams->dragCoefficient, pParams->dragCoefficient ); - pObject->SetGameData( pParams->pGameData ); - - if ( pParams->enableCollisions ) - { - pObject->EnableCollisions( true ); - } - if ( !isStatic && pParams->dragCoefficient != 0.0f ) - { - pObject->EnableDrag( true ); - } - - END_IVP_ALLOCATION(); - - return pObject; -} - -CPhysicsObject *CreatePhysicsSphere( CPhysicsEnvironment *pEnvironment, float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic ) -{ - IVP_U_Quat rotation; - IVP_U_Point pos; - - ConvertRotationToIVP( angles, rotation ); - ConvertPositionToIVP( position, pos ); - - IVP_Template_Real_Object objectTemplate; - InitObjectTemplate( objectTemplate, materialIndex, pParams, isStatic ); - - IVP_Template_Ball ballTemplate; - ballTemplate.radius = ConvertDistanceToIVP( radius ); - - MEM_ALLOC_CREDIT(); - IVP_Ball *realObject = pEnvironment->GetIVPEnvironment()->create_ball( &ballTemplate, &objectTemplate, &rotation, &pos ); - - float volume = pParams->volume; - if ( volume <= 0 ) - { - volume = 4.0f * radius * radius * radius * M_PI / 3.0f; - } - CPhysicsObject *pObject = new CPhysicsObject(); - pObject->Init( NULL, realObject, materialIndex, volume, 0, 0 ); //, pParams->dragCoefficient, pParams->dragCoefficient - pObject->SetGameData( pParams->pGameData ); - - if ( pParams->enableCollisions ) - { - pObject->EnableCollisions( true ); - } - // drag is not supported on spheres - //pObject->EnableDrag( false ); - - return pObject; -} - -class CMaterialIndexOps : public CDefSaveRestoreOps -{ -public: - // save data type interface - virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) - { - int materialIndex = *((int *)fieldInfo.pField); - const char *pMaterialName = physprops->GetPropName( materialIndex ); - if ( !pMaterialName ) - { - pMaterialName = physprops->GetPropName( 0 ); - } - int len = strlen(pMaterialName) + 1; - pSave->WriteInt( &len ); - pSave->WriteString( pMaterialName ); - } - - virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) - { - char nameBuf[1024]; - int nameLen = pRestore->ReadInt(); - pRestore->ReadString( nameBuf, sizeof(nameBuf), nameLen ); - int *pMaterialIndex = (int *)fieldInfo.pField; - *pMaterialIndex = physprops->GetSurfaceIndex( nameBuf ); - if ( *pMaterialIndex < 0 ) - { - *pMaterialIndex = 0; - } - } - - virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) - { - int *pMaterialIndex = (int *)fieldInfo.pField; - return (*pMaterialIndex == 0); - } - - virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) - { - int *pMaterialIndex = (int *)fieldInfo.pField; - *pMaterialIndex = 0; - } -}; - -static CMaterialIndexOps g_MaterialIndexDataOps; - -ISaveRestoreOps* MaterialIndexDataOps() -{ - return &g_MaterialIndexDataOps; -} - -BEGIN_SIMPLE_DATADESC( vphysics_save_cphysicsobject_t ) -// DEFINE_FIELD( pCollide, FIELD_??? ), // don't save this -// DEFINE_FIELD( pName, FIELD_??? ), // don't save this -DEFINE_FIELD( sphereRadius, FIELD_FLOAT ), -DEFINE_FIELD( isStatic, FIELD_BOOLEAN ), -DEFINE_FIELD( collisionEnabled, FIELD_BOOLEAN ), -DEFINE_FIELD( gravityEnabled, FIELD_BOOLEAN ), -DEFINE_FIELD( dragEnabled, FIELD_BOOLEAN ), -DEFINE_FIELD( motionEnabled, FIELD_BOOLEAN ), -DEFINE_FIELD( isAsleep, FIELD_BOOLEAN ), -DEFINE_FIELD( isTrigger, FIELD_BOOLEAN ), -DEFINE_FIELD( asleepSinceCreation, FIELD_BOOLEAN ), -DEFINE_FIELD( hasTouchedDynamic, FIELD_BOOLEAN ), -DEFINE_CUSTOM_FIELD( materialIndex, &g_MaterialIndexDataOps ), -DEFINE_FIELD( mass, FIELD_FLOAT ), -DEFINE_FIELD( rotInertia, FIELD_VECTOR ), -DEFINE_FIELD( speedDamping, FIELD_FLOAT ), -DEFINE_FIELD( rotSpeedDamping, FIELD_FLOAT ), -DEFINE_FIELD( massCenterOverride, FIELD_VECTOR ), -DEFINE_FIELD( callbacks, FIELD_INTEGER ), -DEFINE_FIELD( gameFlags, FIELD_INTEGER ), -DEFINE_FIELD( contentsMask, FIELD_INTEGER ), -DEFINE_FIELD( volume, FIELD_FLOAT ), -DEFINE_FIELD( dragCoefficient, FIELD_FLOAT ), -DEFINE_FIELD( angDragCoefficient, FIELD_FLOAT ), -DEFINE_FIELD( hasShadowController,FIELD_BOOLEAN ), -//DEFINE_VPHYSPTR( pShadow ), -DEFINE_FIELD( origin, FIELD_POSITION_VECTOR ), -DEFINE_FIELD( angles, FIELD_VECTOR ), -DEFINE_FIELD( velocity, FIELD_VECTOR ), -DEFINE_FIELD( angVelocity, FIELD_VECTOR ), -DEFINE_FIELD( collideType, FIELD_SHORT ), -DEFINE_FIELD( gameIndex, FIELD_SHORT ), -DEFINE_FIELD( hingeAxis, FIELD_INTEGER ), -END_DATADESC() - -bool CPhysicsObject::IsCollisionEnabled() const -{ - return GetObject()->is_collision_detection_enabled() ? true : false; -} - -void CPhysicsObject::WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate ) -{ - if ( m_collideType == COLLIDE_BALL ) - { - objectTemplate.pCollide = NULL; - objectTemplate.sphereRadius = GetSphereRadius(); - } - else - { - objectTemplate.pCollide = GetCollide(); - objectTemplate.sphereRadius = 0; - } - objectTemplate.isStatic = IsStatic(); - objectTemplate.collisionEnabled = IsCollisionEnabled(); - objectTemplate.gravityEnabled = IsGravityEnabled(); - objectTemplate.dragEnabled = IsDragEnabled(); - objectTemplate.motionEnabled = IsMotionEnabled(); - objectTemplate.isAsleep = IsAsleep(); - objectTemplate.isTrigger = IsTrigger(); - objectTemplate.asleepSinceCreation = m_asleepSinceCreation; - objectTemplate.materialIndex = m_materialIndex; - objectTemplate.mass = GetMass(); - - objectTemplate.rotInertia = GetInertia(); - GetDamping( &objectTemplate.speedDamping, &objectTemplate.rotSpeedDamping ); - objectTemplate.massCenterOverride.Init(); - if ( !IsMassCenterAtDefault() ) - { - objectTemplate.massCenterOverride = GetMassCenterLocalSpace(); - } - - objectTemplate.callbacks = m_callbacks; - objectTemplate.gameFlags = m_gameFlags; - objectTemplate.volume = GetVolume(); - objectTemplate.dragCoefficient = m_dragCoefficient; - objectTemplate.angDragCoefficient = m_angDragCoefficient; - objectTemplate.pShadow = m_pShadow; - objectTemplate.hasShadowController = (m_pShadow != NULL) ? true : false; - objectTemplate.hasTouchedDynamic = HasTouchedDynamic(); - //bool m_shadowTempGravityDisable; - objectTemplate.collideType = m_collideType; - objectTemplate.gameIndex = m_gameIndex; - objectTemplate.contentsMask = m_contentsMask; - objectTemplate.hingeAxis = m_hingedAxis; - GetPosition( &objectTemplate.origin, &objectTemplate.angles ); - GetVelocity( &objectTemplate.velocity, &objectTemplate.angVelocity ); -} - -void CPhysicsObject::InitFromTemplate( CPhysicsEnvironment *pEnvironment, void *pGameData, const vphysics_save_cphysicsobject_t &objectTemplate ) -{ - MEM_ALLOC_CREDIT(); - m_collideType = objectTemplate.collideType; - - IVP_Template_Real_Object ivpObjectTemplate; - IVP_U_Quat rotation; - IVP_U_Point pos; - - ConvertRotationToIVP( objectTemplate.angles, rotation ); - ConvertPositionToIVP( objectTemplate.origin, pos ); - - ivpObjectTemplate.mass = objectTemplate.mass; - - if ( objectTemplate.materialIndex >= 0 ) - { - ivpObjectTemplate.material = physprops->GetIVPMaterial( objectTemplate.materialIndex ); - } - else - { - ivpObjectTemplate.material = physprops->GetIVPMaterial( physprops->GetSurfaceIndex( "default" ) ); - } - - Assert( ivpObjectTemplate.material ); - // HACKHACK: Pass this name in for debug - ivpObjectTemplate.set_name(objectTemplate.pName); -#if USE_COLLISION_GROUP_STRING - ivpObjectTemplate.set_nocoll_group_ident( NULL ); -#endif - - ivpObjectTemplate.physical_unmoveable = objectTemplate.isStatic ? IVP_TRUE : IVP_FALSE; - ivpObjectTemplate.rot_inertia_is_factor = IVP_TRUE; - - ivpObjectTemplate.rot_inertia.set( 1,1,1 ); - ivpObjectTemplate.rot_speed_damp_factor.set( objectTemplate.rotSpeedDamping, objectTemplate.rotSpeedDamping, objectTemplate.rotSpeedDamping ); - ivpObjectTemplate.speed_damp_factor = objectTemplate.speedDamping; - - IVP_U_Matrix massCenterMatrix; - massCenterMatrix.init(); - if ( objectTemplate.massCenterOverride != vec3_origin ) - { - IVP_U_Point center; - ConvertPositionToIVP( objectTemplate.massCenterOverride, center ); - massCenterMatrix.shift_os( ¢er ); - ivpObjectTemplate.mass_center_override = &massCenterMatrix; - } - - IVP_Real_Object *realObject = NULL; - if ( m_collideType == COLLIDE_BALL ) - { - IVP_Template_Ball ballTemplate; - ballTemplate.radius = ConvertDistanceToIVP( objectTemplate.sphereRadius ); - - realObject = pEnvironment->GetIVPEnvironment()->create_ball( &ballTemplate, &ivpObjectTemplate, &rotation, &pos ); - } - else - { - short collideType; - IVP_SurfaceManager *surman = CreateSurfaceManager( objectTemplate.pCollide, collideType ); - m_collideType = collideType; - realObject = pEnvironment->GetIVPEnvironment()->create_polygon(surman, &ivpObjectTemplate, &rotation, &pos); - } - - m_pObject = realObject; - SetInertia( objectTemplate.rotInertia ); - Init( objectTemplate.pCollide, realObject, objectTemplate.materialIndex, objectTemplate.volume, objectTemplate.dragCoefficient, objectTemplate.dragCoefficient ); - - SetCallbackFlags( (unsigned short) objectTemplate.callbacks ); - SetGameFlags( (unsigned short) objectTemplate.gameFlags ); - SetGameIndex( objectTemplate.gameIndex ); - SetGameData( pGameData ); - SetContents( objectTemplate.contentsMask ); - - if ( objectTemplate.dragEnabled ) - { - Assert( !objectTemplate.isStatic ); - EnableDrag( true ); - } - - if ( !objectTemplate.motionEnabled ) - { - Assert( !objectTemplate.isStatic ); - EnableMotion( false ); - } - - if ( objectTemplate.isTrigger ) - { - BecomeTrigger(); - } - - if ( !objectTemplate.gravityEnabled ) - { - EnableGravity( false ); - } - - if ( objectTemplate.collisionEnabled ) - { - EnableCollisions( true ); - } - - m_asleepSinceCreation = objectTemplate.asleepSinceCreation; - - if ( objectTemplate.velocity.LengthSqr() != 0 || objectTemplate.angVelocity.LengthSqr() != 0 ) - { - // will wake up the object - SetVelocityInstantaneous( &objectTemplate.velocity, &objectTemplate.angVelocity ); - } - else if( !objectTemplate.isAsleep ) - { - Assert( !objectTemplate.isStatic ); - WakeNow(); - } - - if( objectTemplate.isAsleep ) - { - Sleep(); - } - - if ( objectTemplate.hingeAxis ) - { - BecomeHinged( objectTemplate.hingeAxis-1 ); - } - - if ( objectTemplate.hasTouchedDynamic ) - { - SetTouchedDynamic(); - } - - m_pShadow = NULL; -} - - -bool SavePhysicsObject( const physsaveparams_t ¶ms, CPhysicsObject *pObject ) -{ - vphysics_save_cphysicsobject_t objectTemplate; - memset( &objectTemplate, 0, sizeof(objectTemplate) ); - - pObject->WriteToTemplate( objectTemplate ); - params.pSave->WriteAll( &objectTemplate ); - - if ( objectTemplate.hasShadowController ) - { - return SavePhysicsShadowController( params, objectTemplate.pShadow ); - } - return true; -} - -bool RestorePhysicsObject( const physrestoreparams_t ¶ms, CPhysicsObject **ppObject ) -{ - vphysics_save_cphysicsobject_t objectTemplate; - memset( &objectTemplate, 0, sizeof(objectTemplate) ); - params.pRestore->ReadAll( &objectTemplate ); - Assert(objectTemplate.origin.IsValid()); - Assert(objectTemplate.angles.IsValid()); - objectTemplate.pCollide = params.pCollisionModel; - objectTemplate.pName = params.pName; - *ppObject = new CPhysicsObject(); - - postrestore_objectlist_t entry; - entry.Defaults(); - - if ( objectTemplate.collisionEnabled ) - { - // queue up the collision enable for these in case their entities have other dependent - // physics handlers (like controllers) that need to be restored before callbacks are useful - entry.pObject = *ppObject; - entry.enableCollisions = true; - objectTemplate.collisionEnabled = false; - } - - (*ppObject)->InitFromTemplate( static_cast(params.pEnvironment), params.pGameData, objectTemplate ); - - if ( (*ppObject)->IsAsleep() && !(*ppObject)->m_asleepSinceCreation && !(*ppObject)->IsStatic() ) - { - entry.pObject = *ppObject; - entry.growFriction = true; - } - - if ( entry.pObject ) - { - g_PostRestoreObjectList.AddToTail( entry ); - } - - if ( objectTemplate.hasShadowController ) - { - bool restored = RestorePhysicsShadowControllerInternal( params, &objectTemplate.pShadow, *ppObject ); - (*ppObject)->RestoreShadowController( objectTemplate.pShadow ); - return restored; - } - - return true; -} - -IPhysicsObject *CreateObjectFromBuffer( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions ) -{ - CPhysicsObject *pObject = new CPhysicsObject(); - if ( bufferSize >= sizeof(vphysics_save_cphysicsobject_t)) - { - vphysics_save_cphysicsobject_t *pTemplate = reinterpret_cast(pBuffer); - pTemplate->hasShadowController = false; // this hasn't been saved separately so cannot be supported via this path - pObject->InitFromTemplate( pEnvironment, pGameData, *pTemplate ); - if ( pTemplate->collisionEnabled && enableCollisions ) - { - pObject->EnableCollisions(true); - } - return pObject; - } - return NULL; -} - -IPhysicsObject *CreateObjectFromBuffer_UseExistingMemory( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, CPhysicsObject *pExistingMemory ) -{ - if ( bufferSize >= sizeof(vphysics_save_cphysicsobject_t)) - { - vphysics_save_cphysicsobject_t *pTemplate = reinterpret_cast(pBuffer); - // Allow the placement new. If we don't do this, then it'll get a compile error because new - // might be defined as the special form in MEMALL_DEBUG_NEW. - #include "tier0/memdbgoff.h" - pExistingMemory = new ( pExistingMemory ) CPhysicsObject(); - #include "tier0/memdbgon.h" - pExistingMemory->InitFromTemplate( pEnvironment, pGameData, *pTemplate ); - if ( pTemplate->collisionEnabled ) - { - pExistingMemory->EnableCollisions(true); - } - return pExistingMemory; - } - return NULL; -} - -// regenerate the friction systems for these objects. Because when it was saved it had them (came to rest with the contact points). -// So now we need to recreate them or some objects may not wake up when this object (or its neighbors) are deleted. -void PostRestorePhysicsObject() -{ - for ( int i = g_PostRestoreObjectList.Count()-1; i >= 0; --i ) - { - if ( g_PostRestoreObjectList[i].pObject ) - { - if ( g_PostRestoreObjectList[i].growFriction ) - { - g_PostRestoreObjectList[i].pObject->GetObject()->force_grow_friction_system(); - } - if ( g_PostRestoreObjectList[i].enableCollisions ) - { - g_PostRestoreObjectList[i].pObject->EnableCollisions( true ); - } - } - } - g_PostRestoreObjectList.Purge(); -}