diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vphysics/physics_material.cpp | |
| download | archived-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.cpp | 643 |
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]; + } +} |