summaryrefslogtreecommitdiff
path: root/vphysics/physics_material.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vphysics/physics_material.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vphysics/physics_material.cpp')
-rw-r--r--vphysics/physics_material.cpp643
1 files changed, 643 insertions, 0 deletions
diff --git a/vphysics/physics_material.cpp b/vphysics/physics_material.cpp
new file mode 100644
index 0000000..3073217
--- /dev/null
+++ b/vphysics/physics_material.cpp
@@ -0,0 +1,643 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "physics_vehicle.h"
+
+#include "ivp_material.hxx"
+#include <ctype.h>
+#include "utlsymbol.h"
+#include "tier1/strtools.h"
+#include "vcollide_parse_private.h"
+#include "ctype.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: This is the data stored for each material/surface propery list
+//-----------------------------------------------------------------------------
+class CSurface : public IVP_Material
+{
+public:
+
+ // IVP_Material
+ virtual IVP_DOUBLE get_friction_factor()
+ {
+ return data.physics.friction;
+ }
+
+ virtual IVP_DOUBLE get_elasticity()
+ {
+ return data.physics.elasticity;
+ }
+ virtual const char *get_name();
+ // UNDONE: not implemented here.
+ virtual IVP_DOUBLE get_second_friction_factor()
+ {
+ return 0;
+ }
+ virtual IVP_DOUBLE get_adhesion()
+ {
+ return 0;
+ }
+
+ virtual IVP_DOUBLE get_damping()
+ {
+ return data.physics.dampening;
+ }
+
+ // strings
+ CUtlSymbol m_name;
+ unsigned short m_pad;
+
+ // physics properties
+ surfacedata_t data;
+};
+
+
+class CPhysicsSurfaceProps;
+
+class CIVPMaterialManager : public IVP_Material_Manager
+{
+ typedef IVP_Material_Manager BaseClass;
+public:
+ CIVPMaterialManager( void );
+ void Init( CPhysicsSurfaceProps *pProps ) { m_props = pProps; }
+ void SetPropMap( int *map, int mapSize );
+ int RemapIVPMaterialIndex( int ivpMaterialIndex ) const;
+
+ // IVP_Material_Manager
+ virtual IVP_Material *get_material_by_index(IVP_Real_Object *pObject, const IVP_U_Point *world_position, int index);
+
+ virtual IVP_DOUBLE get_friction_factor(IVP_Contact_Situation *situation) // returns values >0, value of 1.0f means object stands on a 45 degres hill
+ {
+ // vehicle wheels get no friction with stuff that isn't ground
+ // helps keep control of the car
+ // traction on less than 60 degree slopes.
+ float wheelFriction = 1.0f;
+ if ( ShouldOverrideWheelContactFriction( &wheelFriction, situation->objects[0], situation->objects[1], &situation->surf_normal ) )
+ {
+ return wheelFriction;
+ }
+
+ IVP_DOUBLE factor = BaseClass::get_friction_factor( situation );
+ factor = clamp(factor,0.0,1.0);
+
+ return factor;
+ }
+
+ virtual IVP_DOUBLE get_elasticity(IVP_Contact_Situation *situation) // range [0, 1.0f[, the relative speed after a collision compared to the speed before
+ {
+ IVP_DOUBLE flElasticity = BaseClass::get_elasticity( situation );
+ if ( flElasticity > 1.0f )
+ {
+ flElasticity = 1.0f;
+ }
+ else if ( flElasticity < 0 )
+ {
+ flElasticity = 0;
+ }
+ return flElasticity;
+ }
+
+private:
+ CPhysicsSurfaceProps *m_props;
+ unsigned short m_propMap[128];
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: This is the main database of materials
+//-----------------------------------------------------------------------------
+class CPhysicsSurfaceProps : public IPhysicsSurfacePropsInternal
+{
+public:
+ CPhysicsSurfaceProps( void );
+ ~CPhysicsSurfaceProps( void );
+
+ virtual int ParseSurfaceData( const char *pFilename, const char *pTextfile );
+ virtual int SurfacePropCount( void ) const;
+ virtual int GetSurfaceIndex( const char *pPropertyName ) const;
+ virtual void GetPhysicsProperties( int surfaceDataIndex, float *density, float *thickness, float *friction, float *elasticity ) const;
+ virtual void GetPhysicsParameters( int surfaceDataIndex, surfacephysicsparams_t *pParamsOut ) const;
+ virtual surfacedata_t *GetSurfaceData( int surfaceDataIndex );
+ virtual const char *GetString( unsigned short stringTableIndex ) const;
+ virtual const char *GetPropName( int surfaceDataIndex ) const;
+ virtual void SetWorldMaterialIndexTable( int *pMapArray, int mapSize );
+ virtual int RemapIVPMaterialIndex( int ivpMaterialIndex ) const
+ {
+ return m_ivpManager.RemapIVPMaterialIndex( ivpMaterialIndex );
+ }
+ bool IsReservedMaterialIndex( int materialIndex ) const;
+ virtual const char *GetReservedMaterialName( int materialIndex ) const;
+ int GetReservedFallBack( int materialIndex ) const;
+
+ int GetReservedSurfaceIndex( const char *pPropertyName ) const;
+
+ // The database is derived from the IVP material class
+ const IVP_Material *GetIVPMaterial( int materialIndex ) const;
+ IVP_Material *GetIVPMaterial( int materialIndex );
+ virtual int GetIVPMaterialIndex( const IVP_Material *pIVP ) const;
+ IVP_Material_Manager *GetIVPManager( void ) { return &m_ivpManager; }
+
+ const char *GetNameString( CUtlSymbol name ) const
+ {
+ return m_strings.String(name);
+ }
+
+private:
+ const CSurface *GetInternalSurface( int materialIndex ) const;
+ CSurface *GetInternalSurface( int materialIndex );
+
+ void CopyPhysicsProperties( CSurface *pOut, int baseIndex );
+ bool AddFileToDatabase( const char *pFilename );
+
+private:
+ CUtlSymbolTableMT m_strings;
+ CUtlVector<CSurface> m_props;
+ CUtlVector<CUtlSymbol> m_fileList;
+ CIVPMaterialManager m_ivpManager;
+ bool m_init;
+ int m_shadowFallback;
+};
+
+
+// Singleton database object
+CPhysicsSurfaceProps g_SurfaceDatabase;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CPhysicsSurfaceProps, IPhysicsSurfaceProps, VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, g_SurfaceDatabase);
+
+
+// Global pointer to singleton for VPHYSICS.DLL internal access
+IPhysicsSurfacePropsInternal *physprops = &g_SurfaceDatabase;
+
+
+const char *CSurface::get_name()
+{
+ return g_SurfaceDatabase.GetNameString( m_name );
+}
+
+CPhysicsSurfaceProps::CPhysicsSurfaceProps( void ) : m_fileList(8,8), m_strings( 0, 32, true )
+{
+ m_ivpManager.Init( this );
+ // Force index 0 to be the empty string. Allows game code to check for zero, but
+ // still resolve to a string
+ m_strings.AddString("");
+ m_init = false;
+ m_shadowFallback = 0;
+}
+
+
+CPhysicsSurfaceProps::~CPhysicsSurfaceProps( void )
+{
+}
+
+int CPhysicsSurfaceProps::SurfacePropCount( void ) const
+{
+ return m_props.Size();
+}
+
+// Add the filename to a list to make sure each file is only processed once
+bool CPhysicsSurfaceProps::AddFileToDatabase( const char *pFilename )
+{
+ CUtlSymbol id = m_strings.AddString( pFilename );
+
+ for ( int i = 0; i < m_fileList.Size(); i++ )
+ {
+ if ( m_fileList[i] == id )
+ return false;
+ }
+
+ m_fileList.AddToTail( id );
+ return true;
+}
+
+int CPhysicsSurfaceProps::GetSurfaceIndex( const char *pPropertyName ) const
+{
+ if ( pPropertyName[0] == '$' )
+ {
+ int index = GetReservedSurfaceIndex( pPropertyName );
+ if ( index >= 0 )
+ return index;
+ }
+
+ CUtlSymbol id = m_strings.Find( pPropertyName );
+ if ( id.IsValid() )
+ {
+ // BUGBUG: Linear search is slow!!!
+ for ( int i = 0; i < m_props.Size(); i++ )
+ {
+ // NOTE: Just comparing strings by index is pretty fast though
+ if ( m_props[i].m_name == id )
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+const char *CPhysicsSurfaceProps::GetPropName( int surfaceDataIndex ) const
+{
+ const CSurface *pSurface = GetInternalSurface( surfaceDataIndex );
+ if ( pSurface )
+ {
+ return GetNameString( pSurface->m_name );
+ }
+ return NULL;
+}
+
+
+// UNDONE: move reserved materials into this table, or into a parallel table
+// that gets hooked out here.
+CSurface *CPhysicsSurfaceProps::GetInternalSurface( int materialIndex )
+{
+ if ( IsReservedMaterialIndex( materialIndex ) )
+ {
+ materialIndex = GetReservedFallBack( materialIndex );
+ }
+ if ( materialIndex < 0 || materialIndex > m_props.Size()-1 )
+ {
+ return NULL;
+ }
+ return &m_props[materialIndex];
+}
+
+// this function is actually const except for the return type, so this is safe
+const CSurface *CPhysicsSurfaceProps::GetInternalSurface( int materialIndex ) const
+{
+ return const_cast<CPhysicsSurfaceProps *>(this)->GetInternalSurface(materialIndex);
+}
+
+void CPhysicsSurfaceProps::GetPhysicsProperties( int materialIndex, float *density, float *thickness, float *friction, float *elasticity ) const
+{
+ const CSurface *pSurface = GetInternalSurface( materialIndex );
+ if ( !pSurface )
+ {
+ pSurface = GetInternalSurface( GetSurfaceIndex( "default" ) );
+ Assert ( pSurface );
+ }
+ if ( pSurface )
+ {
+ if ( friction )
+ {
+ *friction = (float)pSurface->data.physics.friction;
+ }
+ if ( elasticity )
+ {
+ *elasticity = (float)pSurface->data.physics.elasticity;
+ }
+ if ( density )
+ {
+ *density = pSurface->data.physics.density;
+ }
+ if ( thickness )
+ {
+ *thickness = pSurface->data.physics.thickness;
+ }
+ }
+}
+
+void CPhysicsSurfaceProps::GetPhysicsParameters( int surfaceDataIndex, surfacephysicsparams_t *pParamsOut ) const
+{
+ if ( !pParamsOut )
+ return;
+
+ const CSurface *pSurface = GetInternalSurface( surfaceDataIndex );
+ if ( pSurface )
+ {
+ *pParamsOut = pSurface->data.physics;
+ }
+}
+
+surfacedata_t *CPhysicsSurfaceProps::GetSurfaceData( int materialIndex )
+{
+ CSurface *pSurface = GetInternalSurface( materialIndex );
+ if (!pSurface)
+ pSurface = GetInternalSurface( 0 ); // Zero is always the "default" property
+
+ Assert ( pSurface );
+ return &pSurface->data;
+}
+
+const char *CPhysicsSurfaceProps::GetString( unsigned short stringTableIndex ) const
+{
+ return m_strings.String( stringTableIndex );
+}
+
+
+bool CPhysicsSurfaceProps::IsReservedMaterialIndex( int materialIndex ) const
+{
+ return (materialIndex > 127) ? true : false;
+}
+
+const char *CPhysicsSurfaceProps::GetReservedMaterialName( int materialIndex ) const
+{
+ // NOTE: All of these must start with '$'
+ switch( materialIndex )
+ {
+ case MATERIAL_INDEX_SHADOW:
+ return "$MATERIAL_INDEX_SHADOW";
+ }
+
+ return NULL;
+}
+
+int CPhysicsSurfaceProps::GetReservedSurfaceIndex( const char *pPropertyName ) const
+{
+ if ( !Q_stricmp( pPropertyName, "$MATERIAL_INDEX_SHADOW" ) )
+ {
+ return MATERIAL_INDEX_SHADOW;
+ }
+ return -1;
+}
+
+const IVP_Material *CPhysicsSurfaceProps::GetIVPMaterial( int materialIndex ) const
+{
+ return GetInternalSurface(materialIndex);
+}
+
+IVP_Material *CPhysicsSurfaceProps::GetIVPMaterial( int materialIndex )
+{
+ return GetInternalSurface(materialIndex);
+}
+
+
+int CPhysicsSurfaceProps::GetReservedFallBack( int materialIndex ) const
+{
+ switch( materialIndex )
+ {
+ case MATERIAL_INDEX_SHADOW:
+ return m_shadowFallback;
+ }
+
+ return 0;
+}
+
+
+int CPhysicsSurfaceProps::GetIVPMaterialIndex( const IVP_Material *pIVP ) const
+{
+ int index = (const CSurface *)pIVP - m_props.Base();
+ if ( index >= 0 && index < m_props.Size() )
+ return index;
+
+ return -1;
+}
+
+
+void CPhysicsSurfaceProps::CopyPhysicsProperties( CSurface *pOut, int baseIndex )
+{
+ const CSurface *pSurface = GetInternalSurface( baseIndex );
+ if ( pSurface )
+ {
+ pOut->data = pSurface->data;
+ }
+}
+
+
+int CPhysicsSurfaceProps::ParseSurfaceData( const char *pFileName, const char *pTextfile )
+{
+ if ( !AddFileToDatabase( pFileName ) )
+ {
+ return 0;
+ }
+
+ const char *pText = pTextfile;
+
+ do
+ {
+ char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
+
+ pText = ParseKeyvalue( pText, key, value );
+ if ( !strcmp(value, "{") )
+ {
+ CSurface prop;
+ memset( &prop.data, 0, sizeof(prop.data) );
+ prop.m_name = m_strings.AddString( key );
+ int baseMaterial = GetSurfaceIndex( key );
+ if ( baseMaterial < 0 )
+ {
+ baseMaterial = GetSurfaceIndex( "default" );
+ }
+
+ CopyPhysicsProperties( &prop, baseMaterial );
+
+ do
+ {
+ pText = ParseKeyvalue( pText, key, value );
+ if ( !strcmpi( key, "}" ) )
+ {
+ // already in the database, don't add again, override values instead
+ const char *pOverride = m_strings.String(prop.m_name);
+ int propIndex = GetSurfaceIndex( pOverride );
+ if ( propIndex >= 0 )
+ {
+ CSurface *pSurface = GetInternalSurface( propIndex );
+ pSurface->data = prop.data;
+ break;
+ }
+
+ m_props.AddToTail( prop );
+ break;
+ }
+ else if ( !strcmpi( key, "base" ) )
+ {
+ baseMaterial = GetSurfaceIndex( value );
+ CopyPhysicsProperties( &prop, baseMaterial );
+ }
+ else if ( !strcmpi( key, "thickness" ) )
+ {
+ prop.data.physics.thickness = atof(value);
+ }
+ else if ( !strcmpi( key, "density" ) )
+ {
+ prop.data.physics.density = atof(value);
+ }
+ else if ( !strcmpi( key, "elasticity" ) )
+ {
+ prop.data.physics.elasticity = atof(value);
+ }
+ else if ( !strcmpi( key, "friction" ) )
+ {
+ prop.data.physics.friction = atof(value);
+ }
+ else if ( !strcmpi( key, "maxspeedfactor" ) )
+ {
+ prop.data.game.maxSpeedFactor = atof(value);
+ }
+ else if ( !strcmpi( key, "jumpfactor" ) )
+ {
+ prop.data.game.jumpFactor = atof(value);
+ }
+ else if ( !strcmpi( key, "climbable" ) )
+ {
+ prop.data.game.climbable = atoi(value);
+ }
+ // audio parameters
+ else if ( !strcmpi( key, "audioReflectivity" ) )
+ {
+ prop.data.audio.reflectivity = atof(value);
+ }
+ else if ( !strcmpi( key, "audioHardnessFactor" ) )
+ {
+ prop.data.audio.hardnessFactor = atof(value);
+ }
+ else if ( !strcmpi( key, "audioHardMinVelocity" ) )
+ {
+ prop.data.audio.hardVelocityThreshold = atof(value);
+ }
+ else if ( !strcmpi( key, "audioRoughnessFactor" ) )
+ {
+ prop.data.audio.roughnessFactor = atof(value);
+ }
+ else if ( !strcmpi( key, "scrapeRoughThreshold" ) )
+ {
+ prop.data.audio.roughThreshold = atof(value);
+ }
+ else if ( !strcmpi( key, "impactHardThreshold" ) )
+ {
+ prop.data.audio.hardThreshold = atof(value);
+ }
+ // sound names
+ else if ( !strcmpi( key, "stepleft" ) )
+ {
+ prop.data.sounds.stepleft = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "stepright" ) )
+ {
+ prop.data.sounds.stepright = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "impactsoft" ) )
+ {
+ prop.data.sounds.impactSoft = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "impacthard" ) )
+ {
+ prop.data.sounds.impactHard = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "scrapesmooth" ) )
+ {
+ prop.data.sounds.scrapeSmooth = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "scraperough" ) )
+ {
+ prop.data.sounds.scrapeRough = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "bulletimpact" ) )
+ {
+ prop.data.sounds.bulletImpact = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "break" ) )
+ {
+ prop.data.sounds.breakSound = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "strain" ) )
+ {
+ prop.data.sounds.strainSound = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "rolling" ) )
+ {
+ prop.data.sounds.rolling = m_strings.AddString( value );
+ }
+ else if ( !strcmpi( key, "gamematerial" ) )
+ {
+ if ( strlen(value) == 1 && !V_isdigit( value[0]) )
+ {
+ prop.data.game.material = toupper(value[0]);
+ }
+ else
+ {
+ prop.data.game.material = atoi(value);
+ }
+ }
+ else if ( !strcmpi( key, "dampening" ) )
+ {
+ prop.data.physics.dampening = atof(value);
+ }
+ else
+ {
+ // force a breakpoint
+ AssertMsg2( 0, "Bad surfaceprop key %s (%s)\n", key, value );
+ }
+ } while (pText);
+ }
+ } while (pText);
+
+ if ( !m_init )
+ {
+ m_init = true;
+ //AddReservedMaterials
+ CSurface prop;
+
+ int baseMaterial = GetSurfaceIndex( "default" );
+ memset( &prop.data, 0, sizeof(prop.data) );
+ prop.m_name = m_strings.AddString( GetReservedMaterialName(MATERIAL_INDEX_SHADOW) );
+ CopyPhysicsProperties( &prop, baseMaterial );
+ prop.data.physics.elasticity = 1e-3f;
+ prop.data.physics.friction = 0.8f;
+ m_shadowFallback = m_props.AddToTail( prop );
+ }
+ return m_props.Size();
+}
+
+
+void CPhysicsSurfaceProps::SetWorldMaterialIndexTable( int *pMapArray, int mapSize )
+{
+ m_ivpManager.SetPropMap( pMapArray, mapSize );
+}
+
+CIVPMaterialManager::CIVPMaterialManager( void ) : IVP_Material_Manager( IVP_FALSE )
+{
+ // by default every index maps to itself (NULL translation)
+ for ( int i = 0; i < ARRAYSIZE(m_propMap); i++ )
+ {
+ m_propMap[i] = i;
+ }
+}
+
+int CIVPMaterialManager::RemapIVPMaterialIndex( int ivpMaterialIndex ) const
+{
+ if ( ivpMaterialIndex > 127 )
+ return ivpMaterialIndex;
+
+ return m_propMap[ivpMaterialIndex];
+}
+
+// remap the incoming (from IVP) index and get the appropriate material
+// note that ivp will only supply indices between 1 and 127
+IVP_Material *CIVPMaterialManager::get_material_by_index(IVP_Real_Object *pObject, const IVP_U_Point *world_position, int index)
+{
+ IVP_Material *tmp = m_props->GetIVPMaterial( RemapIVPMaterialIndex(index) );
+ Assert(tmp);
+ if ( tmp )
+ {
+ return tmp;
+ }
+ else
+ {
+ return m_props->GetIVPMaterial( m_props->GetSurfaceIndex( "default" ) );
+ }
+}
+
+// Installs a LUT for remapping IVP material indices to physprop indices
+// A table of the names of the materials in index order is stored with the
+// compiled bsp file. This is then remapped dynamically without touching the
+// per-triangle indices on load. If we wanted to support multiple LUTs, it would
+// be better to preprocess/remap the triangles in the collision models at load time
+void CIVPMaterialManager::SetPropMap( int *map, int mapSize )
+{
+ // ??? just ignore any extra bits
+ if ( mapSize > 128 )
+ {
+ mapSize = 128;
+ }
+
+ for ( int i = 0; i < mapSize; i++ )
+ {
+ m_propMap[i] = (unsigned short)map[i];
+ }
+}