Compare commits

..

10 Commits

Author SHA1 Message Date
nillerusr
ce44f36999 fix mass setting 2023-10-19 13:02:56 +03:00
nillerusr
5835b207c1 add creation of dynamic physics objects 2023-10-18 22:38:42 +03:00
nillerusr
58ff2f3a72 improve collision loading, fix wrong axes 2023-10-17 20:49:22 +03:00
nillerusr
16b4da144f update gitignore, remove accidentally uploaded editor files 2023-10-17 20:48:28 +03:00
nillerusr
b95472df79 revert me 2023-10-17 20:46:42 +03:00
nillerusr
5324d8f328 implement basic collision loading 2023-10-17 12:47:03 +03:00
nillerusr
83e334f9b8 physx initial implementation 2023-10-16 07:58:27 +03:00
nillerusr
490bd8b42d make original vphysics copy to track changes 2023-10-16 07:57:53 +03:00
nillerusr
ee6a6d0b37 revert me after 2023-10-16 07:54:56 +03:00
nillerusr
5a4d0b7a4d fix undefined behaviours and jpeg crash on non-windows platforms 2023-10-08 07:31:07 +03:00
90 changed files with 23293 additions and 142 deletions

View File

@ -2,7 +2,6 @@ name: Build
on: [push, pull_request]
jobs:
build-linux-i386:
runs-on: ubuntu-latest
@ -39,7 +38,7 @@ jobs:
- name: Build windows-i386
run: |
git submodule init && git submodule update
./waf.bat configure -T debug --32bits
./waf.bat configure -T debug
./waf.bat build
build-windows-amd64:
@ -50,7 +49,7 @@ jobs:
- name: Build windows-amd64
run: |
git submodule init && git submodule update
./waf.bat configure -T debug
./waf.bat configure -T debug -8
./waf.bat build
build-dedicated-windows-i386:
@ -72,7 +71,7 @@ jobs:
- name: Build dedicated windows-amd64
run: |
git submodule init && git submodule update
./waf.bat configure -T debug -d
./waf.bat configure -T debug -d -8
./waf.bat build
build-dedicated-linux-i386:

View File

@ -38,7 +38,7 @@ jobs:
- name: Run tests windows-i386
run: |
git submodule init && git submodule update
./waf.bat configure -T release --tests --prefix=out/ --32bits
./waf.bat configure -T release --tests --prefix=out/
./waf.bat install
cd out
$env:Path = "bin";
@ -52,7 +52,7 @@ jobs:
- name: Run tests windows-amd64
run: |
git submodule init && git submodule update
./waf.bat configure -T release --tests --prefix=out/
./waf.bat configure -T release --tests --prefix=out/ -8
./waf.bat install
cd out
$env:Path = "bin";

2
.gitignore vendored
View File

@ -37,3 +37,5 @@ waf3*/
.vscode/
.depproj/
source-engine.sln
*.save
*.save.*

View File

@ -278,7 +278,7 @@ bool CDedicatedAppSystemGroup::PreInit( )
return false;
#ifdef _WIN32
g_bVGui = CommandLine()->CheckParm( "-vgui" );
g_bVGui = !CommandLine()->CheckParm( "-console" );
#endif
CreateInterfaceFn factory = GetFactory();

View File

@ -38,12 +38,7 @@ def build(bld):
if bld.env.DEST_OS == 'win32':
source += [
'sys_windows.cpp',
'vgui/CreateMultiplayerGameServerPage.cpp',
'vgui/MainPanel.cpp',
'../public/vgui_controls/vgui_controls.cpp',
'vgui/vguihelpers.cpp',
'console/TextConsoleWin32.cpp'
'sys_windows.cpp'
]
else:
source += [
@ -64,9 +59,6 @@ def build(bld):
libs = ['tier0','vpklib','tier1','tier2','tier3','vstdlib','steam_api','appframework','mathlib', 'EDIT']
if bld.env.DEST_OS == 'win32':
libs += ['vgui_controls', 'USER32', 'SHELL32']
install_path = bld.env.LIBDIR
bld.shlib(

View File

@ -7,7 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

View File

@ -706,13 +706,11 @@ bool CBaseClient::SendServerInfo( void )
serverinfo.WriteToBuffer( msg );
#ifdef _X360
if ( serverinfo.m_nMaxClients > 1 )
if ( IsX360() && serverinfo.m_nMaxClients > 1 )
{
Msg( "Telling clients to connect" );
g_pMatchmaking->TellClientsToConnect();
}
#endif
// send first tick
m_nSignonTick = m_Server->m_nTickCount;

View File

@ -6,7 +6,6 @@
#include "client_pch.h"
#ifdef SWDS
#include "igame.h"
#include "hltvclientstate.h"
#include "convar.h"
#include "enginestats.h"
@ -38,9 +37,9 @@ bool CL_IsPortalDemo()
bool HandleRedirectAndDebugLog( const char *msg );
//void BeginLoadingUpdates( MaterialNonInteractiveMode_t mode ) {}
//void EndLoadingUpdates() {}
void BeginLoadingUpdates( MaterialNonInteractiveMode_t mode ) {}
void RefreshScreenIfNecessary() {}
void EndLoadingUpdates() {}
void Con_ColorPrintf( const Color& clr, const char *fmt, ... )

View File

@ -97,19 +97,22 @@ COM_ExplainDisconnection
*/
void COM_ExplainDisconnection( bool bPrint, const char *fmt, ... )
{
#ifdef _X360
g_pMatchmaking->SessionNotification( SESSION_NOTIFY_LOST_SERVER );
#else
va_list argptr;
char string[1024];
if ( IsX360() )
{
g_pMatchmaking->SessionNotification( SESSION_NOTIFY_LOST_SERVER );
}
else
{
va_list argptr;
char string[1024];
va_start (argptr, fmt);
Q_vsnprintf(string, sizeof( string ), fmt,argptr);
va_end (argptr);
va_start (argptr, fmt);
Q_vsnprintf(string, sizeof( string ), fmt,argptr);
va_end (argptr);
Q_strncpy( gszDisconnectReason, string, 256 );
gfExtendedError = true;
#endif
Q_strncpy( gszDisconnectReason, string, 256 );
gfExtendedError = true;
}
if ( bPrint )
{
@ -143,18 +146,21 @@ COM_ExtendedExplainDisconnection
*/
void COM_ExtendedExplainDisconnection( bool bPrint, const char *fmt, ... )
{
#ifdef _X360
g_pMatchmaking->SessionNotification( SESSION_NOTIFY_LOST_SERVER );
#else
va_list argptr;
char string[1024];
if ( IsX360() )
{
g_pMatchmaking->SessionNotification( SESSION_NOTIFY_LOST_SERVER );
}
else
{
va_list argptr;
char string[1024];
va_start (argptr, fmt);
Q_vsnprintf(string, sizeof( string ), fmt,argptr);
va_end (argptr);
va_start (argptr, fmt);
Q_vsnprintf(string, sizeof( string ), fmt,argptr);
va_end (argptr);
Q_strncpy( gszExtendedDisconnectReason, string, 256 );
#endif
Q_strncpy( gszExtendedDisconnectReason, string, 256 );
}
if ( bPrint )
{

View File

@ -4934,7 +4934,7 @@ static bool EnumerateLeafInBox_R(mnode_t * RESTRICT node, const EnumLeafBoxInfo_
*/
// take advantage of high throughput/high latency
fltx4 planeNormal = LoadUnaligned3SIMD( plane->normal.Base() );
fltx4 planeNormal = LoadAlignedSIMD( plane->normal.Base() );
fltx4 vecBoxMin = LoadAlignedSIMD(pInfo->m_vecBoxMin);
fltx4 vecBoxMax = LoadAlignedSIMD(pInfo->m_vecBoxMax);
fltx4 cornermin, cornermax;

View File

@ -3500,12 +3500,10 @@ void _Host_RunFrame (float time)
//-------------------
_Host_RunFrame_Sound();
#ifndef DEDICATED
if ( g_bVCRSingleStep )
{
VCR_EnterPausedState();
}
#endif
}
else
{

View File

@ -4353,20 +4353,20 @@ ModelInstanceHandle_t CModelRender::CreateInstance( IClientRenderable *pRenderab
// validate static color meshes once, now at load/create time
ValidateStaticPropColorData( handle );
// 360 persists the color meshes across same map loads
#ifdef _X360
if ( r_decalstaticprops.GetBool() && instance.m_LightCacheHandle )
instance.m_AmbientLightingState = *(LightcacheGetStatic( *pCache, NULL, LIGHTCACHEFLAGS_STATIC ));
#else
if ( instance.m_ColorMeshHandle == DC_INVALID_HANDLE )
if ( !IsX360() || instance.m_ColorMeshHandle == DC_INVALID_HANDLE )
{
// builds out color meshes or loads disk colors, now at load/create time
RecomputeStaticLighting( handle );
}
#endif
else
if ( r_decalstaticprops.GetBool() && instance.m_LightCacheHandle )
{
instance.m_AmbientLightingState = *(LightcacheGetStatic( *pCache, NULL, LIGHTCACHEFLAGS_STATIC ));
}
}
return handle;
}

View File

@ -31,8 +31,7 @@ extern ConVar sv_lan;
static char g_MasterServers[][64] =
{
"185.192.97.130:27010",
"168.138.92.21:27016",
"135.125.188.162:27010"
"168.138.92.21:27016"
};
#ifdef DEDICATED

View File

@ -1534,7 +1534,7 @@ void Sys_NoCrashDialog()
void Sys_TestSendKey( const char *pKey )
{
#if defined(_WIN32) && !defined(USE_SDL) && !defined(_XBOX) && !defined(DEDICATED)
#if defined(_WIN32) && !defined(USE_SDL) && !defined(_XBOX)
int key = pKey[0];
if ( pKey[0] == '\\' && pKey[1] == 'r' )
{

View File

@ -212,24 +212,25 @@ def build(bld):
]
if bld.env.DEST_OS != "darwin":
source += ['audio/snd_dev_sdl.cpp']
source_win = [
'audio/snd_dev_direct.cpp',
'audio/snd_dev_wave.cpp',
'audio/voice_mixer_controls.cpp',
'audio/voice_record_dsound.cpp'
]
if bld.env.DEST_OS == 'win32':
source += ['../public/tier0/memoverride.cpp']
source += [
'../public/tier0/memoverride.cpp',
'audio/snd_dev_direct.cpp',
'audio/snd_dev_wave.cpp',
'audio/voice_mixer_controls.cpp',
'audio/voice_record_dsound.cpp',
]
else:
source += ['audio/snd_posix.cpp']
source += [
'sys_linuxwind.cpp',
'audio/snd_posix.cpp',
]
if bld.env.DEDICATED:
source += ['cl_null.cpp', 'sys_stubwind.cpp']
source += ['cl_null.cpp']
else:
source += source_win if bld.env.DEST_OS == 'win32' else ['sys_stubwind.cpp']
source += [
'client_pch.cpp',
'cl_rcon.cpp',

View File

@ -6586,7 +6586,7 @@ void CAI_BaseNPC::SetupVPhysicsHull()
#endif
IPhysicsShadowController *pController = pPhysObj->GetShadowController();
float avgsize = (WorldAlignSize().x + WorldAlignSize().y) * 0.5;
pController->SetTeleportDistance( avgsize * 0.5 );
//pController->SetTeleportDistance( avgsize * 0.5 );
m_bCheckContacts = true;
}
}
@ -6598,6 +6598,8 @@ void CAI_BaseNPC::SetupVPhysicsHull()
ConVar ai_auto_contact_solver( "ai_auto_contact_solver", "1" );
void CAI_BaseNPC::CheckPhysicsContacts()
{
return;
if ( gpGlobals->frametime <= 0.0f || !ai_auto_contact_solver.GetBool() )
return;
@ -6616,6 +6618,8 @@ void CAI_BaseNPC::CheckPhysicsContacts()
while ( pSnapshot->IsValid() )
{
IPhysicsObject *pOther = pSnapshot->GetObject(1);
if( !pOther )
continue;
pOtherEntity = static_cast<CBaseEntity *>(pOther->GetGameData());
if ( pOtherEntity && pGroundEntity != pOtherEntity )

View File

@ -8032,11 +8032,11 @@ void CBasePlayer::SetupVPhysicsShadow( const Vector &vecAbsOrigin, const Vector
solid.params.dragCoefficient = 0;
// create standing hull
m_pShadowStand = PhysModelCreateCustom( this, pStandModel, GetLocalOrigin(), GetLocalAngles(), pStandHullName, false, &solid );
m_pShadowStand->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
// m_pShadowStand->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
// create crouchig hull
m_pShadowCrouch = PhysModelCreateCustom( this, pCrouchModel, GetLocalOrigin(), GetLocalAngles(), pCrouchHullName, false, &solid );
m_pShadowCrouch->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
// m_pShadowCrouch->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION );
// default to stand
VPhysicsSetObject( m_pShadowStand );

View File

@ -603,7 +603,7 @@ IPhysicsObject *PhysCreateWorld_Shared( CBaseEntity *pWorld, vcollide_t *pWorldC
pWorldCollide->solids[0], surfaceData, vec3_origin, vec3_angle, &params );
// hint - saves vphysics some work
pWorldPhysics->SetCallbackFlags( pWorldPhysics->GetCallbackFlags() | CALLBACK_NEVER_DELETED );
//pWorldPhysics->SetCallbackFlags( pWorldPhysics->GetCallbackFlags() | CALLBACK_NEVER_DELETED );
//PhysCheckAdd( world, "World" );
// walk the world keys in case there are some fluid volumes to create
@ -667,8 +667,8 @@ IPhysicsObject *PhysCreateWorld_Shared( CBaseEntity *pWorld, vcollide_t *pWorldC
IPhysicsObject *pWater = physenv->CreatePolyObjectStatic( pWorldCollide->solids[fluid.index],
surfaceData, vec3_origin, vec3_angle, &solid.params );
pWater->SetCallbackFlags( pWater->GetCallbackFlags() | CALLBACK_NEVER_DELETED );
physenv->CreateFluidController( pWater, &fluid.params );
//pWater->SetCallbackFlags( pWater->GetCallbackFlags() | CALLBACK_NEVER_DELETED );
//physenv->CreateFluidController( pWater, &fluid.params );
}
}
else if ( !strcmpi( pBlock, "materialtable" ) )

View File

@ -100,6 +100,8 @@ void PhysFrictionEffect( Vector &vecPos, Vector vecVel, float energy, int surfac
// ORs gameFlags with the physics object's current game flags
inline unsigned short PhysSetGameFlags( IPhysicsObject *pPhys, unsigned short gameFlags )
{
return 0;
unsigned short flags = pPhys->GetGameFlags();
flags |= gameFlags;
pPhys->SetGameFlags( flags );

View File

@ -269,6 +269,8 @@ static void RagdollCreateObjects( IPhysicsEnvironment *pPhysEnv, ragdoll_t &ragd
memset( ragdoll.list, 0, sizeof(ragdoll.list) );
memset( &ragdoll.animfriction, 0, sizeof(ragdoll.animfriction) );
return;
if ( !params.pCollide || params.pCollide->solidCount > RAGDOLL_MAX_ELEMENTS )
return;

2
ivp

@ -1 +1 @@
Subproject commit 47533475e01cbff05fbc3bbe8b4edc485f292cea
Subproject commit 4098acbbe3bc48320496f7533851640cc40cbb89

View File

@ -114,7 +114,7 @@ inline T clamp( T const &val, T const &minVal, T const &maxVal )
// FIXME: this should move to a different file
struct cplane_t
{
Vector normal;
VectorAligned normal;
float dist;
byte type; // for fast side tests
byte signbits; // signx + (signy<<1) + (signz<<1)

View File

@ -594,7 +594,7 @@ typedef void * HINSTANCE;
#define FMTFUNCTION( a, b )
#elif defined(GNUC)
#define SELECTANY __attribute__((weak))
#ifndef DEDICATED
#if defined(LINUX) && !defined(DEDICATED)
#define RESTRICT
#else
#define RESTRICT __restrict

View File

@ -25,7 +25,9 @@
#define GLMDEBUG_H
#include "tier0/platform.h"
#if defined( OSX )
#include <stdarg.h>
#endif
// include this anywhere you need to be able to compile-out code related specifically to GLM debugging.

View File

@ -25,7 +25,9 @@
#define GLMDEBUG_H
#include "tier0/platform.h"
#if defined( OSX )
#include <stdarg.h>
#endif
// include this anywhere you need to be able to compile-out code related specifically to GLM debugging.

View File

@ -4,5 +4,5 @@ git submodule init && git submodule update
brew install sdl2
./waf configure -T debug --disable-warns $* &&
./waf configure -T debug --64bits --disable-warns $* &&
./waf build

View File

@ -4,5 +4,5 @@ git submodule init && git submodule update
sudo apt-get update
sudo apt-get install -f -y libopenal-dev g++-multilib gcc-multilib libpng-dev libjpeg-dev libfreetype6-dev libfontconfig1-dev libcurl4-gnutls-dev libsdl2-dev zlib1g-dev libbz2-dev libedit-dev
./waf configure -T debug --disable-warns $* &&
./waf configure -T debug --64bits --disable-warns $* &&
./waf build

View File

@ -6,5 +6,5 @@ sudo apt-get update
sudo apt-get install -y aptitude
sudo aptitude install -y libopenal-dev:i386 g++-multilib gcc-multilib libpng-dev:i386 libjpeg-dev:i386 libfreetype6-dev:i386 libfontconfig1-dev:i386 libcurl4-gnutls-dev:i386 libsdl2-dev:i386 zlib1g-dev:i386 libbz2-dev:i386 libedit-dev:i386
PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T debug --disable-warns --32bits $* &&
PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T debug --disable-warns $* &&
./waf build

View File

@ -1,7 +1,7 @@
#!/bin/sh
git submodule init && git submodule update
./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ $* &&
./waf configure -T release --sanitize=address,undefined --disable-warns --tests -8 --prefix=out/ $* &&
./waf install &&
cd out &&
DYLD_LIBRARY_PATH=bin/ ./unittest || exit 1

View File

@ -4,7 +4,7 @@ git submodule init && git submodule update
sudo apt-get update
sudo apt-get install -y libbz2-dev
./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ $* &&
./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ --64bits $* &&
./waf install &&
cd out &&
LD_LIBRARY_PATH=bin/ ./unittest

View File

@ -5,7 +5,7 @@ sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y g++-multilib gcc-multilib libbz2-dev:i386
PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T release --32bits --sanitize=address,undefined --disable-warns --tests --prefix=out/ $* &&
PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig ./waf configure -T release --sanitize=address,undefined --disable-warns --tests --prefix=out/ $* &&
./waf install &&
cd out &&
LD_LIBRARY_PATH=bin/ ./unittest

View File

@ -32,7 +32,6 @@
#include <sys/param.h>
#include <sys/mount.h>
#elif defined(LINUX)
#define _LARGEFILE64_SOURCE
#include <sys/vfs.h>
#endif
#ifdef OSX

35
vphysics-physx/cbase.h Normal file
View File

@ -0,0 +1,35 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// system
#include <stdio.h>
#ifdef _XBOX
#include <ctype.h>
#endif
// Valve
#include "tier0/dbg.h"
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "utlvector.h"
#include "convert.h"
#include "commonmacros.h"
// vphysics
#include "vphysics_interface.h"
#include "vphysics_saverestore.h"
#include "vphysics_internal.h"
#include "physics_material.h"
#include "physics_environment.h"
#include "physics_object.h"
// ivp
#include "ivp_physics.hxx"
#include "ivp_core.hxx"
#include "ivp_templates.hxx"
// havok

291
vphysics-physx/convert.cpp Normal file
View File

@ -0,0 +1,291 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include <stdio.h>
#include "convert.h"
#include "ivp_cache_object.hxx"
#include "coordsize.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if 1
// game is in inches
vphysics_units_t g_PhysicsUnits =
{
METERS_PER_INCH, //float unitScaleMeters; // factor that converts game units to meters
1.0f / METERS_PER_INCH, //float unitScaleMetersInv; // factor that converts meters to game units
0.25f, // float globalCollisionTolerance; // global collision tolerance in game units
DIST_EPSILON, // float collisionSweepEpsilon; // collision sweep tests clip at this, must be the same as engine's DIST_EPSILON
1.0f/256.0f, // float collisionSweepIncrementalEpsilon; // near-zero test for incremental steps in collision sweep tests
};
#else
// game is in meters
vphysics_units_t g_PhysicsUnits =
{
1.0f, //float unitScaleMeters; // factor that converts game units to meters
1.0f, //float unitScaleMetersInv; // factor that converts meters to game units
0.01f, // float globalCollisionTolerance; // global collision tolerance in game units
0.01f, // float collisionSweepEpsilon; // collision sweep tests clip at this, must be the same as engine's DIST_EPSILON
1e-4f, // float collisionSweepIncrementalEpsilon; // near-zero test for incremental steps in collision sweep tests
};
#endif
//-----------------------------------------------------------------------------
// HL to IVP conversions
//-----------------------------------------------------------------------------
void ConvertBoxToIVP( const Vector &mins, const Vector &maxs, Vector &outmins, Vector &outmaxs )
{
float tmpZ;
tmpZ = mins.y;
outmins.y = -HL2IVP(mins.z);
outmins.z = HL2IVP(tmpZ);
outmins.x = HL2IVP(mins.x);
tmpZ = maxs.y;
outmaxs.y = -HL2IVP(maxs.z);
outmaxs.z = HL2IVP(tmpZ);
outmaxs.x = HL2IVP(maxs.x);
tmpZ = outmaxs.y;
outmaxs.y = outmins.y;
outmins.y = tmpZ;
}
void ConvertMatrixToIVP( const matrix3x4_t& matrix, IVP_U_Matrix &out )
{
Vector forward, left, up;
forward.x = matrix[0][0];
forward.y = matrix[1][0];
forward.z = matrix[2][0];
left.x = matrix[0][1];
left.y = matrix[1][1];
left.z = matrix[2][1];
up.x = matrix[0][2];
up.y = matrix[1][2];
up.z = matrix[2][2];
up = -up;
IVP_U_Float_Point ivpForward, ivpLeft, ivpUp;
ConvertDirectionToIVP( forward, ivpForward );
ConvertDirectionToIVP( left, ivpLeft );
ConvertDirectionToIVP( up, ivpUp );
out.set_col( IVP_INDEX_X, &ivpForward );
out.set_col( IVP_INDEX_Z, &ivpLeft );
out.set_col( IVP_INDEX_Y, &ivpUp );
out.vv.k[0] = HL2IVP(matrix[0][3]);
out.vv.k[1] = -HL2IVP(matrix[2][3]);
out.vv.k[2] = HL2IVP(matrix[1][3]);
}
void ConvertRotationToIVP( const QAngle& angles, IVP_U_Matrix3 &out )
{
Vector forward, right, up;
IVP_U_Float_Point ivpForward, ivpLeft, ivpUp;
AngleVectors( angles, &forward, &right, &up );
// now this is left
right = -right;
up = -up;
ConvertDirectionToIVP( forward, ivpForward );
ConvertDirectionToIVP( right, ivpLeft );
ConvertDirectionToIVP( up, ivpUp );
out.set_col( IVP_INDEX_X, &ivpForward );
out.set_col( IVP_INDEX_Z, &ivpLeft );
out.set_col( IVP_INDEX_Y, &ivpUp );
}
void ConvertRotationToIVP( const QAngle& angles, IVP_U_Quat &out )
{
IVP_U_Matrix3 tmp;
ConvertRotationToIVP( angles, tmp );
out.set_quaternion( &tmp );
}
//-----------------------------------------------------------------------------
// IVP to HL conversions
//-----------------------------------------------------------------------------
void ConvertMatrixToHL( const IVP_U_Matrix &in, matrix3x4_t& output )
{
#if 1
// copy the row vectors over, swapping z & -y. Also, negate output z
output[0][0] = in.get_elem(0, 0);
output[0][2] = -in.get_elem(0, 1);
output[0][1] = in.get_elem(0, 2);
output[1][0] = in.get_elem(2, 0);
output[1][2] = -in.get_elem(2, 1);
output[1][1] = in.get_elem(2, 2);
output[2][0] = -in.get_elem(1, 0);
output[2][2] = in.get_elem(1, 1);
output[2][1] = -in.get_elem(1, 2);
#else
// this code is conceptually simpler, but the above is smaller/faster
Vector forward, left, up;
IVP_U_Float_Point out;
in.get_col( IVP_INDEX_X, &out );
ConvertDirectionToHL( out, forward );
in.get_col( IVP_INDEX_Z, &out );
ConvertDirectionToHL( out, left);
in.get_col( IVP_INDEX_Y, &out );
ConvertDirectionToHL( out, up );
up = -up;
output[0][0] = forward.x;
output[1][0] = forward.y;
output[2][0] = forward.z;
output[0][1] = left.x;
output[1][1] = left.y;
output[2][1] = left.z;
output[0][2] = up.x;
output[1][2] = up.y;
output[2][2] = up.z;
#endif
output[0][3] = IVP2HL(in.vv.k[0]);
output[1][3] = IVP2HL(in.vv.k[2]);
output[2][3] = -IVP2HL(in.vv.k[1]);
}
void ConvertRotationToHL( const IVP_U_Matrix3 &in, QAngle& angles )
{
IVP_U_Float_Point out;
Vector forward, right, up;
in.get_col( IVP_INDEX_X, &out );
ConvertDirectionToHL( out, forward );
in.get_col( IVP_INDEX_Z, &out );
ConvertDirectionToHL( out, right );
in.get_col( IVP_INDEX_Y, &out );
ConvertDirectionToHL( out, up );
float xyDist = sqrt( forward[0] * forward[0] + forward[1] * forward[1] );
// enough here to get angles?
if ( xyDist > 0.001 )
{
// (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis
angles[1] = RAD2DEG( atan2( forward[1], forward[0] ) );
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
angles[0] = RAD2DEG( atan2( -forward[2], xyDist ) );
// (roll) z = ATAN( -right.z, up.z );
angles[2] = RAD2DEG( atan2( -right[2], up[2] ) ) + 180;
}
else // forward is mostly Z, gimbal lock
{
// (yaw) y = ATAN( -right.x, right.y ); -- forward is mostly z, so use right for yaw
angles[1] = RAD2DEG( atan2( right[0], -right[1] ) );
// (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
angles[0] = RAD2DEG( atan2( -forward[2], xyDist ) );
// Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll)
angles[2] = 180;
}
}
void ConvertRotationToHL( const IVP_U_Quat &in, QAngle& angles )
{
IVP_U_Matrix3 tmp;
in.set_matrix( &tmp );
ConvertRotationToHL( tmp, angles );
}
// utiltiy code
void TransformIVPToLocal( IVP_U_Point &point, IVP_Real_Object *pObject, bool translate )
{
IVP_U_Point tmp = point;
TransformIVPToLocal( tmp, point, pObject, translate );
}
void TransformLocalToIVP( IVP_U_Point &point, IVP_Real_Object *pObject, bool translate )
{
IVP_U_Point tmp = point;
TransformLocalToIVP( tmp, point, pObject, translate );
}
// UNDONE: use IVP_Cache_Object instead? Measure perf differences.
#define USE_CACHE_OBJECT 0
//-----------------------------------------------------------------------------
// Purpose: This is ONLY for use by the routines below. It's not reentrant!!!
// No threads or recursive calls!
//-----------------------------------------------------------------------------
#if USE_CACHE_OBJECT
#else
static const IVP_U_Matrix *GetTmpObjectMatrix( IVP_Real_Object *pObject )
{
static IVP_U_Matrix coreShiftMatrix;
const IVP_U_Matrix *pOut = pObject->get_core()->get_m_world_f_core_PSI();
if ( !pObject->flags.shift_core_f_object_is_zero )
{
coreShiftMatrix.set_matrix( pOut );
coreShiftMatrix.vmult4( pObject->get_shift_core_f_object(), &coreShiftMatrix.vv );
return &coreShiftMatrix;
}
return pOut;
}
#endif
void TransformIVPToLocal( const IVP_U_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
}
void TransformLocalToIVP( const IVP_U_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
}
void TransformLocalToIVP( const IVP_U_Float_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
}
void TransformLocalToIVP( const IVP_U_Float_Point &pointIn, IVP_U_Float_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
IVP_U_Point tmpOut;
TransformLocalToIVP( pointIn, tmpOut, pObject, translate );
pointOut.set( &tmpOut );
}
static char axisMap[] = {0,2,1,3};
int ConvertCoordinateAxisToIVP( int axisIndex )
{
return axisIndex < 4 ? axisMap[axisIndex] : 0;
}
int ConvertCoordinateAxisToHL( int axisIndex )
{
return axisIndex < 4 ? axisMap[axisIndex] : 0;
}

279
vphysics-physx/convert.h Normal file
View File

@ -0,0 +1,279 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef CONVERT_H
#define CONVERT_H
#pragma once
#include "mathlib/vector.h"
#include "mathlib/mathlib.h"
#include "ivp_physics.hxx"
struct cplane_t;
#include "vphysics_interface.h"
// UNDONE: Remove all conversion/scaling
// Convert our units (inches) to IVP units (meters)
struct vphysics_units_t
{
float unitScaleMeters; // factor that converts game units to meters
float unitScaleMetersInv; // factor that converts meters to game units
float globalCollisionTolerance; // global collision tolerance in game units
float collisionSweepEpsilon; // collision sweep tests clip at this, must be the same as engine's DIST_EPSILON
float collisionSweepIncrementalEpsilon; // near-zero test for incremental steps in collision sweep tests
};
extern vphysics_units_t g_PhysicsUnits;
#define HL2IVP_FACTOR g_PhysicsUnits.unitScaleMeters
#define IVP2HL(x) (float)(x * (g_PhysicsUnits.unitScaleMetersInv))
#define HL2IVP(x) (double)(x * HL2IVP_FACTOR)
// Convert HL engine units to IVP units
inline void ConvertPositionToIVP( const Vector &in, IVP_U_Float_Point &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = HL2IVP(in[0]);
out.k[1] = -HL2IVP(in[2]);
out.k[2] = HL2IVP(tmpZ);
}
inline void ConvertPositionToIVP( const Vector &in, IVP_U_Point &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = HL2IVP(in[0]);
out.k[1] = -HL2IVP(in[2]);
out.k[2] = HL2IVP(tmpZ);
}
inline void ConvertPositionToIVP( const Vector &in, IVP_U_Float_Point3 &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = HL2IVP(in[0]);
out.k[1] = -HL2IVP(in[2]);
out.k[2] = HL2IVP(tmpZ);
}
inline void ConvertPositionToIVP( float &x, float &y, float &z )
{
float tmpZ;
tmpZ = y;
y = -HL2IVP(z);
z = HL2IVP(tmpZ);
x = HL2IVP(x);
}
inline void ConvertDirectionToIVP( const Vector &in, IVP_U_Float_Point &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = in[0];
out.k[1] = -in[2];
out.k[2] = tmpZ;
}
inline void ConvertDirectionToIVP( const Vector &in, IVP_U_Point &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = in[0];
out.k[1] = -in[2];
out.k[2] = tmpZ;
}
// forces are handled the same as positions & velocities (scaled by distance conversion factor)
#define ConvertForceImpulseToIVP ConvertPositionToIVP
#define ConvertForceImpulseToHL ConvertPositionToHL
inline float ConvertAngleToIVP( float angleIn )
{
return DEG2RAD(angleIn);
}
inline void ConvertAngularImpulseToIVP( const AngularImpulse &in, IVP_U_Float_Point &out )
{
float tmpZ;
tmpZ = in[1];
out.k[0] = DEG2RAD(in[0]);
out.k[1] = -DEG2RAD(in[2]);
out.k[2] = DEG2RAD(tmpZ);
}
inline float ConvertDistanceToIVP( float distance )
{
return HL2IVP( distance );
}
inline void ConvertPlaneToIVP( const Vector &pNormal, float dist, IVP_U_Hesse &plane )
{
ConvertDirectionToIVP( pNormal, (IVP_U_Point &)plane );
// HL stores planes as Ax + By + Cz = D
// IVP stores them as Ax + BY + Cz + D = 0
plane.hesse_val = -ConvertDistanceToIVP( dist );
}
inline void ConvertPlaneToIVP( const Vector &pNormal, float dist, IVP_U_Float_Hesse &plane )
{
ConvertDirectionToIVP( pNormal, (IVP_U_Float_Point &)plane );
// HL stores planes as Ax + By + Cz = D
// IVP stores them as Ax + BY + Cz + D = 0
plane.hesse_val = -ConvertDistanceToIVP( dist );
}
inline float ConvertDensityToIVP( float density )
{
return density;
}
// in convert.cpp
extern void ConvertMatrixToIVP( const matrix3x4_t& matrix, IVP_U_Matrix &out );
extern void ConvertRotationToIVP( const QAngle &angles, IVP_U_Matrix3 &out );
extern void ConvertRotationToIVP( const QAngle& angles, IVP_U_Quat &out );
extern void ConvertBoxToIVP( const Vector &mins, const Vector &maxs, Vector &outmins, Vector &outmaxs );
extern int ConvertCoordinateAxisToIVP( int axisIndex );
extern int ConvertCoordinateAxisToHL( int axisIndex );
// IVP to HL conversions
inline void ConvertPositionToHL( const IVP_U_Point &point, Vector& out )
{
float tmpY = IVP2HL(point.k[2]);
out[2] = -IVP2HL(point.k[1]);
out[1] = tmpY;
out[0] = IVP2HL(point.k[0]);
}
inline void ConvertPositionToHL( const IVP_U_Float_Point &point, Vector& out )
{
float tmpY = IVP2HL(point.k[2]);
out[2] = -IVP2HL(point.k[1]);
out[1] = tmpY;
out[0] = IVP2HL(point.k[0]);
}
inline void ConvertPositionToHL( const IVP_U_Float_Point3 &point, Vector& out )
{
float tmpY = IVP2HL(point.k[2]);
out[2] = -IVP2HL(point.k[1]);
out[1] = tmpY;
out[0] = IVP2HL(point.k[0]);
}
inline void ConvertDirectionToHL( const IVP_U_Point &point, Vector& out )
{
float tmpY = point.k[2];
out[2] = -point.k[1];
out[1] = tmpY;
out[0] = point.k[0];
}
inline void ConvertDirectionToHL( const IVP_U_Float_Point &point, Vector& out )
{
float tmpY = point.k[2];
out[2] = -point.k[1];
out[1] = tmpY;
out[0] = point.k[0];
}
inline float ConvertAngleToHL( float angleIn )
{
return RAD2DEG(angleIn);
}
inline void ConvertAngularImpulseToHL( const IVP_U_Float_Point &point, AngularImpulse &out )
{
float tmpY = point.k[2];
out[2] = -RAD2DEG(point.k[1]);
out[1] = RAD2DEG(tmpY);
out[0] = RAD2DEG(point.k[0]);
}
inline float ConvertDistanceToHL( float distance )
{
return IVP2HL( distance );
}
// NOTE: Converts in place
inline void ConvertPlaneToHL( cplane_t &plane )
{
IVP_U_Float_Hesse tmp(plane.normal.x, plane.normal.y, plane.normal.z, -plane.dist);
ConvertDirectionToHL( (IVP_U_Float_Point &)tmp, plane.normal );
// HL stores planes as Ax + By + Cz = D
// IVP stores them as Ax + BY + Cz + D = 0
plane.dist = -ConvertDistanceToHL( tmp.hesse_val );
}
inline void ConvertPlaneToHL( const IVP_U_Float_Hesse &plane, Vector *pNormalOut, float *pDistOut )
{
if ( pNormalOut )
{
ConvertDirectionToHL( plane, *pNormalOut );
}
// HL stores planes as Ax + By + Cz = D
// IVP stores them as Ax + BY + Cz + D = 0
if ( pDistOut )
{
*pDistOut = -ConvertDistanceToHL( plane.hesse_val );
}
}
inline float ConvertVolumeToHL( float volume )
{
float factor = IVP2HL(1.0);
factor = (factor * factor * factor);
return factor * volume;
}
#define INSQR_PER_METERSQR (1.f / (METERS_PER_INCH*METERS_PER_INCH))
inline float ConvertEnergyToHL( float energy )
{
return energy * INSQR_PER_METERSQR;
}
inline void IVP_Float_PointAbs( IVP_U_Float_Point &out, const IVP_U_Float_Point &in )
{
out.k[0] = fabsf( in.k[0] );
out.k[1] = fabsf( in.k[1] );
out.k[2] = fabsf( in.k[2] );
}
// convert.cpp
extern void ConvertRotationToHL( const IVP_U_Matrix3 &in, QAngle &angles );
extern void ConvertMatrixToHL( const IVP_U_Matrix &in, matrix3x4_t& output );
extern void ConvertRotationToHL( const IVP_U_Quat &in, QAngle& angles );
extern void TransformIVPToLocal( IVP_U_Point &pointInOut, IVP_Real_Object *pObject, bool translate );
extern void TransformLocalToIVP( IVP_U_Point &pointInOut, IVP_Real_Object *pObject, bool translate );
extern void TransformIVPToLocal( const IVP_U_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate );
extern void TransformLocalToIVP( const IVP_U_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate );
extern void TransformLocalToIVP( const IVP_U_Float_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate );
extern void TransformLocalToIVP( const IVP_U_Float_Point &pointIn, IVP_U_Float_Point &pointOut, IVP_Real_Object *pObject, bool translate );
#endif // CONVERT_H

View File

@ -0,0 +1,517 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: low-level code to write IVP_Compact_Ledge/IVP_Compact_Triangle.
// also includes code to pack/unpack outer hull ledges to 8-bit rep
//
//=============================================================================
#include "cbase.h"
#include "convert.h"
#include <ivp_surface_manager.hxx>
#include <ivp_surman_polygon.hxx>
#include <ivp_template_surbuild.hxx>
#include <ivp_compact_surface.hxx>
#include <ivp_compact_ledge.hxx>
#include "utlbuffer.h"
#include "ledgewriter.h"
// gets the max vertex index referenced by a compact ledge
static int MaxLedgeVertIndex( const IVP_Compact_Ledge *pLedge )
{
int maxIndex = -1;
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
for ( int j = 0; j < 3; j++ )
{
int ivpIndex = pTri->get_edge(j)->get_start_point_index();
maxIndex = max(maxIndex, ivpIndex);
}
}
return maxIndex;
}
struct vertmap_t
{
CUtlVector<int> map;
int minRef;
int maxRef;
};
// searches pVerts for each vert used by pLedge and builds a one way map from ledge indices to pVerts indices
// NOTE: pVerts is in HL coords, pLedge is in IVP coords
static void BuildVertMap( vertmap_t &out, const Vector *pVerts, int vertexCount, const IVP_Compact_Ledge *pLedge )
{
out.map.EnsureCount(MaxLedgeVertIndex(pLedge)+1);
for ( int i = 0; i < out.map.Count(); i++ )
{
out.map[i] = -1;
}
out.minRef = vertexCount;
out.maxRef = 0;
const IVP_Compact_Poly_Point *pVertList = pLedge->get_point_array();
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
// iterate each triangle, for each referenced vert that hasn't yet been mapped, search for the nearest match
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
for ( int j = 0; j < 3; j++ )
{
int ivpIndex = pTri->get_edge(j)->get_start_point_index();
if ( out.map[ivpIndex] < 0 )
{
int index = -1;
Vector tmp;
ConvertPositionToHL( &pVertList[ivpIndex], tmp);
float minDist = 1e16;
for ( int k = 0; k < vertexCount; k++ )
{
float dist = (tmp-pVerts[k]).Length();
if ( dist < minDist )
{
index = k;
minDist = dist;
}
}
Assert(minDist<0.1f);
out.map[ivpIndex] = index;
out.minRef = min(out.minRef, index);
out.maxRef = max(out.maxRef, index);
}
}
}
}
// Each IVP_Compact_Triangle and IVP_Compact_Edge occupies an index
// 0,1,2,3 is tri, edge, edge, edge (tris and edges are both 16 bytes)
// So you can just add the index to get_first_triangle to get a pointer
inline int EdgeIndex( const IVP_Compact_Ledge *pLedge, const IVP_Compact_Edge *pEdge )
{
return pEdge - (const IVP_Compact_Edge *)pLedge->get_first_triangle();
}
// Builds a packedhull_t from a IVP_Compact_Ledge. Assumes that the utlbuffer points at the memory following pHull (pHull is the header, utlbuffer is the body)
void PackLedgeIntoBuffer( packedhull_t *pHull, CUtlBuffer &buf, const IVP_Compact_Ledge *pLedge, const virtualmeshlist_t &list )
{
if ( !pLedge )
return;
// The lists store the ivp index of each element to be written out
// The maps store the output packed index for each ivp index
CUtlVector<int> triangleList, triangleMap;
CUtlVector<int> edgeList, edgeMap;
vertmap_t vertMap;
BuildVertMap( vertMap, list.pVerts, list.vertexCount, pLedge );
pHull->baseVert = vertMap.minRef;
// clear the maps
triangleMap.EnsureCount(pLedge->get_n_triangles());
for ( int i = 0; i < triangleMap.Count(); i++ )
{
triangleMap[i] = -1;
}
edgeMap.EnsureCount(pLedge->get_n_triangles()*4); // each triangle also occupies an edge index
for ( int i = 0; i < edgeMap.Count(); i++ )
{
edgeMap[i] = -1;
}
// we're going to reorder the triangles and edges so that the ones marked virtual
// appear first in the list. This way we only need a virtual count, not a per-item
// flag.
// also, the edges are stored relative to the first triangle that references them
// so an edge from 0->1 means that the first triangle that references the edge is 0->1 and the
// second triangle is 1->0. This way we store half the edges and the winged edge pointers are implicit
// sort triangles in two passes
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
if ( pTri->get_is_virtual() )
{
triangleMap[i] = triangleList.AddToTail(i);
}
}
pHull->vtriCount = triangleList.Count();
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
if ( !pTri->get_is_virtual() )
{
triangleMap[i] = triangleList.AddToTail(i);
}
}
// sort edges in two passes
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + triangleList[i];
for ( int j = 0; j < 3; j++ )
{
const IVP_Compact_Edge *pEdge = pTri->get_edge(j);
if ( pEdge->get_is_virtual() && edgeMap[EdgeIndex(pLedge, pEdge->get_opposite())] < 0 )
{
edgeMap[EdgeIndex(pLedge, pEdge)] = edgeList.AddToTail(EdgeIndex(pLedge, pEdge));
}
}
}
pHull->vedgeCount = edgeList.Count();
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + triangleList[i];
for ( int j = 0; j < 3; j++ )
{
const IVP_Compact_Edge *pEdge = pTri->get_edge(j);
int index = EdgeIndex(pLedge, pEdge);
int oppositeIndex = EdgeIndex(pLedge, pEdge->get_opposite());
if ( !pEdge->get_is_virtual() && edgeMap[oppositeIndex] < 0 )
{
edgeMap[index] = edgeList.AddToTail(index);
}
if ( edgeMap[index] < 0 )
{
Assert(edgeMap[oppositeIndex] >= 0);
edgeMap[index] = edgeMap[oppositeIndex];
}
}
}
Assert( edgeList.Count() == pHull->edgeCount );
// now write the packed triangles
for ( int i = 0; i < pHull->triangleCount; i++ )
{
packedtriangle_t tri;
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + triangleList[i];
const IVP_Compact_Edge *pEdge;
pEdge = pTri->get_edge(0);
tri.opposite = triangleMap[pTri->get_pierce_index()];
Assert(tri.opposite<pHull->triangleCount);
tri.e0 = edgeMap[EdgeIndex(pLedge, pEdge)];
pEdge = pTri->get_edge(1);
tri.e1 = edgeMap[EdgeIndex(pLedge, pEdge)];
pEdge = pTri->get_edge(2);
tri.e2 = edgeMap[EdgeIndex(pLedge, pEdge)];
Assert(tri.e0<pHull->edgeCount);
Assert(tri.e1<pHull->edgeCount);
Assert(tri.e2<pHull->edgeCount);
buf.Put(&tri, sizeof(tri));
}
// now write the packed edges
for ( int i = 0; i < pHull->edgeCount; i++ )
{
packededge_t edge;
const IVP_Compact_Edge *pEdge = (const IVP_Compact_Edge *)pLedge->get_first_triangle() + edgeList[i];
Assert((edgeList[i]&3) != 0); // must not be a triangle
int v0 = vertMap.map[pEdge->get_start_point_index()] - pHull->baseVert;
int v1 = vertMap.map[pEdge->get_next()->get_start_point_index()] - pHull->baseVert;
Assert(v0>=0 && v0<256);
Assert(v1>=0 && v1<256);
edge.v0 = v0;
edge.v1 = v1;
buf.Put(&edge, sizeof(edge));
}
}
// decompress packed hull into a compact ledge
void CVPhysicsVirtualMeshWriter::UnpackCompactLedgeFromHull( IVP_Compact_Ledge *pLedge, int materialIndex, const IVP_Compact_Poly_Point *pPointList, const virtualmeshhull_t *pHullHeader, int hullIndex, bool isVirtualLedge )
{
const packedhull_t *pHull = pHullHeader->GetPackedHull(hullIndex);
const packedtriangle_t *pPackedTris = pHullHeader->GetPackedTriangles(hullIndex);
// write the ledge
pLedge->set_offset_ledge_points( (int)((char *)pPointList - (char *)pLedge) ); // byte offset from 'this' to (ledge) point array
pLedge->set_is_compact( IVP_TRUE );
pLedge->set_size(sizeof(IVP_Compact_Ledge) + sizeof(IVP_Compact_Triangle)*pHull->triangleCount); // <0 indicates a non compact compact ledge
pLedge->n_triangles = pHull->triangleCount;
pLedge->has_chilren_flag = isVirtualLedge ? IVP_TRUE : IVP_FALSE;
// Make the offset -pLedge so the result is a NULL ledgetree node - we haven't needed to create one of these as of yet
//pLedge->ledgetree_node_offset = -((int)pLedge);
// keep track of which triangle edge referenced this edge (so the next one can swap the order and point to the first one)
int forwardEdgeIndex[255];
for ( int i = 0; i < pHull->edgeCount; i++ )
{
forwardEdgeIndex[i] = -1;
}
packededge_t *pPackedEdges = (packededge_t *)(pPackedTris + pHull->triangleCount);
IVP_Compact_Triangle *pOut = pLedge->get_first_triangle();
// now write the compact triangles and their edges
int baseVert = pHull->baseVert;
for ( int i = 0; i < pHull->triangleCount; i++ )
{
pOut[i].set_tri_index(i);
pOut[i].set_material_index(materialIndex);
pOut[i].set_is_virtual( i < pHull->vtriCount ? IVP_TRUE : IVP_FALSE );
pOut[i].set_pierce_index(pPackedTris[i].opposite);
Assert(pPackedTris[i].opposite<pHull->triangleCount);
int edges[3] = {pPackedTris[i].e0, pPackedTris[i].e1, pPackedTris[i].e2};
for ( int j = 0; j < 3; j++ )
{
Assert(edges[j]<pHull->edgeCount);
if ( forwardEdgeIndex[edges[j]] < 0 )
{
// this is the first triangle to use this edge, so it's forward (and the other triangle sharing (opposite edge pointer) is unknown)
int startVert = pPackedEdges[edges[j]].v0 + baseVert;
pOut[i].c_three_edges[j].set_start_point_index(startVert);
pOut[i].c_three_edges[j].set_is_virtual( edges[j] < pHull->vedgeCount ? IVP_TRUE : IVP_FALSE );
forwardEdgeIndex[edges[j]] = EdgeIndex(pLedge, &pOut[i].c_three_edges[j]);
}
else
{
// this is the second triangle to use this edge, so it's reversed (and the other triangle sharing is in the forward edge table)
int oppositeIndex = forwardEdgeIndex[edges[j]];
int startVert = pPackedEdges[edges[j]].v1 + baseVert;
pOut[i].c_three_edges[j].set_start_point_index(startVert);
pOut[i].c_three_edges[j].set_is_virtual( edges[j] < pHull->vedgeCount ? IVP_TRUE : IVP_FALSE );
// now build the links between the triangles sharing this edge
int thisEdgeIndex = EdgeIndex( pLedge, &pOut[i].c_three_edges[j] );
pOut[i].c_three_edges[j].set_opposite_index( oppositeIndex - thisEdgeIndex );
pOut[i].c_three_edges[j].get_opposite()->set_opposite_index( thisEdgeIndex - oppositeIndex );
}
}
}
}
// low-level code to initialize a 2-sided triangle
static void InitTriangle( IVP_Compact_Triangle *pTri, int index, int materialIndex, int v0, int v1, int v2, int opp0, int opp1, int opp2 )
{
pTri->set_tri_index(index);
pTri->set_material_index(materialIndex);
pTri->c_three_edges[0].set_start_point_index(v0);
pTri->c_three_edges[1].set_start_point_index(v1);
pTri->c_three_edges[2].set_start_point_index(v2);
pTri->c_three_edges[0].set_opposite_index(opp0);
pTri->c_three_edges[1].set_opposite_index(opp1);
pTri->c_three_edges[2].set_opposite_index(opp2);
}
void CVPhysicsVirtualMeshWriter::InitTwoSidedTriangleLege( triangleledge_t *pOut, const IVP_Compact_Poly_Point *pPoints, int v0, int v1, int v2, int materialIndex )
{
IVP_Compact_Ledge *pLedge = &pOut->ledge;
pLedge->set_offset_ledge_points( (int)((char *)pPoints - (char *)pLedge) ); // byte offset from 'this' to (ledge) point array
pLedge->set_is_compact( IVP_TRUE );
pLedge->set_size(sizeof(triangleledge_t)); // <0 indicates a non compact compact ledge
pLedge->n_triangles = 2;
pLedge->has_chilren_flag = IVP_FALSE;
// triangles
InitTriangle( &pOut->faces[0], 0, materialIndex, v0, v1, v2, 6, 4, 2 );
InitTriangle( &pOut->faces[1], 1, materialIndex, v0, v2, v1, -2, -4, -6);
pOut->faces[0].set_pierce_index(1);
pOut->faces[1].set_pierce_index(0);
}
bool CVPhysicsVirtualMeshWriter::LedgeCanBePacked(const IVP_Compact_Ledge *pLedge, const virtualmeshlist_t &list)
{
int edgeCount = pLedge->get_n_triangles() * 3;
if ( edgeCount > 512 )
return false;
vertmap_t vertMap;
BuildVertMap( vertMap, list.pVerts, list.vertexCount, pLedge );
if ( (vertMap.maxRef - vertMap.minRef) > 255 )
return false;
return true;
}
// this builds a packed hull array from a compact ledge array (needs the virtualmeshlist for reference)
virtualmeshhull_t *CVPhysicsVirtualMeshWriter::CreatePackedHullFromLedges( const virtualmeshlist_t &list, const IVP_Compact_Ledge **pLedges, int ledgeCount )
{
int triCount = 0;
int edgeCount = 0;
for ( int i = 0; i < ledgeCount; i++ )
{
triCount += pLedges[i]->get_n_triangles();
edgeCount += (pLedges[i]->get_n_triangles() * 3)/2;
Assert(LedgeCanBePacked(pLedges[i], list));
}
unsigned int totalSize = sizeof(packedtriangle_t)*triCount + sizeof(packededge_t)*edgeCount + sizeof(packedhull_t)*ledgeCount + sizeof(virtualmeshhull_t);
byte *pBuf = new byte[totalSize];
CUtlBuffer buf;
buf.SetExternalBuffer( pBuf, totalSize, 0, 0 );
if ( 1 )
{
virtualmeshhull_t tmp;
Q_memset( &tmp, 0, sizeof(tmp) );
tmp.hullCount = ledgeCount;
buf.Put(&tmp, sizeof(tmp));
}
// write the headers
Assert(ledgeCount < 16);
packedhull_t *pHulls[16];
for ( int i = 0; i < ledgeCount; i++ )
{
pHulls[i] = (packedhull_t *)buf.PeekPut();
packedhull_t hull;
hull.triangleCount = pLedges[i]->get_n_triangles();
hull.edgeCount = (hull.triangleCount * 3) / 2;
buf.Put(&hull, sizeof(hull));
}
// write the data itself
for ( int i = 0; i < ledgeCount; i++ )
{
PackLedgeIntoBuffer( pHulls[i], buf, pLedges[i], list );
}
return (virtualmeshhull_t *)pBuf;
}
// frees the memory associated with this packed hull
void CVPhysicsVirtualMeshWriter::DestroyPackedHull( virtualmeshhull_t *pHull )
{
byte *pData = (byte *)pHull;
delete[] pData;
}
unsigned int CVPhysicsVirtualMeshWriter::UnpackLedgeListFromHull( byte *pOut, virtualmeshhull_t *pHull, IVP_Compact_Poly_Point *pPoints )
{
unsigned int memOffset = 0;
for ( int i = 0; i < pHull->hullCount; i++ )
{
IVP_Compact_Ledge *pHullLedge = (IVP_Compact_Ledge *)(pOut + memOffset);
CVPhysicsVirtualMeshWriter::UnpackCompactLedgeFromHull( pHullLedge, 0, pPoints, pHull, i, true );
memOffset += pHullLedge->get_size();
}
return memOffset;
}
/*
#define DUMP_FILES 1
static bool DumpListToGLView( const char *pFilename, const virtualmeshlist_t &list )
{
#if DUMP_FILES
FILE *fp = fopen( pFilename, "a+" );
for ( int i = 0; i < list.triangleCount; i++ )
{
fprintf( fp, "3\n" );
fprintf( fp, "%6.3f %6.3f %6.3f 1 0 0\n", list.pVerts[list.indices[i*3+0]].x, list.pVerts[list.indices[i*3+0]].y, list.pVerts[list.indices[i*3+0]].z );
fprintf( fp, "%6.3f %6.3f %6.3f 0 1 0\n", list.pVerts[list.indices[i*3+1]].x, list.pVerts[list.indices[i*3+1]].y, list.pVerts[list.indices[i*3+1]].z );
fprintf( fp, "%6.3f %6.3f %6.3f 0 0 1\n", list.pVerts[list.indices[i*3+2]].x, list.pVerts[list.indices[i*3+2]].y, list.pVerts[list.indices[i*3+2]].z );
}
fclose(fp);
#endif
return true;
}
static bool DumpLedgeToGLView( const char *pFilename, const IVP_Compact_Ledge *pLedge, float r=1.0f, float g=1.0f, float b=1.0f, float offset=0.0f )
{
#if DUMP_FILES
FILE *fp = fopen( pFilename, "a+" );
int ivpIndex;
Vector tmp[3];
const IVP_Compact_Poly_Point *pPoints = pLedge->get_point_array();
for ( int i = 0; i < pLedge->get_n_triangles(); i++ )
{
// iterate each triangle, for each referenced vert that hasn't yet been mapped, search for the nearest match
const IVP_Compact_Triangle *pTri = pLedge->get_first_triangle() + i;
ivpIndex = pTri->get_edge(2)->get_start_point_index();
ConvertPositionToHL( &pPoints[ivpIndex], tmp[0] );
ivpIndex = pTri->get_edge(1)->get_start_point_index();
ConvertPositionToHL( &pPoints[ivpIndex], tmp[1] );
ivpIndex = pTri->get_edge(0)->get_start_point_index();
ConvertPositionToHL( &pPoints[ivpIndex], tmp[2] );
tmp[0].x += offset;
tmp[1].x += offset;
tmp[2].x += offset;
fprintf( fp, "2\n" );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[0].x, tmp[0].y, tmp[0].z, r, g, b );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[1].x, tmp[1].y, tmp[1].z, r, g, b );
fprintf( fp, "2\n" );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[1].x, tmp[1].y, tmp[1].z, r, g, b );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[2].x, tmp[2].y, tmp[2].z, r, g, b );
fprintf( fp, "2\n" );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[2].x, tmp[2].y, tmp[2].z, r, g, b );
fprintf( fp, "%6.3f %6.3f %6.3f %.1f %.1f %.1f\n", tmp[0].x, tmp[0].y, tmp[0].z, r, g, b );
}
fclose( fp );
#endif
return true;
}
static int ComputeSize( virtualmeshhull_t *pHeader )
{
packedhull_t *pHull = (packedhull_t *)(pHeader+1);
unsigned int size = pHeader->hullCount * sizeof(IVP_Compact_Ledge);
for ( int i = 0; i < pHeader->hullCount; i++ )
{
size += sizeof(IVP_Compact_Triangle) * pHull[i].triangleCount;
}
return size;
}
bool CVPhysicsVirtualMeshWriter::CheckHulls( virtualmeshhull_t *pHull0, virtualmeshhull_t *pHull1, const virtualmeshlist_t &list )
{
for ( int i = 0; i < pHull0->hullCount; i++ )
{
const packedhull_t *pP0 = pHull0->GetPackedHull(i);
const packedhull_t *pP1 = pHull1->GetPackedHull(i);
Assert(pP0->triangleCount == pP1->triangleCount);
Assert(pP0->vtriCount == pP1->vtriCount);
Assert(pP0->edgeCount == pP1->edgeCount);
Assert(pP0->vedgeCount == pP1->vedgeCount);
Assert(pP0->baseVert == pP1->baseVert);
const packedtriangle_t *pTri0 = pHull0->GetPackedTriangles( i );
const packedtriangle_t *pTri1 = pHull1->GetPackedTriangles( i );
for ( int j = 0; j < pP0->triangleCount; j++ )
{
Assert(pTri0[j].e0 == pTri1[j].e0);
Assert(pTri0[j].e1 == pTri1[j].e1);
Assert(pTri0[j].e2 == pTri1[j].e2);
Assert(pTri0[j].opposite == pTri1[j].opposite);
}
}
{
int size0 = ComputeSize(pHull0);
int pointSize0 = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
byte *pMem0 = (byte *)ivp_malloc_aligned( size0+pointSize0, 16 );
IVP_Compact_Poly_Point *pPoints = (IVP_Compact_Poly_Point *)pMem0;
IVP_Compact_Ledge *pLedge0 = (IVP_Compact_Ledge *)(pPoints + list.vertexCount);
for ( int i = 0; i < list.vertexCount; i++ )
{
ConvertPositionToIVP( list.pVerts[i], pPoints[i] );
}
UnpackLedgeListFromHull( (byte *)pLedge0, pHull0, pPoints );
for ( int i = 0; i < pHull0->hullCount; i++ )
{
if ( i == i ) DumpLedgeToGLView( "c:\\jay.txt", pLedge0, 1, 0, 0, 0 );
pLedge0 = (IVP_Compact_Ledge *)( ((byte *)pLedge0 ) + pLedge0->get_size() );
}
ivp_free_aligned(pMem0);
}
{
int size1 = ComputeSize(pHull1);
int pointSize1 = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
byte *pMem1 = (byte *)ivp_malloc_aligned( size1+pointSize1, 16 );
IVP_Compact_Poly_Point *pPoints = (IVP_Compact_Poly_Point *)pMem1;
IVP_Compact_Ledge *pLedge1 = (IVP_Compact_Ledge *)(pPoints + list.vertexCount);
for ( int i = 0; i < list.vertexCount; i++ )
{
ConvertPositionToIVP( list.pVerts[i], pPoints[i] );
}
UnpackLedgeListFromHull( (byte *)pLedge1, pHull1, pPoints );
for ( int i = 0; i < pHull1->hullCount; i++ )
{
if ( i == i ) DumpLedgeToGLView( "c:\\jay.txt", pLedge1, 0, 1, 0, 1024 );
pLedge1 = (IVP_Compact_Ledge *)( ((byte *)pLedge1 ) + pLedge1->get_size() );
}
ivp_free_aligned(pMem1);
}
return true;
}
*/

View File

@ -0,0 +1,110 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef LEDGEWRITER_H
#define LEDGEWRITER_H
#ifdef _WIN32
#pragma once
#endif
#include "vphysics/virtualmesh.h"
// 2-sided triangle ledge rep
struct triangleledge_t
{
IVP_Compact_Ledge ledge;
IVP_Compact_Triangle faces[2];
};
// minimum footprint convex hull rep. Assume 8-bits of index space per edge/triangle/vert
// NOTE: EACH ELEMENT OF THESE STRUCTS MUST BE 8-bits OR YOU HAVE TO WRITE SWAPPING CODE FOR
// THE X360 IMPLEMENTATION. THERE IS NO SUCH CODE AS OF NOW.
#pragma pack(1)
struct packedtriangle_t
{
byte e0; // only bytes allowed see above
byte e1;
byte e2;
byte opposite;
};
struct packededge_t
{
byte v0; // only bytes allowed see above
byte v1;
};
struct packedhull_t
{
byte triangleCount; // only bytes allowed see above
byte vtriCount;
byte edgeCount;
byte vedgeCount;
byte baseVert;
inline size_t DataSize() const
{
return (sizeof(packedtriangle_t) * triangleCount) + (sizeof(packededge_t)*edgeCount);
}
};
struct virtualmeshhull_t
{
byte hullCount; // only bytes allowed see above
byte pad[3];
inline const packedhull_t *GetPackedHull( int hullIndex ) const
{
Assert(hullIndex<hullCount);
return ((const packedhull_t *)(this+1)) + hullIndex;
}
inline const packedtriangle_t *GetPackedTriangles( int hullIndex ) const
{
const packedhull_t *pHull = GetPackedHull(0);
// the first triangle is immediately following the memory for the packed hulls
const byte *pStart = reinterpret_cast<const byte *>(GetPackedHull(0) + hullCount);
for ( int i = 0; i < hullIndex; i++ )
{
pStart += pHull[i].DataSize();
}
return reinterpret_cast<const packedtriangle_t *>(pStart);
}
inline const packededge_t *GetPackedEdges( int hullIndex ) const
{
return reinterpret_cast<const packededge_t *>(GetPackedTriangles(hullIndex) + GetPackedHull(hullIndex)->triangleCount);
}
inline size_t TotalSize() const
{
size_t size = sizeof(*this) + sizeof(packedhull_t) * hullCount;
for ( int i = 0; i < hullCount; i++ )
{
size += GetPackedHull(i)->DataSize();
}
return size;
}
};
#pragma pack()
// end
// NOTE: EACH ELEMENT OF THE ABOVE STRUCTS MUST BE 8-bits OR YOU HAVE TO WRITE SWAPPING CODE FOR
// THE X360 IMPLEMENTATION. THERE IS NO SUCH CODE AS OF NOW.
// These statics are grouped in a class so they can be friends of IVP_Compact_Ledge and access its private data
class CVPhysicsVirtualMeshWriter
{
public:
// init a 2-sided triangle ledge
static void InitTwoSidedTriangleLege( triangleledge_t *pOut, const IVP_Compact_Poly_Point *pPoints, int v0, int v1, int v2, int materialIndex );
static virtualmeshhull_t *CreatePackedHullFromLedges( const virtualmeshlist_t &list, const IVP_Compact_Ledge **pLedges, int ledgeCount );
static void UnpackCompactLedgeFromHull( IVP_Compact_Ledge *pLedge, int materialIndex, const IVP_Compact_Poly_Point *pPointList, const virtualmeshhull_t *pHullHeader, int hullIndex, bool isVirtualLedge );
static void DestroyPackedHull( virtualmeshhull_t *pHull );
static bool LedgeCanBePacked(const IVP_Compact_Ledge *pLedge, const virtualmeshlist_t &list);
static unsigned int UnpackLedgeListFromHull( byte *pOut, virtualmeshhull_t *pHull, IVP_Compact_Poly_Point *pPoints );
};
#endif // LEDGEWRITER_H

View File

@ -0,0 +1,113 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "tier0/platform.h"
#include "linear_solver.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
// BUGBUG: Remove/tune this number somehow!!!
#define DET_EPSILON 1e-6f
// assumes square matrix!
// ONLY SUPPORTS 2x2, 3x3, and 4x4
float Det( float *matrix, int rows )
{
if ( rows == 2 )
{
return matrix[0]*matrix[3] - matrix[1]*matrix[2];
}
if ( rows == 3 )
{
return matrix[0]*matrix[4]*matrix[8] - matrix[0]*matrix[7]*matrix[5] - matrix[1]*matrix[3]*matrix[8] +
matrix[1]*matrix[5]*matrix[6] + matrix[2]*matrix[3]*matrix[7] - matrix[2]*matrix[4]*matrix[6];
}
// ERROR no more than 4x4
if ( rows != 4 )
return 0;
// UNDONE: Generalize this to NxN
float tmp[9];
float det = 0.f;
// do 4 3x3 dets
for ( int i = 0; i < 4; i++ )
{
// develop on row 0
int out = 0;
for ( int j = 1; j < 4; j++ )
{
// iterate each column and
for ( int k = 0; k < 4; k++ )
{
if ( k == i )
continue;
tmp[out] = matrix[(j*rows)+k];
out++;
}
}
if ( i & 1 )
{
det -= matrix[i]*Det(tmp,3);
}
else
{
det += matrix[i]*Det(tmp,3);
}
}
return det;
}
float *SolveCramer( const float *matrix, int rows, int columns )
{
// max 4 equations, 4 unknowns (until determinant routine is more general)
float tmpMain[16*16], tmpSub[16*16];
static float solution[16];
int i, j;
if ( rows > 4 || columns > 5 )
{
return NULL;
}
int outCol = columns - 1;
// copy out the square matrix
for ( i = 0; i < rows; i++ )
{
memcpy( tmpMain + (i*outCol), matrix + i*columns, sizeof(float)*outCol );
}
float detMain = Det( tmpMain, rows );
// probably degenerate!
if ( fabs(detMain) < DET_EPSILON )
{
return NULL;
}
for ( i = 0; i < rows; i++ )
{
// copy the square matrix
memcpy( tmpSub, tmpMain, sizeof(float)*rows*rows );
// copy the column of constants over the row
for ( j = 0; j < rows; j++ )
{
tmpSub[i+j*outCol] = matrix[j*columns+columns-1];
}
float det = Det( tmpSub, rows );
solution[i] = det / detMain;
}
return solution;
}

View File

@ -0,0 +1,22 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef LINEAR_SOLVER_H
#define LINEAR_SOLVER_H
#ifdef _WIN32
#pragma once
#endif
// Take the determinant of a matrix.
// NOTE: ONLY SUPPORTS 2x2, 3x3, and 4x4
extern float Det( float *matrix, int rows );
// solve a system of linear equations using Cramer's rule (only supports up to 4 variables due to limits on Det())
extern float *SolveCramer( const float *matrix, int rows, int columns );
#endif // LINEAR_SOLVER_H

269
vphysics-physx/main.cpp Normal file
View File

@ -0,0 +1,269 @@
//========= 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"
#include "convert.h"
using namespace physx;
#if defined(_WIN32) && !defined(_X360)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#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;
PxCooking *gPxCooking = NULL;
// 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<<index1;
m_bits[index1] |= 1<<index0;
}
void DisableCollisions( int index0, int index1 )
{
Assert(index0<32&&index1<32);
m_bits[index0] &= ~(1<<index1);
m_bits[index1] &= ~(1<<index0);
}
bool ShouldCollide( int index0, int index1 )
{
Assert(index0<32&&index1<32);
return (m_bits[index0] & (1<<index1)) ? true : false;
}
private:
unsigned int m_bits[32];
};
//-----------------------------------------------------------------------------
// Main physics interface
//-----------------------------------------------------------------------------
class CPhysicsInterface : public CTier1AppSystem<IPhysics>
{
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<IPhysics> BaseClass;
private:
CUtlVector<IPhysicsEnvironment *> m_envList;
CUtlVector<CPhysicsCollisionSet> 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);
PxTolerancesScale scale;
scale.length = g_PhysicsUnits.unitScaleMetersInv;
scale.speed *= g_PhysicsUnits.unitScaleMetersInv;
gPxPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gPxFoundation, scale, recordMemoryAllocations, gPxPvd);
if( !gPxPhysics )
{
Error("PxCreatePhysics failed!\n");
return INIT_FAILED;
}
gPxCooking = PxCreateCooking(PX_PHYSICS_VERSION, *gPxFoundation, PxCookingParams(scale));
return INIT_OK;
}
void CPhysicsInterface::Shutdown()
{
if( gPxCooking )
gPxCooking->release();
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;
}

View File

@ -0,0 +1,342 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "stdafx.h"
#include "filesystem_tools.h"
#include "KeyValues.h"
#include "physdll.h"
#include "materialsystem/imesh.h"
#include "utlvector.h"
char g_szAppName[] = "VPhysics perf test";
bool g_bCaptureOnFocus = false;
IPhysics *physics = NULL;
IPhysicsCollision *physcollision = NULL;
IPhysicsSurfaceProps *physprops = NULL;
IMaterial *g_materialFlatshaded = NULL;
IMaterial *g_pWireframeMaterial = NULL;
int gKeys[256];
const objectparams_t g_PhysDefaultObjectParams =
{
NULL,
1.0f, //mass
1.0f, // inertia
0.0f, // damping
0.0f, // rotdamping
0.05f, // rotIntertiaLimit
"DEFAULT",
NULL,// game data
0.f, // volume (leave 0 if you don't have one or call physcollision->CollideVolume() to compute it)
1.0f, // drag coefficient
true,// enable collisions?
};
void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem )
{
// Load file into memory
FileHandle_t file = pFileSystem->Open( pFileName, "rb" );
if ( file )
{
int len = pFileSystem->Size( file );
// read the file
char *buffer = (char *)stackalloc( len+1 );
pFileSystem->Read( buffer, len, file );
pFileSystem->Close( file );
buffer[len] = 0;
pProps->ParseSurfaceData( pFileName, buffer );
// buffer is on the stack, no need to free
}
}
void PhysParseSurfaceData( IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem )
{
const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt";
KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE );
if ( manifest->LoadFromFile( pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) )
{
for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() )
{
if ( !Q_stricmp( sub->GetName(), "file" ) )
{
// Add
AddSurfacepropFile( sub->GetString(), pProps, pFileSystem );
continue;
}
Warning( "surfaceprops::Init: Manifest '%s' with bogus file type '%s', expecting 'file'\n",
SURFACEPROP_MANIFEST_FILE, sub->GetName() );
}
}
else
{
Error( "Unable to load manifest file '%s'\n", SURFACEPROP_MANIFEST_FILE );
}
manifest->deleteThis();
}
struct physics_test_object_t
{
IPhysicsObject *pPhysics;
ICollisionQuery *pModel;
};
struct physicstest_t
{
IPhysicsEnvironment *physenv;
CUtlVector<physics_test_object_t> list;
void Clear()
{
physenv->SetQuickDelete( true );
for ( int i = 0; i < list.Count(); i++ )
{
physcollision->DestroyQueryModel( list[i].pModel );
physenv->DestroyObject( list[i].pPhysics );
}
list.Purge();
physics->DestroyEnvironment( physenv );
}
void InitEnvironment()
{
physenv = physics->CreateEnvironment();
//g_EntityCollisionHash = physics->CreateObjectPairHash();
physenv->EnableDeleteQueue( true );
//physenv->SetCollisionSolver( &g_Collisions );
//physenv->SetCollisionEventHandler( &g_Collisions );
//physenv->SetConstraintEventHandler( g_pConstraintEvents );
//physenv->SetObjectEventHandler( &g_Objects );
physenv->SetSimulationTimestep( DEFAULT_TICK_INTERVAL ); // 15 ms per tick
// HL Game gravity, not real-world gravity
physenv->SetGravity( Vector( 0, 0, -600.0f ) );
physenv->SetAirDensity( 0.5f );
}
int AddObject( IPhysicsObject *pObject )
{
int index = list.AddToTail();
list[index].pPhysics = pObject;
list[index].pModel = physcollision->CreateQueryModel( (CPhysCollide *)pObject->GetCollide() );
return index;
}
void CreateGround( float size )
{
{
CPhysCollide *pCollide = physcollision->BBoxToCollide( Vector(-size,-size,-24), Vector(size,size,0) );
objectparams_t params = g_PhysDefaultObjectParams;
IPhysicsObject *pGround = physenv->CreatePolyObjectStatic( pCollide, physprops->GetSurfaceIndex( "default" ), vec3_origin, vec3_angle, &params );
AddObject( pGround );
}
for ( int i = 0; i < 20; i++ )
{
CPhysCollide *pCollide = physcollision->BBoxToCollide( Vector(-24,-24,-24), Vector(24,24,24) );
objectparams_t params = g_PhysDefaultObjectParams;
params.mass = 150.0f;
IPhysicsObject *pGround = physenv->CreatePolyObject( pCollide, physprops->GetSurfaceIndex( "default" ), Vector(64*(i%4),64 * (i%5),1024), vec3_angle, &params );
AddObject( pGround );
pGround->Wake();
}
}
void Explode( const Vector &origin, float force )
{
for ( int i = 0; i < list.Count(); i++ )
{
if ( !list[i].pPhysics->IsMoveable() )
continue;
Vector pos, dir;
list[i].pPhysics->GetPosition( &pos, NULL );
dir = pos - origin;
dir.z += 10;
VectorNormalize( dir );
list[i].pPhysics->ApplyForceCenter( dir * force );
}
}
void RandomColor( float *color, int key )
{
static bool first = true;
static colorVec colors[256];
if ( first )
{
int r, g, b;
first = false;
for ( int i = 0; i < 256; i++ )
{
do
{
r = rand()&255;
g = rand()&255;
b = rand()&255;
} while ( (r+g+b)<256 );
colors[i].r = r;
colors[i].g = g;
colors[i].b = b;
colors[i].a = 255;
}
}
int index = key & 255;
color[0] = colors[index].r * (1.f / 255.f);
color[1] = colors[index].g * (1.f / 255.f);
color[2] = colors[index].b * (1.f / 255.f);
color[3] = colors[index].a * (1.f / 255.f);
}
void DrawObject( ICollisionQuery *pModel, IMaterial *pMaterial, IPhysicsObject *pObject )
{
matrix3x4_t matrix;
pObject->GetPositionMatrix( &matrix );
CMatRenderContextPtr pRenderContext(g_MaterialSystemApp.m_pMaterialSystem);
pRenderContext->Bind( pMaterial );
int vertIndex = 0;
for ( int i = 0; i < pModel->ConvexCount(); i++ )
{
float color[4];
RandomColor( color, i + (int)pObject );
IMesh* pMatMesh = pRenderContext->GetDynamicMesh( );
CMeshBuilder meshBuilder;
int triCount = pModel->TriangleCount( i );
meshBuilder.Begin( pMatMesh, MATERIAL_TRIANGLES, triCount );
for ( int j = 0; j < triCount; j++ )
{
Vector objectSpaceVerts[3];
pModel->GetTriangleVerts( i, j, objectSpaceVerts );
for ( int k = 0; k < 3; k++ )
{
Vector v;
VectorTransform (objectSpaceVerts[k], matrix, v);
meshBuilder.Position3fv( v.Base() );
meshBuilder.Color4fv( color );
meshBuilder.AdvanceVertex();
}
}
meshBuilder.End( false, true );
}
}
void Draw()
{
for ( int i = 0; i < list.Count(); i++ )
{
DrawObject( list[i].pModel, g_materialFlatshaded, list[i].pPhysics );
}
}
void Simulate( float frametime )
{
physenv->Simulate( frametime );
}
};
physicstest_t staticTest;
void AppInit( void )
{
memset( gKeys, 0, sizeof(gKeys) );
CreateInterfaceFn physicsFactory = GetPhysicsFactory();
if (!(physics = (IPhysics *)physicsFactory( VPHYSICS_INTERFACE_VERSION, NULL )) ||
!(physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL )) ||
!(physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL )) )
{
return;
}
PhysParseSurfaceData( physprops, g_pFullFileSystem );
g_materialFlatshaded = g_MaterialSystemApp.m_pMaterialSystem->FindMaterial("debug/debugdrawflatpolygons", TEXTURE_GROUP_OTHER, true);
g_pWireframeMaterial = g_MaterialSystemApp.m_pMaterialSystem->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
staticTest.InitEnvironment();
staticTest.CreateGround( 1024 );
}
void FPSControls( float frametime, float mouseDeltaX, float mouseDeltaY, Vector& cameraPosition, QAngle& cameraAngles, float speed )
{
cameraAngles[1] -= mouseDeltaX;
cameraAngles[0] -= mouseDeltaY;
if ( cameraAngles[0] < -85 )
cameraAngles[0] = -85;
if ( cameraAngles[0] > 85 )
cameraAngles[0] = 85;
Vector forward, right, up;
AngleVectors( cameraAngles, &forward, &right, &up );
if ( gKeys[ 'W' ] )
VectorMA( cameraPosition, frametime * speed, forward, cameraPosition );
if ( gKeys[ 'S' ] )
VectorMA( cameraPosition, -frametime * speed, forward, cameraPosition );
if ( gKeys[ 'A' ] )
VectorMA( cameraPosition, -frametime * speed, right, cameraPosition );
if ( gKeys[ 'D' ] )
VectorMA( cameraPosition, frametime * speed, right, cameraPosition );
}
void SetupCamera( Vector& cameraPosition, QAngle& cameraAngles )
{
CMatRenderContextPtr pRenderContext(g_MaterialSystemApp.m_pMaterialSystem);
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->LoadIdentity( );
pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
pRenderContext->Rotate( 90, 0, 0, 1 );
pRenderContext->Rotate( -cameraAngles[2], 1, 0, 0); // roll
pRenderContext->Rotate( -cameraAngles[0], 0, 1, 0); // pitch
pRenderContext->Rotate( -cameraAngles[1], 0, 0, 1); // yaw
pRenderContext->Translate( -cameraPosition[0], -cameraPosition[1], -cameraPosition[2] );
}
static Vector cameraPosition = Vector(0,0,128);
static QAngle cameraAngles = vec3_angle;
void AppRender( float frametime, float mouseDeltaX, float mouseDeltaY )
{
FPSControls( frametime, mouseDeltaX, mouseDeltaY, cameraPosition, cameraAngles, 300 );
SetupCamera( cameraPosition, cameraAngles );
staticTest.Simulate( frametime );
staticTest.Draw();
}
void AppExit( void )
{
staticTest.Clear();
//physics->DestroyObjectPairHash( g_EntityCollisionHash );
//g_EntityCollisionHash = NULL;
physics->DestroyAllCollisionSets();
}
void AppKey( int key, int down )
{
gKeys[ key & 255 ] = down;
}
void AppChar( int key )
{
if ( key == ' ' )
{
staticTest.Explode( cameraPosition, 150 * 100 );
}
}

View File

@ -0,0 +1,57 @@
//-----------------------------------------------------------------------------
// PERFTEST.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_win_win32_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,..\..\utils\common,..\..\utils\matsysapp,."
$PreprocessorDefinitions "$BASE;VECTOR;PROTECTED_THINGS_DISABLE"
}
$Linker
{
// $AdditionalDependencies "comctl32.lib winmm.lib"
}
}
$Project "perftest"
{
$Folder "Source Files"
{
$File "..\..\utils\matsysapp\matsysapp.cpp"
$File "perftest.cpp"
$Folder "common files"
{
// $File "..\..\utils\common\bsplib.cpp"
$File "..\..\utils\common\cmdlib.cpp"
$File "$SRCDIR\public\filesystem_helpers.cpp"
$File "$SRCDIR\public\filesystem_init.cpp"
$File "..\..\utils\common\filesystem_tools.cpp"
$File "..\..\utils\common\physdll.cpp"
$File "..\..\utils\common\scriplib.cpp"
}
}
$Folder "Header Files"
{
$File "$SRCDIR\public\vphysics_interface.h"
$File "stdafx.h"
}
$Folder "Link Libraries"
{
// $DynamicFile "$SRCDIR\lib\public\appframework.lib"
$DynamicFile "$SRCDIR\lib\public\mathlib.lib"
$DynamicFile "$SRCDIR\lib\public\tier2.lib"
}
}

View File

@ -0,0 +1,13 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "materialsystem/imaterialsystem.h"
#include "matsysapp.h"
#include "mathlib/mathlib.h"
#include "const.h"
#include "vphysics_interface.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,303 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PHYSICS_AIRBOAT_H
#define PHYSICS_AIRBOAT_H
#ifdef _WIN32
#pragma once
#endif
#include "ivp_controller.hxx"
#include "ivp_car_system.hxx"
class IPhysicsObject;
class IVP_Ray_Solver_Template;
class IVP_Ray_Hit;
class IVP_Event_Sim;
#define IVP_RAYCAST_AIRBOAT_MAX_WHEELS 4
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class IVP_Raycast_Airboat_Wheel
{
public:
// static section
IVP_U_Float_Point hp_cs; // hard point core system projected on y plane
IVP_U_Float_Point raycast_start_cs; // ray cast start position
IVP_U_Float_Point raycast_dir_cs;
IVP_FLOAT raycast_length;
IVP_U_Float_Point spring_direction_cs; // spring direction in core-space
IVP_FLOAT distance_orig_hp_to_hp; // distance hp is moved by projecting it onto the y - plane
IVP_FLOAT spring_len; // == pretension + distance_orig_hp_to_hp
IVP_FLOAT spring_constant; // shock at wheel spring constant
IVP_FLOAT spring_damp_relax; // shock at wheel spring dampening during relaxation
IVP_FLOAT spring_damp_compress; // shock at wheel spring dampening during compression
IVP_FLOAT max_rotation_speed; // max rotational speed of the wheel
IVP_FLOAT wheel_radius; // wheel radius
IVP_FLOAT inv_wheel_radius; // inverse wheel radius
IVP_FLOAT friction_of_wheel; // wheel friction
// dynamic section
IVP_FLOAT torque; // torque applied to wheel
IVP_BOOL wheel_is_fixed; // eg. handbrake (fixed = stationary)
IVP_U_Float_Point axis_direction_cs; // axle direction in core-space
IVP_FLOAT angle_wheel; // wheel angle
IVP_FLOAT wheel_angular_velocity; // angular velocity of wheel
// out
IVP_U_Float_Point surface_speed_of_wheel_on_ground_ws; // actual speed in world-space
IVP_FLOAT pressure; // force from gravity, mass of car, stabilizers, etc. on wheel
IVP_FLOAT raycast_dist; // raycast distance to impact for wheel
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class IVP_Raycast_Airboat_Impact
{
public:
IVP_FLOAT friction_value; // combined (multiply) frictional value of impact surface and wheel
IVP_FLOAT stabilizer_force; // force on wheel due to axle stabilization
IVP_Real_Object *moveable_object_hit_by_ray; // moveable physics object hit by raycast
IVP_U_Float_Point raycast_dir_ws; // raycast direction in world-space
IVP_U_Float_Point spring_direction_ws; // spring direction (raycast for impact direction) in world-space
IVP_U_Float_Point surface_speed_wheel_ws; // wheel speed in world-space
IVP_U_Float_Point projected_surface_speed_wheel_ws; // ???
IVP_U_Float_Point axis_direction_ws; // axle direction in world-space
IVP_U_Float_Point projected_axis_direction_ws; // ???
IVP_FLOAT forces_needed_to_drive_straight; // forces need to keep the vehicle driving straight (attempt and directional wheel friction)
IVP_FLOAT inv_normal_dot_dir; // ???
// Impact information.
IVP_BOOL bImpact; // Had an impact?
IVP_BOOL bImpactWater; // Impact with water?
IVP_BOOL bInWater; // Point in water?
IVP_U_Point vecImpactPointWS; // Impact point in world-space.
IVP_U_Float_Point vecImpactNormalWS; // Impact normal in world-space.
IVP_FLOAT flDepth; // Distance to water surface.
IVP_FLOAT flFriction; // Friction at impact point.
IVP_FLOAT flDampening; // Dampening at surface.
int nSurfaceProps; // Surface property!
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class IVP_Raycast_Airboat_Axle
{
public:
IVP_FLOAT stabilizer_constant; // axle (for wheels) stabilizer constant
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class IVP_Controller_Raycast_Airboat_Vector_of_Cores_1: public IVP_U_Vector<IVP_Core>
{
void *elem_buffer[1];
public:
IVP_Controller_Raycast_Airboat_Vector_of_Cores_1();
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class CPhysics_Airboat : public IVP_Car_System, protected IVP_Controller_Dependent
{
public:
CPhysics_Airboat( IVP_Environment *env, const IVP_Template_Car_System *t, IPhysicsGameTrace *pGameTrace );
virtual ~CPhysics_Airboat();
void update_wheel_positions( void ) {}
void SetWheelFriction( int iWheel, float flFriction );
IPhysicsObject *GetWheel( int index );
virtual const char *get_controller_name() { return "sys:airboat"; }
protected:
void InitAirboat( const IVP_Template_Car_System *pCarSystem );
float GetWaterDepth( Ray_t *pGameRay, IPhysicsObject *pPhysAirboat );
// Purpose: Deconstructor
void PerformFrictionNotification( float flEliminatedEnergy, float dt, int nSurfaceProp, IPhysicsCollisionData *pCollisionData );
void do_raycasts_gameside( int nRaycastCount, IVP_Ray_Solver_Template *pRays, IVP_Raycast_Airboat_Impact *pImpacts );
void pre_raycasts_gameside( int nRaycastCount, IVP_Ray_Solver_Template *pRays, Ray_t *pGameRays, IVP_Raycast_Airboat_Impact *pImpacts );
IVP_Real_Object *m_pWheels[IVP_RAYCAST_AIRBOAT_MAX_WHEELS];
IPhysicsGameTrace *m_pGameTrace;
public:
// Steering
void do_steering_wheel(IVP_POS_WHEEL wheel_pos, IVP_FLOAT s_angle); // called by do_steering()
// Car Adjustment
void change_spring_constant(IVP_POS_WHEEL pos, IVP_FLOAT spring_constant); // [Newton/meter]
void change_spring_dampening(IVP_POS_WHEEL pos, IVP_FLOAT spring_dampening); // when spring is relaxing spring
void change_spring_dampening_compression(IVP_POS_WHEEL pos, IVP_FLOAT spring_dampening); // [Newton/meter] for compressing spring
void change_max_body_force(IVP_POS_WHEEL , IVP_FLOAT mforce) {}
void change_spring_pre_tension(IVP_POS_WHEEL pos, IVP_FLOAT pre_tension_length);
void change_spring_length(IVP_POS_WHEEL pos, IVP_FLOAT spring_length);
void change_stabilizer_constant(IVP_POS_AXIS pos, IVP_FLOAT stabi_constant); // [Newton/meter]
void change_fast_turn_factor( IVP_FLOAT fast_turn_factor_ ); // not implemented for raycasts
void change_wheel_torque(IVP_POS_WHEEL pos, IVP_FLOAT torque);
IVP_FLOAT get_wheel_torque(IVP_POS_WHEEL wheel_nr);
void update_throttle( IVP_FLOAT flThrottle );
void update_body_countertorque() {}
void change_body_downforce(IVP_FLOAT force); // extra force to keep flipped objects flipped over
void fix_wheel( IVP_POS_WHEEL, IVP_BOOL stop_wheel ); // stop wheel completely (e.g. handbrake )
void change_friction_of_wheel( IVP_POS_WHEEL pos, IVP_FLOAT friction );
void set_powerslide( float frontAccel, float rearAccel ) {}
// Car Info
IVP_DOUBLE get_body_speed(IVP_COORDINATE_INDEX idx_z = IVP_INDEX_Z); // km/h in 'z' direction
IVP_DOUBLE get_wheel_angular_velocity(IVP_POS_WHEEL);
IVP_DOUBLE get_orig_front_wheel_distance();
IVP_DOUBLE get_orig_axles_distance();
void get_skid_info( IVP_Wheel_Skid_Info *array_of_skid_info_out);
void get_wheel_position(IVP_U_Point *position_ws_out, IVP_U_Quat *direction_ws_out);
// Methods: 2nd Level, based on primitives
virtual void do_steering(IVP_FLOAT steering_angle_in, bool bAnalog); // default implementation updates this->steering_angle
//
// Booster (the airboat has no booster).
//
virtual bool IsBoosting(void) { return false; }
virtual void set_booster_acceleration( IVP_FLOAT acceleration) {}
virtual void activate_booster(IVP_FLOAT thrust, IVP_FLOAT duration, IVP_FLOAT delay) {}
virtual void update_booster(IVP_FLOAT delta_time) {}
virtual IVP_FLOAT get_booster_delay() { return 0; }
virtual IVP_FLOAT get_booster_time_to_go() { return 0; }
// Debug
void SetCarSystemDebugData( const IVP_CarSystemDebugData_t &carSystemDebugData );
void GetCarSystemDebugData( IVP_CarSystemDebugData_t &carSystemDebugData );
protected:
IVP_Core *m_pCore;
IVP_U_Float_Point m_vecLocalVelocity;
float m_flSpeed;
IVP_Real_Object *m_pAirboatBody; // *car_body
// Wheels/Axles.
short n_wheels;
short n_axis;
short wheels_per_axis;
IVP_Raycast_Airboat_Wheel m_aAirboatWheels[IVP_RAYCAST_AIRBOAT_MAX_WHEELS]; // wheel_of_car
IVP_Raycast_Airboat_Axle m_aAirboatAxles[IVP_RAYCAST_AIRBOAT_MAX_WHEELS/2]; // axis_of_car
// Gravity.
IVP_FLOAT gravity_y_direction; // +/-1
IVP_U_Float_Point normized_gravity_ws;
IVP_FLOAT extra_gravity;
// Orientation.
IVP_COORDINATE_INDEX index_x;
IVP_COORDINATE_INDEX index_y;
IVP_COORDINATE_INDEX index_z;
IVP_BOOL is_left_handed;
// Speed.
IVP_FLOAT max_speed;
//
IVP_FLOAT down_force;
IVP_FLOAT down_force_vertical_offset;
// Steering
IVP_FLOAT m_SteeringAngle;
bool m_bSteeringReversed;
bool m_bAnalogSteering;
IVP_FLOAT m_flPrevSteeringAngle;
IVP_FLOAT m_flSteerTime; // Number of seconds we've steered in this direction.
// Thrust.
IVP_FLOAT m_flThrust;
bool m_bAirborne; // Whether we are airborne or not.
IVP_FLOAT m_flAirTime; // How long we've been airborne (if we are).
bool m_bWeakJump; // Set when we become airborne while going slow.
// Pitch and roll stabilizers.
IVP_FLOAT m_flPitchErrorPrev;
IVP_FLOAT m_flRollErrorPrev;
// Debugging!
IVP_CarSystemDebugData_t m_CarSystemDebugData;
protected:
IVP_Raycast_Airboat_Wheel *get_wheel( IVP_POS_WHEEL i );
IVP_Raycast_Airboat_Axle *get_axle( IVP_POS_AXIS i );
virtual void core_is_going_to_be_deleted_event( IVP_Core * );
virtual IVP_U_Vector<IVP_Core> *get_associated_controlled_cores( void );
virtual void do_simulation_controller(IVP_Event_Sim *,IVP_U_Vector<IVP_Core> *core_list);
virtual IVP_CONTROLLER_PRIORITY get_controller_priority();
private:
// Initialization.
void InitRaycastCarEnvironment( IVP_Environment *pEnvironment, const IVP_Template_Car_System *pCarSystemTemplate );
void InitRaycastCarBody( const IVP_Template_Car_System *pCarSystemTemplate );
void InitRaycastCarWheels( const IVP_Template_Car_System *pCarSystemTemplate );
void InitRaycastCarAxes( const IVP_Template_Car_System *pCarSystemTemplate );
// Raycasts for simulation.
void PreRaycasts( IVP_Ray_Solver_Template *pRaySolverTemplates, const IVP_U_Matrix *m_world_f_core, IVP_Raycast_Airboat_Impact *pImpacts );
bool PostRaycasts( IVP_Ray_Solver_Template *pRaySolverTemplates, const IVP_U_Matrix *matWorldFromCore, IVP_Raycast_Airboat_Impact *pImpacts );
// Simulation.
void DoSimulationPontoons( IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim );
void DoSimulationPontoonsGround( IVP_Raycast_Airboat_Wheel *pPontoonPoint, IVP_Raycast_Airboat_Impact *pImpact, IVP_Event_Sim *pEventSim );
void DoSimulationPontoonsWater( IVP_Raycast_Airboat_Wheel *pPontoonPoint, IVP_Raycast_Airboat_Impact *pImpact, IVP_Event_Sim *pEventSim );
void DoSimulationDrag( IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim );
void DoSimulationTurbine( IVP_Event_Sim *pEventSim );
void DoSimulationSteering( IVP_Event_Sim *pEventSim );
void DoSimulationKeepUprightPitch( IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim );
void DoSimulationKeepUprightRoll( IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim );
void DoSimulationGravity( IVP_Event_Sim *pEventSim );
int CountSurfaceContactPoints( IVP_Raycast_Airboat_Impact *pImpacts );
void UpdateAirborneState( IVP_Raycast_Airboat_Impact *pImpacts, IVP_Event_Sim *pEventSim );
float ComputeFrontPontoonWaveNoise( int nPontoonIndex, float flSpeedRatio );
void CalcImpactPosition( IVP_Ray_Solver_Template *pRaySolver, IVP_Raycast_Airboat_Wheel *pPontoonPoint,
IVP_Raycast_Airboat_Impact *pImpacts );
IVP_Controller_Raycast_Airboat_Vector_of_Cores_1 vector_of_cores;
};
#endif // PHYSICS_AIRBOAT_H

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_CONSTRAINT_H
#define PHYSICS_CONSTRAINT_H
#pragma once
class IVP_Environment;
class CPhysicsObject;
class IPhysicsConstraint;
class IPhysicsConstraintGroup;
extern IPhysicsConstraint *CreateRagdollConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll );
extern IPhysicsConstraint *CreateHingeConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_limitedhingeparams_t &ragdoll );
extern IPhysicsConstraint *CreateFixedConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed );
extern IPhysicsConstraint *CreateBallsocketConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket );
extern IPhysicsConstraint *CreateSlidingConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &slide );
extern IPhysicsConstraint *CreatePulleyConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley );
extern IPhysicsConstraint *CreateLengthConstraint( IVP_Environment *pEnvironment, CPhysicsObject *pReferenceObject, CPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length );
extern IPhysicsConstraintGroup *CreatePhysicsConstraintGroup( IVP_Environment *pEnvironment, const constraint_groupparams_t &group );
extern IPhysicsConstraint *GetClientDataForHkConstraint( class hk_Breakable_Constraint *pHkConstraint );
extern bool IsExternalConstraint( IVP_Controller *pLCS, void *pGameData );
#endif // PHYSICS_CONSTRAINT_H

View File

@ -0,0 +1,171 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "physics_controller_raycast_vehicle.h"
#include "ivp_material.hxx"
#include "ivp_ray_solver.hxx"
#include "ivp_cache_object.hxx"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CPhysics_Car_System_Raycast_Wheels::CPhysics_Car_System_Raycast_Wheels( IVP_Environment *pEnv,
const IVP_Template_Car_System *pCarSystem )
: IVP_Controller_Raycast_Car( pEnv, pCarSystem )
{
InitCarSystemWheels( pCarSystem );
}
//-----------------------------------------------------------------------------
// Purpose: Deconstructor
//-----------------------------------------------------------------------------
CPhysics_Car_System_Raycast_Wheels::~CPhysics_Car_System_Raycast_Wheels()
{
}
//-----------------------------------------------------------------------------
// Purpose: Setup the car system wheels.
//-----------------------------------------------------------------------------
void CPhysics_Car_System_Raycast_Wheels::InitCarSystemWheels( const IVP_Template_Car_System *pCarSystem )
{
for ( int iWheel = 0; iWheel < pCarSystem->n_wheels; ++iWheel )
{
m_pWheels[iWheel] = pCarSystem->car_wheel[iWheel];
m_pWheels[iWheel]->enable_collision_detection( IVP_FALSE );
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the raycast wheel.
//-----------------------------------------------------------------------------
IPhysicsObject *CPhysics_Car_System_Raycast_Wheels::GetWheel( int index )
{
Assert( index >= 0 );
Assert( index < n_wheels );
return ( IPhysicsObject* )m_pWheels[index]->client_data;
}
//-----------------------------------------------------------------------------
// Purpose: Setup the car system wheels.
//-----------------------------------------------------------------------------
void CPhysics_Car_System_Raycast_Wheels::do_raycasts( IVP_Event_Sim *es,
int n_wheels,
class IVP_Ray_Solver_Template *t_in,
class IVP_Ray_Hit *hits_out,
IVP_FLOAT *friction_of_object_out )
{
t_in[0].ray_flags = IVP_RAY_SOLVER_ALL;
int j = 0;
IVP_Ray_Solver_Min ray_solver0(&t_in[j]);
j++; if ( j >= n_wheels) j--;
IVP_Ray_Solver_Min ray_solver1(&t_in[j]);
j++; if ( j >= n_wheels) j--;
IVP_Ray_Solver_Min ray_solver2(&t_in[j]);
j++; if ( j >= n_wheels) j--;
IVP_Ray_Solver_Min ray_solver3(&t_in[j]);
IVP_Ray_Solver_Min *solvers[4] = { &ray_solver0, &ray_solver1, &ray_solver2, &ray_solver3 };
IVP_Ray_Solver_Group rs_group( n_wheels, (IVP_Ray_Solver **)solvers );
#if 0
// Debug!
IVP_CarSystemDebugData_t carSystemDebugData;
GetCarSystemDebugData( carSystemDebugData );
carSystemDebugData.wheelRaycasts[0][0] = ray_solver0.ray_start_point;
carSystemDebugData.wheelRaycasts[0][1] = ray_solver0.ray_end_point;
carSystemDebugData.wheelRaycasts[1][0] = ray_solver1.ray_start_point;
carSystemDebugData.wheelRaycasts[1][1] = ray_solver1.ray_end_point;
carSystemDebugData.wheelRaycasts[2][0] = ray_solver2.ray_start_point;
carSystemDebugData.wheelRaycasts[2][1] = ray_solver2.ray_end_point;
carSystemDebugData.wheelRaycasts[3][0] = ray_solver3.ray_start_point;
carSystemDebugData.wheelRaycasts[3][1] = ray_solver3.ray_end_point;
#endif
// check which objects are hit
rs_group.check_ray_group_against_all_objects_in_sim(es->environment);
for ( int i = 0; i < n_wheels; i++ )
{
IVP_Ray_Hit *hit = solvers[i]->get_ray_hit();
if (hit)
{
hits_out[i] = *hit;
friction_of_object_out[i] = hit->hit_real_object->l_default_material->get_friction_factor();
#if 0
// Debug!
carSystemDebugData.wheelRaycastImpacts[i] = ( hit->hit_distance / solvers[i]->ray_length );
#endif
}
else
{
memset( &hits_out[i], 0, sizeof(IVP_Ray_Hit) );
friction_of_object_out[i] = 0;
#if 0
// Debug!
carSystemDebugData.wheelRaycastImpacts[i] = 0.0f;
#endif
}
}
#if 0
// Debug!
SetCarSystemDebugData( carSystemDebugData );
#endif
}
void CPhysics_Car_System_Raycast_Wheels::update_wheel_positions( void )
{
// Get the car body object.
IVP_Cache_Object *pCacheObject = car_body->get_cache_object();
// Get the core (vehicle) matrix.
IVP_U_Matrix m_core_f_object;
car_body->calc_m_core_f_object( &m_core_f_object );
for ( int iWheel = 0; iWheel < n_wheels; ++iWheel )
{
// Get the current raycast wheel.
IVP_Raycast_Car_Wheel *pRaycastWheel = get_wheel( IVP_POS_WHEEL( iWheel ) );
// Get the position of the wheel in vehicle core space.
IVP_U_Float_Point hp_cs;
hp_cs.add_multiple( &pRaycastWheel->hp_cs, &pRaycastWheel->spring_direction_cs, pRaycastWheel->raycast_dist - pRaycastWheel->wheel_radius );
// Get the position on vehicle object space (inverse transform).
IVP_U_Float_Point hp_os;
m_core_f_object.vimult4( &hp_cs, &hp_os );
// Transform the wheel position from object space into world space.
IVP_U_Point hp_ws;
pCacheObject->transform_position_to_world_coords( &hp_os, &hp_ws );
// Apply rotational component.
IVP_U_Point wheel_cs( &pRaycastWheel->axis_direction_cs );
IVP_U_Point wheel2_cs( 0 ,0 ,0 );
wheel2_cs.k[index_y] = -1.0;
wheel2_cs.rotate( IVP_COORDINATE_INDEX( index_x ), pRaycastWheel->angle_wheel );
IVP_U_Matrix3 m_core_f_wheel;
m_core_f_wheel.init_normized3_col( &wheel_cs, IVP_COORDINATE_INDEX( index_x ), &wheel2_cs );
IVP_U_Matrix3 m_world_f_wheel;
pCacheObject->m_world_f_object.mmult3( &m_core_f_wheel, &m_world_f_wheel ); // bid hack, assumes cs = os (for rotation);
IVP_U_Quat rot_ws;
rot_ws.set_quaternion( &m_world_f_wheel );
m_pWheels[iWheel]->beam_object_to_new_position( &rot_ws, &hp_ws );
}
pCacheObject->remove_reference();
}

View File

@ -0,0 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PHYSICS_CONTROLLER_RAYCAST_VEHICLE_H
#define PHYSICS_CONTROLLER_RAYCAST_VEHICLE_H
#ifdef _WIN32
#pragma once
#endif
#include "ivp_controller.hxx"
#include "ivp_car_system.hxx"
#include "ivp_controller_raycast_car.hxx"
class IPhysicsObject;
//=============================================================================
//
// Raycast Car System
//
class CPhysics_Car_System_Raycast_Wheels : public IVP_Controller_Raycast_Car
{
public:
CPhysics_Car_System_Raycast_Wheels( IVP_Environment *env, const IVP_Template_Car_System *t );
virtual ~CPhysics_Car_System_Raycast_Wheels();
virtual void do_raycasts( IVP_Event_Sim *, int n_wheels, IVP_Ray_Solver_Template *t_in,
IVP_Ray_Hit *hits_out, IVP_FLOAT *friction_of_object_out );
void update_wheel_positions( void );
IPhysicsObject *GetWheel( int index );
virtual const char *get_controller_name() { return "sys:vehicle"; }
protected:
void InitCarSystemWheels( const IVP_Template_Car_System *pCarSystem );
IVP_Real_Object *m_pWheels[IVP_RAYCAST_CAR_MAX_WHEELS];
};
#endif // PHYSICS_CONTROLLER_RAYCAST_VEHICLE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_WORLD_H
#define PHYSICS_WORLD_H
#pragma once
#include "vphysics_interface.h"
#include "ivu_types.hxx"
#include "utlvector.h"
#include "physics_globals.h"
class IVP_Environment;
class CSleepObjects;
class CPhysicsListenerCollision;
class CPhysicsListenerConstraint;
class IVP_Listener_Collision;
class IVP_Listener_Constraint;
class IVP_Listener_Object;
class IVP_Controller;
class CPhysicsFluidController;
class CCollisionSolver;
class CPhysicsObject;
class CDeleteQueue;
class IVPhysicsDebugOverlay;
struct constraint_limitedhingeparams_t;
struct vphysics_save_iphysicsobject_t;
class CPhysicsEnvironment : public IPhysicsEnvironment
{
public:
CPhysicsEnvironment( void );
~CPhysicsEnvironment( void );
virtual void SetDebugOverlay( CreateInterfaceFn debugOverlayFactory );
virtual IVPhysicsDebugOverlay *GetDebugOverlay( void );
void SetGravity( const Vector& gravityVector );
IPhysicsObject *CreatePolyObject( const CPhysCollide *pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t *pParams );
IPhysicsObject *CreatePolyObjectStatic( const CPhysCollide *pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t *pParams );
virtual unsigned int GetObjectSerializeSize( IPhysicsObject *pObject ) const;
virtual void SerializeObjectToBuffer( IPhysicsObject *pObject, unsigned char *pBuffer, unsigned int bufferSize );
virtual IPhysicsObject *UnserializeObjectFromBuffer( void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions );
PxScene *GetPxScene() { return m_pPxScene; }
IPhysicsSpring *CreateSpring( IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, springparams_t *pParams );
IPhysicsFluidController *CreateFluidController( IPhysicsObject *pFluidObject, fluidparams_t *pParams );
IPhysicsConstraint *CreateRagdollConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll );
virtual IPhysicsConstraint *CreateHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge );
virtual IPhysicsConstraint *CreateLimitedHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_limitedhingeparams_t &hinge );
virtual IPhysicsConstraint *CreateFixedConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed );
virtual IPhysicsConstraint *CreateSlidingConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding );
virtual IPhysicsConstraint *CreateBallsocketConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket );
virtual IPhysicsConstraint *CreatePulleyConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley );
virtual IPhysicsConstraint *CreateLengthConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length );
virtual IPhysicsConstraintGroup *CreateConstraintGroup( const constraint_groupparams_t &group );
virtual void DestroyConstraintGroup( IPhysicsConstraintGroup *pGroup );
void Simulate( float deltaTime );
float GetSimulationTimestep() const;
void SetSimulationTimestep( float timestep );
float GetSimulationTime() const;
float GetNextFrameTime() const;
bool IsInSimulation() const;
virtual void DestroyObject( IPhysicsObject * );
virtual void DestroySpring( IPhysicsSpring * );
virtual void DestroyFluidController( IPhysicsFluidController * );
virtual void DestroyConstraint( IPhysicsConstraint * );
virtual void SetCollisionEventHandler( IPhysicsCollisionEvent *pCollisionEvents );
virtual void SetObjectEventHandler( IPhysicsObjectEvent *pObjectEvents );
virtual void SetConstraintEventHandler( IPhysicsConstraintEvent *pConstraintEvents );
virtual IPhysicsShadowController *CreateShadowController( IPhysicsObject *pObject, bool allowTranslation, bool allowRotation );
virtual void DestroyShadowController( IPhysicsShadowController * );
virtual IPhysicsMotionController *CreateMotionController( IMotionEvent *pHandler );
virtual void DestroyMotionController( IPhysicsMotionController *pController );
virtual IPhysicsPlayerController *CreatePlayerController( IPhysicsObject *pObject );
virtual void DestroyPlayerController( IPhysicsPlayerController *pController );
virtual IPhysicsVehicleController *CreateVehicleController( IPhysicsObject *pVehicleBodyObject, const vehicleparams_t &params, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace );
virtual void DestroyVehicleController( IPhysicsVehicleController *pController );
virtual void SetQuickDelete( bool bQuick )
{
m_deleteQuick = bQuick;
}
virtual bool ShouldQuickDelete() const { return m_deleteQuick; }
virtual void TraceBox( trace_t *ptr, const Vector &mins, const Vector &maxs, const Vector &start, const Vector &end );
virtual void SetCollisionSolver( IPhysicsCollisionSolver *pCollisionSolver );
virtual void GetGravity( Vector *pGravityVector ) const;
virtual int GetActiveObjectCount() const;
virtual void GetActiveObjects( IPhysicsObject **pOutputObjectList ) const;
virtual const IPhysicsObject **GetObjectList( int *pOutputObjectCount ) const;
virtual bool TransferObject( IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment );
IVP_Environment *GetIVPEnvironment( void ) { return m_pPhysEnv; }
void ClearDeadObjects( void );
IVP_Controller *GetDragController() { return m_pDragController; }
const IVP_Controller *GetDragController() const { return m_pDragController; }
virtual void SetAirDensity( float density );
virtual float GetAirDensity( void ) const;
virtual void ResetSimulationClock( void );
virtual IPhysicsObject *CreateSphereObject( float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic );
virtual void CleanupDeleteList();
virtual void EnableDeleteQueue( bool enable ) { m_queueDeleteObject = enable; }
// debug
virtual bool IsCollisionModelUsed( CPhysCollide *pCollide ) const;
// trace against the physics world
virtual void TraceRay( const Ray_t &ray, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace );
virtual void SweepCollideable( const CPhysCollide *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd,
const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace );
// performance tuning
virtual void GetPerformanceSettings( physics_performanceparams_t *pOutput ) const;
virtual void SetPerformanceSettings( const physics_performanceparams_t *pSettings );
// perf/cost statistics
virtual void ReadStats( physics_stats_t *pOutput );
virtual void ClearStats();
virtual void EnableConstraintNotify( bool bEnable );
// debug
virtual void DebugCheckContacts(void);
// Save/restore
bool Save( const physsaveparams_t &params );
void PreRestore( const physprerestoreparams_t &params );
bool Restore( const physrestoreparams_t &params );
void PostRestore();
void PhantomAdd( CPhysicsObject *pObject );
void PhantomRemove( CPhysicsObject *pObject );
void AddPlayerController( IPhysicsPlayerController *pController );
void RemovePlayerController( IPhysicsPlayerController *pController );
IPhysicsPlayerController *FindPlayerController( IPhysicsObject *pObject );
IPhysicsCollisionEvent *GetCollisionEventHandler();
// a constraint is being disabled - report the game DLL as "broken"
void NotifyConstraintDisabled( IPhysicsConstraint *pConstraint );
private:
IVP_Environment *m_pPhysEnv;
IVP_Controller *m_pDragController;
IVPhysicsDebugOverlay *m_pDebugOverlay; // Interface to use for drawing debug overlays.
CUtlVector<IPhysicsObject *> m_objects;
CUtlVector<IPhysicsObject *> m_deadObjects;
CUtlVector<CPhysicsFluidController *> m_fluids;
CUtlVector<IPhysicsPlayerController *> m_playerControllers;
CSleepObjects *m_pSleepEvents;
CPhysicsListenerCollision *m_pCollisionListener;
CCollisionSolver *m_pCollisionSolver;
CPhysicsListenerConstraint *m_pConstraintListener;
CDeleteQueue *m_pDeleteQueue;
int m_lastObjectThisTick;
bool m_deleteQuick;
bool m_inSimulation;
bool m_queueDeleteObject;
bool m_fixedTimestep;
bool m_enableConstraintNotify;
PxDefaultCpuDispatcher *m_pPxDispatcher;
PxScene *m_pPxScene;
};
extern IPhysicsEnvironment *CreatePhysicsEnvironment( void );
class IVP_Synapse_Friction;
class IVP_Real_Object;
extern IVP_Real_Object *GetOppositeSynapseObject( IVP_Synapse_Friction *pfriction );
extern IPhysicsObjectPairHash *CreateObjectPairHash();
#endif // PHYSICS_WORLD_H

View File

@ -0,0 +1,233 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "physics_fluid.h"
#include "ivp_compact_surface.hxx"
#include "ivp_surman_polygon.hxx"
#include "ivp_phantom.hxx"
#include "ivp_controller_buoyancy.hxx"
#include "ivp_liquid_surface_descript.hxx"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// NOTE: This is auto-deleted by the phantom controller
class CBuoyancyAttacher : public IVP_Attacher_To_Cores_Buoyancy
{
public:
virtual IVP_Template_Buoyancy *get_parameters_per_core( IVP_Core *pCore );
CBuoyancyAttacher(IVP_Template_Buoyancy &templ, IVP_U_Set_Active<IVP_Core> *set_of_cores_, IVP_Liquid_Surface_Descriptor *liquid_surface_descriptor_);
float m_density;
};
CPhysicsFluidController::CPhysicsFluidController( CBuoyancyAttacher *pBuoy, IVP_Liquid_Surface_Descriptor *pLiquid, CPhysicsObject *pObject, int nContents )
{
m_pBuoyancy = pBuoy;
m_pLiquidSurface = pLiquid;
m_pObject = pObject;
m_nContents = nContents;
}
CPhysicsFluidController::~CPhysicsFluidController( void )
{
delete m_pLiquidSurface;
}
void CPhysicsFluidController::SetGameData( void *pGameData )
{
m_pGameData = pGameData;
}
void *CPhysicsFluidController::GetGameData( void ) const
{
return m_pGameData;
}
void CPhysicsFluidController::GetSurfacePlane( Vector *pNormal, float *pDist ) const
{
IVP_U_Float_Hesse surface;
IVP_U_Float_Point abs_speed_of_current;
m_pLiquidSurface->calc_liquid_surface( GetIVPObject()->get_core()->environment,
GetIVPObject()->get_core(), &surface, &abs_speed_of_current );
ConvertPlaneToHL( surface, pNormal, pDist );
if ( pNormal )
{
*pNormal *= -1;
}
if ( pDist )
{
*pDist *= -1;
}
}
IVP_Real_Object *CPhysicsFluidController::GetIVPObject()
{
return m_pObject->GetObject();
}
const IVP_Real_Object *CPhysicsFluidController::GetIVPObject() const
{
return m_pObject->GetObject();
}
float CPhysicsFluidController::GetDensity() const
{
return m_pBuoyancy->m_density;
}
void CPhysicsFluidController::WakeAllSleepingObjects()
{
GetIVPObject()->get_controller_phantom()->wake_all_sleeping_objects();
}
int CPhysicsFluidController::GetContents() const
{
return m_nContents;
}
IVP_Template_Buoyancy *CBuoyancyAttacher::get_parameters_per_core( IVP_Core *pCore )
{
if ( pCore )
{
IVP_Real_Object *pivp = pCore->objects.element_at(0);
CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pivp->client_data);
// This ratio is for objects whose mass / (collision model) volume is not equal to their density.
// Keep the fluid pressure/friction solution for the volume, but scale the buoyant force calculations
// to be in line with the object's real density. This is accompilshed by changing the fluid's density
// on a per-object basis.
float ratio = pPhys->GetBuoyancyRatio();
if ( pPhys->GetShadowController() || !(pPhys->CallbackFlags() & CALLBACK_DO_FLUID_SIMULATION) )
{
// NOTE: don't do buoyancy on these guys for now!
template_buoyancy.medium_density = 0;
}
else
{
template_buoyancy.medium_density = m_density * ratio;
}
}
else
{
template_buoyancy.medium_density = m_density;
}
return &template_buoyancy;
}
CBuoyancyAttacher::CBuoyancyAttacher(IVP_Template_Buoyancy &templ, IVP_U_Set_Active<IVP_Core> *set_of_cores_, IVP_Liquid_Surface_Descriptor *liquid_surface_descriptor_)
:IVP_Attacher_To_Cores_Buoyancy(templ, set_of_cores_, liquid_surface_descriptor_)
{
m_density = templ.medium_density;
}
//-----------------------------------------------------------------------------
// Defines the surface descriptor in local space
//-----------------------------------------------------------------------------
class CLiquidSurfaceDescriptor : public IVP_Liquid_Surface_Descriptor
{
public:
CLiquidSurfaceDescriptor( CPhysicsObject *pFluidObject, const Vector4D &plane, const Vector &current )
{
cplane_t worldPlane;
worldPlane.normal = plane.AsVector3D();
worldPlane.dist = plane[3];
matrix3x4_t matObjectToWorld;
pFluidObject->GetPositionMatrix( &matObjectToWorld );
MatrixITransformPlane( matObjectToWorld, worldPlane, m_objectSpacePlane );
VectorIRotate( current, matObjectToWorld, m_vecObjectSpaceCurrent );
m_pFluidObject = pFluidObject;
}
virtual void calc_liquid_surface( IVP_Environment * /*environment*/,
IVP_Core * /*core*/,
IVP_U_Float_Hesse *surface_normal_out,
IVP_U_Float_Point *abs_speed_of_current_out)
{
cplane_t worldPlane;
matrix3x4_t matObjectToWorld;
m_pFluidObject->GetPositionMatrix( &matObjectToWorld );
MatrixTransformPlane( matObjectToWorld, m_objectSpacePlane, worldPlane );
worldPlane.normal *= -1.0f;
worldPlane.dist *= -1.0f;
IVP_U_Float_Hesse worldSurface;
ConvertPlaneToIVP( worldPlane.normal, worldPlane.dist, worldSurface );
surface_normal_out->set(&worldSurface);
surface_normal_out->hesse_val = worldSurface.hesse_val;
Vector worldSpaceCurrent;
VectorRotate( m_vecObjectSpaceCurrent, matObjectToWorld, worldSpaceCurrent );
IVP_U_Float_Point ivpWorldSpaceCurrent;
ConvertDirectionToIVP( worldSpaceCurrent, ivpWorldSpaceCurrent );
abs_speed_of_current_out->set( &ivpWorldSpaceCurrent );
}
private:
Vector m_vecObjectSpaceCurrent;
cplane_t m_objectSpacePlane;
CPhysicsObject *m_pFluidObject;
};
CPhysicsFluidController *CreateFluidController( IVP_Environment *pEnvironment, CPhysicsObject *pFluidObject, fluidparams_t *pParams )
{
pFluidObject->BecomeTrigger();
return NULL;
IVP_Controller_Phantom *pPhantom = pFluidObject->GetObject()->get_controller_phantom();
if ( !pPhantom )
return NULL;
IVP_Liquid_Surface_Descriptor *lsd = new CLiquidSurfaceDescriptor( pFluidObject, pParams->surfacePlane, pParams->currentVelocity );
int surfaceprops = pFluidObject->GetMaterialIndex();
float density = physprops->GetSurfaceData( surfaceprops )->physics.density;
// ---------------------------------------------
// create parameter template for Buoyancy_Solver
// ---------------------------------------------
// UNDONE: Expose these other parametersd
IVP_Template_Buoyancy buoyancy_input;
buoyancy_input.medium_density = ConvertDensityToIVP(density); // density of water (unit: kg/m^3)
buoyancy_input.pressure_damp_factor = pParams->damping;
buoyancy_input.viscosity_factor = 0.0f;
buoyancy_input.torque_factor = 0.01f;
buoyancy_input.viscosity_input_factor = 0.1f;
// -------------------------------------------------------------------------------
// create "water" (i.e. buoyancy solver) and attach a dynamic list of object cores
// -------------------------------------------------------------------------------
CBuoyancyAttacher *attacher_to_cores_buoyancy = new CBuoyancyAttacher( buoyancy_input, pPhantom->get_intruding_cores(), lsd );
CPhysicsFluidController *pFluid = new CPhysicsFluidController( attacher_to_cores_buoyancy, lsd, pFluidObject, pParams->contents );
pFluid->SetGameData( pParams->pGameData );
pPhantom->client_data = static_cast<void *>(pFluid);
return pFluid;
}
bool SavePhysicsFluidController( const physsaveparams_t &params, CPhysicsFluidController *pFluidObject )
{
return false;
}
bool RestorePhysicsFluidController( const physrestoreparams_t &params, CPhysicsFluidController **ppFluidObject )
{
return false;
}

View File

@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_FLUID_H
#define PHYSICS_FLUID_H
#pragma once
#include "vphysics_interface.h"
class IVP_Compact_Surface;
class IVP_Environment;
class IVP_Listener_Phantom;
class CBuoyancyAttacher;
class IVP_Liquid_Surface_Descriptor;
class CPhysicsObject;
class CPhysicsObject;
class CPhysicsFluidController : public IPhysicsFluidController
{
public:
CPhysicsFluidController( CBuoyancyAttacher *pBuoy, IVP_Liquid_Surface_Descriptor *pLiquid, CPhysicsObject *pObject, int nContents );
~CPhysicsFluidController( void );
virtual void SetGameData( void *pGameData );
virtual void *GetGameData( void ) const;
virtual void GetSurfacePlane( Vector *pNormal, float *pDist ) const;
virtual float GetDensity() const;
virtual void WakeAllSleepingObjects();
virtual int GetContents() const;
class IVP_Real_Object *GetIVPObject();
const class IVP_Real_Object *GetIVPObject() const;
private:
CBuoyancyAttacher *m_pBuoyancy;
IVP_Liquid_Surface_Descriptor *m_pLiquidSurface;
CPhysicsObject *m_pObject;
int m_nContents;
void *m_pGameData;
};
extern CPhysicsFluidController *CreateFluidController( IVP_Environment *pEnvironment, CPhysicsObject *pFluidObject, fluidparams_t *pParams );
#endif // PHYSICS_FLUID_H

View File

@ -0,0 +1,194 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "physics_friction.h"
#include "vphysics/friction.h"
#include "ivp_mindist.hxx"
#include "ivp_mindist_intern.hxx"
#include "ivp_listener_collision.hxx"
#include "ivp_friction.hxx"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CFrictionSnapshot : public IPhysicsFrictionSnapshot
{
public:
CFrictionSnapshot( IVP_Real_Object *pObject );
~CFrictionSnapshot();
bool IsValid();
// Object 0 is this object, Object 1 is the other object
IPhysicsObject *GetObject( int index );
int GetMaterial( int index );
void GetContactPoint( Vector &out );
void GetSurfaceNormal( Vector &out );
float GetNormalForce();
float GetEnergyAbsorbed();
void RecomputeFriction();
void ClearFrictionForce();
void MarkContactForDelete();
void DeleteAllMarkedContacts( bool wakeObjects );
void NextFrictionData();
float GetFrictionCoefficient();
private:
void SetFrictionSynapse( IVP_Synapse_Friction *pSet );
CUtlVector<IVP_Real_Object *> *m_pDeleteList;
IVP_Real_Object *m_pObject;
IVP_Synapse_Friction *m_pFriction;
IVP_Contact_Point *m_pContactPoint;
int m_synapseIndex;
};
CFrictionSnapshot::CFrictionSnapshot( IVP_Real_Object *pObject ) : m_pObject(pObject)
{
m_pDeleteList = NULL;
//SetFrictionSynapse( pObject->get_first_friction_synapse() );
}
CFrictionSnapshot::~CFrictionSnapshot()
{
delete m_pDeleteList;
}
void CFrictionSnapshot::DeleteAllMarkedContacts( bool wakeObjects )
{
if ( !m_pDeleteList )
return;
for ( int i = 0; i < m_pDeleteList->Count(); i++ )
{
if ( wakeObjects )
{
m_pDeleteList->Element(i)->ensure_in_simulation();
}
DeleteAllFrictionPairs( m_pObject, m_pDeleteList->Element(i) );
}
m_pFriction = NULL;
}
void CFrictionSnapshot::SetFrictionSynapse( IVP_Synapse_Friction *pSet )
{
if ( pSet )
{
m_pFriction = pSet;
m_pContactPoint = pSet->get_contact_point();
m_synapseIndex = (pSet == m_pContactPoint->get_synapse(0)) ? 0 : 1;
}
else
{
m_pFriction = NULL;
m_pContactPoint = NULL;
m_synapseIndex = 0;
}
}
bool CFrictionSnapshot::IsValid()
{
return m_pFriction != NULL ? true : false;
}
IPhysicsObject *CFrictionSnapshot::GetObject( int index )
{
return NULL;
}
void CFrictionSnapshot::MarkContactForDelete()
{
IVP_Synapse_Friction *pFriction = m_pContactPoint->get_synapse(!m_synapseIndex);
IVP_Real_Object *pObject = pFriction->get_object();
Assert(pObject != m_pObject);
if ( pObject != m_pObject )
{
if ( !m_pDeleteList )
{
m_pDeleteList = new CUtlVector<IVP_Real_Object *>;
}
m_pDeleteList->AddToTail( pObject );
}
}
int CFrictionSnapshot::GetMaterial( int index )
{
IVP_Material *ivpMats[2];
m_pContactPoint->get_material_info(ivpMats);
// index 1 is the other one
index ^= m_synapseIndex;
return physprops->GetIVPMaterialIndex( ivpMats[index] );
}
void CFrictionSnapshot::GetContactPoint( Vector &out )
{
ConvertPositionToHL( *m_pContactPoint->get_contact_point_ws(), out );
}
void CFrictionSnapshot::GetSurfaceNormal( Vector &out )
{
float sign[2] = {1,-1};
IVP_U_Float_Point normal;
IVP_Contact_Point_API::get_surface_normal_ws(const_cast<IVP_Contact_Point *>(m_pContactPoint), &normal );
ConvertDirectionToHL( normal, out );
out *= sign[m_synapseIndex];
VectorNormalize(out);
}
float CFrictionSnapshot::GetFrictionCoefficient()
{
return m_pContactPoint->get_friction_factor();
}
float CFrictionSnapshot::GetNormalForce()
{
return ConvertDistanceToHL( IVP_Contact_Point_API::get_vert_force( m_pContactPoint ) );
}
float CFrictionSnapshot::GetEnergyAbsorbed()
{
return ConvertEnergyToHL( IVP_Contact_Point_API::get_eliminated_energy( m_pContactPoint ) );
}
void CFrictionSnapshot::RecomputeFriction()
{
m_pContactPoint->recompute_friction();
}
void CFrictionSnapshot::ClearFrictionForce()
{
m_pContactPoint->set_friction_to_neutral();
}
void CFrictionSnapshot::NextFrictionData()
{
SetFrictionSynapse( m_pFriction->get_next() );
}
IPhysicsFrictionSnapshot *CreateFrictionSnapshot( IVP_Real_Object *pObject )
{
return new CFrictionSnapshot( pObject );
}
void DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot )
{
delete pSnapshot;
}
void DeleteAllFrictionPairs( IVP_Real_Object *pObject0, IVP_Real_Object *pObject1 )
{
pObject0->unlink_contact_points_for_object( pObject1 );
}

View File

@ -0,0 +1,21 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef PHYSICS_FRICTION_H
#define PHYSICS_FRICTION_H
#ifdef _WIN32
#pragma once
#endif
class IVP_Real_Object;
class IPhysicsFrictionSnapshot;
IPhysicsFrictionSnapshot *CreateFrictionSnapshot( IVP_Real_Object *pObject );
void DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot );
void DeleteAllFrictionPairs( IVP_Real_Object *pObject0, IVP_Real_Object *pObject1 );
#endif // PHYSICS_FRICTION_H

View File

@ -0,0 +1,8 @@
#include "PxPhysicsAPI.h"
using namespace physx;
extern PxFoundation *gPxFoundation;
extern PxPvd *gPxPvd;
extern PxPhysics *gPxPhysics;
extern PxCooking *gPxCooking;

View File

@ -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];
}
}

View File

@ -0,0 +1,34 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_MATERIAL_H
#define PHYSICS_MATERIAL_H
#pragma once
#include "vphysics_interface.h"
class IVP_Material;
class IVP_Material_Manager;
class IPhysicsSurfacePropsInternal : public IPhysicsSurfaceProps
{
public:
virtual IVP_Material *GetIVPMaterial( int materialIndex ) = 0;
virtual int GetIVPMaterialIndex( const IVP_Material *pIVP ) const = 0;
virtual IVP_Material_Manager *GetIVPManager( void ) = 0;
virtual int RemapIVPMaterialIndex( int ivpMaterialIndex ) const = 0;
};
extern IPhysicsSurfacePropsInternal *physprops;
// Special material indices outside of the normal system
enum
{
MATERIAL_INDEX_SHADOW = 0xF000,
};
#endif // PHYSICS_MATERIAL_H

View File

@ -0,0 +1,334 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifdef _WIN32
#pragma warning (disable:4127)
#pragma warning (disable:4244)
#endif
#include "cbase.h"
#include "ivp_controller.hxx"
#include "physics_motioncontroller.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
struct vphysics_save_motioncontroller_t
{
CUtlVector<IPhysicsObject *> m_objectList;
int m_nPriority;
DECLARE_SIMPLE_DATADESC();
};
BEGIN_SIMPLE_DATADESC( vphysics_save_motioncontroller_t )
DEFINE_VPHYSPTR_UTLVECTOR( m_objectList ),
DEFINE_FIELD( m_nPriority, FIELD_INTEGER ),
END_DATADESC()
class CPhysicsMotionController : public IVP_Controller_Independent, public IPhysicsMotionController
{
public:
CPhysicsMotionController( IMotionEvent *pHandler, CPhysicsEnvironment *pVEnv );
virtual ~CPhysicsMotionController( void );
virtual void do_simulation_controller(IVP_Event_Sim *event,IVP_U_Vector<IVP_Core> *core_list);
virtual IVP_CONTROLLER_PRIORITY get_controller_priority();
virtual void core_is_going_to_be_deleted_event(IVP_Core *core)
{
m_coreList.FindAndRemove( core );
}
virtual const char *get_controller_name() { return "vphysics:motion"; }
virtual void SetEventHandler( IMotionEvent *handler );
virtual void AttachObject( IPhysicsObject *pObject, bool checkIfAlreadyAttached );
virtual void DetachObject( IPhysicsObject *pObject );
void RemoveCore( IVP_Core *pCore );
// Save/load
void WriteToTemplate( vphysics_save_motioncontroller_t &controllerTemplate );
void InitFromTemplate( const vphysics_save_motioncontroller_t &controllerTemplate );
// returns the number of objects currently attached to the controller
virtual int CountObjects( void )
{
return m_coreList.Count();
}
// NOTE: pObjectList is an array with at least CountObjects() allocated
virtual void GetObjects( IPhysicsObject **pObjectList )
{
for ( int i = 0; i < m_coreList.Count(); i++ )
{
IVP_Core *pCore = m_coreList[i];
IVP_Real_Object *pivp = pCore->objects.element_at(0);
IPhysicsObject *pPhys = static_cast<IPhysicsObject *>(pivp->client_data);
// copy out
pObjectList[i] = pPhys;
}
}
// detaches all attached objects
virtual void ClearObjects( void )
{
while ( m_coreList.Count() )
{
int x = m_coreList.Count()-1;
IVP_Core *pCore = m_coreList[x];
RemoveCore( pCore );
}
}
// wakes up all attached objects
virtual void WakeObjects( void )
{
for ( int i = 0; i < m_coreList.Count(); i++ )
{
IVP_Core *pCore = m_coreList[i];
pCore->ensure_core_to_be_in_simulation();
}
}
virtual void SetPriority( priority_t priority );
private:
IMotionEvent *m_handler;
CUtlVector<IVP_Core *> m_coreList;
CPhysicsEnvironment *m_pVEnv;
int m_priority;
};
CPhysicsMotionController::CPhysicsMotionController( IMotionEvent *pHandler, CPhysicsEnvironment *pVEnv )
{
m_handler = pHandler;
m_pVEnv = pVEnv;
SetPriority( MEDIUM_PRIORITY );
}
CPhysicsMotionController::~CPhysicsMotionController( void )
{
Assert( !m_pVEnv->IsInSimulation() );
for ( int i = 0; i < m_coreList.Count(); i++ )
{
m_coreList[i]->rem_core_controller( (IVP_Controller *)this );
}
}
void CPhysicsMotionController::do_simulation_controller(IVP_Event_Sim *event,IVP_U_Vector<IVP_Core> *core_list)
{
if ( m_handler )
{
for ( int i = 0; i < core_list->len(); i++ )
{
IVP_U_Float_Point ivpSpeed, ivpRot;
IVP_Core *pCore = core_list->element_at(i);
IVP_Real_Object *pivp = pCore->objects.element_at(0);
IPhysicsObject *pPhys = static_cast<IPhysicsObject *>(pivp->client_data);
if ( !pPhys->IsMoveable() )
continue;
Vector speed;
AngularImpulse rot;
speed.Init();
rot.Init();
IMotionEvent::simresult_e ret = m_handler->Simulate( this, pPhys, event->delta_time, speed, rot );
switch( ret )
{
case IMotionEvent::SIM_NOTHING:
break;
case IMotionEvent::SIM_LOCAL_ACCELERATION:
{
ConvertForceImpulseToIVP( speed, ivpSpeed );
ConvertAngularImpulseToIVP( rot, ivpRot );
const IVP_U_Matrix *m_world_f_core = pCore->get_m_world_f_core_PSI();
// transform to world space
m_world_f_core->inline_vmult3( &ivpSpeed, &ivpSpeed );
// UNDONE: Put these values into speed change / rot_speed_change instead?
pCore->speed.add_multiple( &ivpSpeed, event->delta_time );
pCore->rot_speed.add_multiple( &ivpRot, event->delta_time );
}
break;
case IMotionEvent::SIM_LOCAL_FORCE:
{
ConvertForceImpulseToIVP( speed, ivpSpeed );
ConvertAngularImpulseToIVP( rot, ivpRot );
const IVP_U_Matrix *m_world_f_core = pCore->get_m_world_f_core_PSI();
// transform to world space
m_world_f_core->inline_vmult3( &ivpSpeed, &ivpSpeed );
pCore->center_push_core_multiple_ws( &ivpSpeed, event->delta_time );
pCore->rot_push_core_multiple_cs( &ivpRot, event->delta_time );
}
break;
case IMotionEvent::SIM_GLOBAL_ACCELERATION:
{
ConvertAngularImpulseToIVP( rot, ivpRot );
ConvertForceImpulseToIVP( speed, ivpSpeed );
pCore->speed.add_multiple( &ivpSpeed, event->delta_time );
pCore->rot_speed.add_multiple( &ivpRot, event->delta_time );
}
break;
case IMotionEvent::SIM_GLOBAL_FORCE:
{
ConvertAngularImpulseToIVP( rot, ivpRot );
ConvertForceImpulseToIVP( speed, ivpSpeed );
pCore->center_push_core_multiple_ws( &ivpSpeed, event->delta_time );
pCore->rot_push_core_multiple_cs( &ivpRot, event->delta_time );
}
break;
}
// TODO(mastercoms): apply sv_maxvelocity?
//pCore->apply_velocity_limit();
}
}
}
IVP_CONTROLLER_PRIORITY CPhysicsMotionController::get_controller_priority()
{
return (IVP_CONTROLLER_PRIORITY) m_priority;
}
void CPhysicsMotionController::SetPriority( priority_t priority )
{
switch ( priority )
{
case LOW_PRIORITY:
m_priority = IVP_CP_CONSTRAINTS_MIN;
break;
default:
case MEDIUM_PRIORITY:
m_priority = IVP_CP_MOTION;
break;
case HIGH_PRIORITY:
m_priority = IVP_CP_FORCEFIELDS+1;
break;
}
}
void CPhysicsMotionController::SetEventHandler( IMotionEvent *handler )
{
m_handler = handler;
}
void CPhysicsMotionController::AttachObject( IPhysicsObject *pObject, bool checkIfAlreadyAttached )
{
// BUGBUG: Sometimes restore comes back with a NULL, REVISIT
if ( !pObject || pObject->IsStatic() )
return;
CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pObject);
IVP_Real_Object *pIVP = pPhys->GetObject();
IVP_Core *pCore = pIVP->get_core();
// UNDONE: On save/load, trigger-based motion controllers re-attach their objects.
// UNDONE: Do something cheaper about this?
// OPTIMIZE: Linear search here?
if ( checkIfAlreadyAttached )
{
int index = m_coreList.Find(pCore);
if ( m_coreList.IsValidIndex(index) )
{
DevMsg(1,"Attached core twice!!!\n");
return;
}
}
m_coreList.AddToTail( pCore );
MEM_ALLOC_CREDIT();
pCore->add_core_controller( (IVP_Controller *)this );
}
void CPhysicsMotionController::RemoveCore( IVP_Core *pCore )
{
int index = m_coreList.Find(pCore);
if ( !m_coreList.IsValidIndex(index) )
{
#if DEBUG
Msg("removed invalid core !!!\n");
#endif
return;
}
//Assert( !m_pVEnv->IsInSimulation() );
m_coreList.Remove( index );
pCore->rem_core_controller( static_cast<IVP_Controller_Independent *>(this) );
}
void CPhysicsMotionController::DetachObject( IPhysicsObject *pObject )
{
CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pObject);
IVP_Real_Object *pIVP = pPhys->GetObject();
IVP_Core *core = pIVP->get_core();
RemoveCore(core);
}
// Save/load
void CPhysicsMotionController::WriteToTemplate( vphysics_save_motioncontroller_t &controllerTemplate )
{
controllerTemplate.m_nPriority = m_priority;
int nObjectCount = CountObjects();
controllerTemplate.m_objectList.AddMultipleToTail( nObjectCount );
GetObjects( controllerTemplate.m_objectList.Base() );
}
void CPhysicsMotionController::InitFromTemplate( const vphysics_save_motioncontroller_t &controllerTemplate )
{
m_priority = controllerTemplate.m_nPriority;
int nObjectCount = controllerTemplate.m_objectList.Count();
for ( int i = 0; i < nObjectCount; ++i )
{
AttachObject( controllerTemplate.m_objectList[i], true );
}
}
IPhysicsMotionController *CreateMotionController( CPhysicsEnvironment *pPhysEnv, IMotionEvent *pHandler )
{
if ( !pHandler )
return NULL;
return new CPhysicsMotionController( pHandler, pPhysEnv );
}
bool SavePhysicsMotionController( const physsaveparams_t &params, IPhysicsMotionController *pMotionController )
{
vphysics_save_motioncontroller_t controllerTemplate;
memset( &controllerTemplate, 0, sizeof(controllerTemplate) );
CPhysicsMotionController *pControllerImp = static_cast<CPhysicsMotionController*>(pMotionController);
pControllerImp->WriteToTemplate( controllerTemplate );
params.pSave->WriteAll( &controllerTemplate );
return true;
}
bool RestorePhysicsMotionController( const physrestoreparams_t &params, IPhysicsMotionController **ppMotionController )
{
CPhysicsMotionController *pControllerImp = new CPhysicsMotionController( NULL, static_cast<CPhysicsEnvironment *>(params.pEnvironment) );
vphysics_save_motioncontroller_t controllerTemplate;
memset( &controllerTemplate, 0, sizeof(controllerTemplate) );
params.pRestore->ReadAll( &controllerTemplate );
pControllerImp->InitFromTemplate( controllerTemplate );
*ppMotionController = pControllerImp;
return true;
}

View File

@ -0,0 +1,20 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_MOTIONCONTROLLER_H
#define PHYSICS_MOTIONCONTROLLER_H
#ifdef _WIN32
#pragma once
#endif
class IPhysicsMotionController;
class CPhysicsEnvironment;
class IMotionEvent;
IPhysicsMotionController *CreateMotionController( CPhysicsEnvironment *pEnv, IMotionEvent *pHandler );
#endif // PHYSICS_MOTIONCONTROLLER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,288 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_OBJECT_H
#define PHYSICS_OBJECT_H
#ifdef _WIN32
#pragma once
#endif
#include "vphysics_interface.h"
class IVP_Real_Object;
class IVP_Environment;
class IVP_U_Float_Point;
class IVP_SurfaceManager;
class IVP_Controller;
class CPhysicsEnvironment;
struct vphysics_save_cphysicsobject_t
{
const CPhysCollide *pCollide;
const char *pName;
float sphereRadius;
bool isStatic;
bool collisionEnabled;
bool gravityEnabled;
bool dragEnabled;
bool motionEnabled;
bool isAsleep;
bool isTrigger;
bool asleepSinceCreation; // has this been asleep since creation?
bool hasTouchedDynamic;
bool hasShadowController;
short collideType;
unsigned short gameIndex;
int hingeAxis;
int materialIndex;
float mass;
Vector rotInertia;
float speedDamping;
float rotSpeedDamping;
Vector massCenterOverride;
unsigned int callbacks;
unsigned int gameFlags;
unsigned int contentsMask;
float volume;
float dragCoefficient;
float angDragCoefficient;
IPhysicsShadowController *pShadow;
//bool m_shadowTempGravityDisable;
Vector origin;
QAngle angles;
Vector velocity;
AngularImpulse angVelocity;
DECLARE_SIMPLE_DATADESC();
};
enum
{
OBJ_AWAKE = 0, // awake, simulating
OBJ_STARTSLEEP = 1, // going to sleep, but not queried yet
OBJ_SLEEP = 2, // sleeping, no state changes since last query
};
class CPhysicsObject : public IPhysicsObject
{
public:
CPhysicsObject( void );
virtual ~CPhysicsObject( void );
void Init( const CPhysCollide *pCollisionModel, IVP_Real_Object *pObject, int materialIndex, float volume, float drag, float angDrag );
// IPhysicsObject functions
bool IsStatic() const;
bool IsAsleep() const;
bool IsTrigger() const;
bool IsFluid() const;
bool IsHinged() const { return (m_hingedAxis != 0) ? true : false; }
bool IsCollisionEnabled() const;
bool IsGravityEnabled() const;
bool IsDragEnabled() const;
bool IsMotionEnabled() const;
bool IsMoveable() const;
bool IsAttachedToConstraint( bool bExternalOnly ) const;
void EnableCollisions( bool enable );
// Enable / disable gravity for this object
void EnableGravity( bool enable );
// Enable / disable air friction / drag for this object
void EnableDrag( bool enable );
void EnableMotion( bool enable );
void SetGameData( void *pAppData );
void *GetGameData( void ) const;
void SetCallbackFlags( unsigned short callbackflags );
unsigned short GetCallbackFlags( void ) const;
void SetGameFlags( unsigned short userFlags );
unsigned short GetGameFlags( void ) const;
void SetGameIndex( unsigned short gameIndex );
unsigned short GetGameIndex( void ) const;
void Wake();
void WakeNow();
void Sleep();
void RecheckCollisionFilter();
void RecheckContactPoints();
void SetMass( float mass );
float GetMass( void ) const;
float GetInvMass( void ) const;
void SetInertia( const Vector &inertia );
Vector GetInertia( void ) const;
Vector GetInvInertia( void ) const;
void GetDamping( float *speed, float *rot ) const;
void SetDamping( const float *speed, const float *rot );
void SetDragCoefficient( float *pDrag, float *pAngularDrag );
void SetBuoyancyRatio( float ratio );
int GetMaterialIndex() const { return GetMaterialIndexInternal(); }
void SetMaterialIndex( int materialIndex );
inline int GetMaterialIndexInternal( void ) const { return m_materialIndex; }
unsigned int GetContents() const { return m_contentsMask; }
void SetContents( unsigned int contents );
float GetSphereRadius() const;
Vector GetMassCenterLocalSpace() const;
float GetEnergy() const;
void SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport = false );
void SetPositionMatrix( const matrix3x4_t& matrix, bool isTeleport = false );
void GetPosition( Vector *worldPosition, QAngle *angles ) const;
void GetPositionMatrix( matrix3x4_t *positionMatrix ) const;
void SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity );
void SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity );
void AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity );
void GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const;
void GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const;
void GetVelocityAtPoint( const Vector &worldPosition, Vector *pVelocity ) const;
void LocalToWorld( Vector *worldPosition, const Vector &localPosition ) const;
void WorldToLocal( Vector *localPosition, const Vector &worldPosition ) const;
void LocalToWorldVector( Vector *worldVector, const Vector &localVector ) const;
void WorldToLocalVector( Vector *localVector, const Vector &worldVector ) const;
void ApplyForceCenter( const Vector &forceVector );
void ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition );
void ApplyTorqueCenter( const AngularImpulse & );
void CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) const;
void CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) const;
float CalculateLinearDrag( const Vector &unitDirection ) const;
float CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const;
bool GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) const;
void SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation );
void UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset );
void RemoveShadowController();
int GetShadowPosition( Vector *position, QAngle *angles ) const;
IPhysicsShadowController *GetShadowController( void ) const;
float ComputeShadowControl( const hlshadowcontrol_params_t &params, float secondsToArrival, float dt );
const CPhysCollide *GetCollide( void ) const;
char const *GetName() const;
float GetDragInDirection( const IVP_U_Float_Point &dir ) const;
float GetAngularDragInDirection( const IVP_U_Float_Point &angVelocity ) const;
void BecomeTrigger();
void RemoveTrigger();
void BecomeHinged( int localAxis );
void RemoveHinged();
IPhysicsFrictionSnapshot *CreateFrictionSnapshot();
void DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot );
void OutputDebugInfo() const;
// local functions
inline IVP_Real_Object *GetObject( void ) const { return m_pObject; }
inline int CallbackFlags( void ) const { return m_callbacks; }
inline void AddCallbackFlags( unsigned short flags ) { m_callbacks |= flags; }
inline void RemoveCallbackFlags( unsigned short flags ) { m_callbacks &= ~flags; }
inline bool HasTouchedDynamic();
inline void SetTouchedDynamic();
void NotifySleep( void );
void NotifyWake( void );
int GetSleepState( void ) const { return m_sleepState; }
inline void ForceSilentDelete() { m_forceSilentDelete = true; }
inline int GetActiveIndex( void ) const { return m_activeIndex; }
inline void SetActiveIndex( int index ) { m_activeIndex = index; }
inline float GetBuoyancyRatio( void ) const { return m_buoyancyRatio; }
// returns true if the mass center is set to the default for the collision model
bool IsMassCenterAtDefault() const;
// is this object simulated, or controlled by game logic?
bool IsControlledByGame() const;
IVP_SurfaceManager *GetSurfaceManager( void ) const;
void WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate );
void InitFromTemplate( CPhysicsEnvironment *pEnvironment, void *pGameData, const vphysics_save_cphysicsobject_t &objectTemplate );
CPhysicsEnvironment *GetVPhysicsEnvironment();
const CPhysicsEnvironment *GetVPhysicsEnvironment() const;
private:
// NOTE: Local to vphysics, used to save/restore shadow controller
void RestoreShadowController( IPhysicsShadowController *pShadowController );
friend bool RestorePhysicsObject( const physrestoreparams_t &params, CPhysicsObject **ppObject );
bool IsControlling( const IVP_Controller *pController ) const;
float GetVolume() const;
void SetVolume( float volume );
// the mass has changed, recompute the drag information
void RecomputeDragBases();
void ClampVelocity();
// NOTE: If m_pGameData is not the first member, the constructor debug code must be modified
void *m_pGameData;
IVP_Real_Object *m_pObject;
const CPhysCollide *m_pCollide;
IPhysicsShadowController *m_pShadow;
Vector m_dragBasis;
Vector m_angDragBasis;
// these 5 should pack into a short
// pack new bools here
bool m_shadowTempGravityDisable : 5;
bool m_hasTouchedDynamic : 1;
bool m_asleepSinceCreation : 1;
bool m_forceSilentDelete : 1;
unsigned char m_sleepState : 2;
unsigned char m_hingedAxis : 3;
unsigned char m_collideType : 3;
unsigned short m_gameIndex;
private:
unsigned short m_materialIndex;
unsigned short m_activeIndex;
unsigned short m_callbacks;
unsigned short m_gameFlags;
unsigned int m_contentsMask;
float m_volume;
float m_buoyancyRatio;
float m_dragCoefficient;
float m_angDragCoefficient;
friend CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle& angles, objectparams_t *pParams, bool isStatic );
friend bool CPhysicsEnvironment::TransferObject( IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment ); //need direct access to m_pShadow for Portal mod's physics object transfer system
};
// If you haven't ever touched a dynamic object, there's no need to search for contacting objects to
// wakeup when you are deleted. So cache a bit here when contacts are generated
inline bool CPhysicsObject::HasTouchedDynamic()
{
return m_hasTouchedDynamic;
}
inline void CPhysicsObject::SetTouchedDynamic()
{
m_hasTouchedDynamic = true;
}
extern CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic );
extern CPhysicsObject *CreatePhysicsSphere( CPhysicsEnvironment *pEnvironment, float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic );
extern void PostRestorePhysicsObject();
extern IPhysicsObject *CreateObjectFromBuffer( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions );
extern IPhysicsObject *CreateObjectFromBuffer_UseExistingMemory( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, CPhysicsObject *pExistingMemory );
#endif // PHYSICS_OBJECT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_SHADOW_H
#define PHYSICS_SHADOW_H
#pragma once
class CPhysicsObject;
class IPhysicsShadowController;
class IPhysicsPlayerController;
extern IPhysicsShadowController *CreateShadowController( CPhysicsObject *pObject, bool allowTranslation, bool allowRotation );
extern IPhysicsPlayerController *CreatePlayerController( CPhysicsObject *pObject );
extern void DestroyPlayerController( IPhysicsPlayerController *pController );
extern void ComputeController( IVP_U_Float_Point &currentSpeed, const IVP_U_Float_Point &delta, const IVP_U_Float_Point &maxSpeed, float scaleDelta, float damping );
#include "ivp_physics.hxx"
struct shadowcontrol_params_t
{
shadowcontrol_params_t()
{
lastPosition.set_to_zero();
lastImpulse.set_to_zero();
}
IVP_U_Point targetPosition;
IVP_U_Quat targetRotation;
IVP_U_Point lastPosition; // estimate for where the object should be, used to compute error for teleport
IVP_U_Float_Point lastImpulse; // Impulse applied last frame
float maxAngular;
float maxDampAngular;
float maxSpeed;
float maxDampSpeed;
float dampFactor;
float teleportDistance;
};
float ComputeShadowControllerHL( CPhysicsObject *pObject, const hlshadowcontrol_params_t &params, float secondsToArrival, float dt );
float ComputeShadowControllerIVP( IVP_Real_Object *pivp, shadowcontrol_params_t &params, float secondsToArrival, float dt );
#endif // PHYSICS_SHADOW_H

View File

@ -0,0 +1,286 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "ivp_actuator.hxx"
#include "ivp_actuator_spring.hxx"
#include "ivp_listener_object.hxx"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
struct vphysics_save_cphysicsspring_t : public springparams_t
{
CPhysicsObject *pObjStart;
CPhysicsObject *pObjEnd;
DECLARE_SIMPLE_DATADESC();
};
BEGIN_SIMPLE_DATADESC( vphysics_save_cphysicsspring_t )
DEFINE_FIELD( constant, FIELD_FLOAT ),
DEFINE_FIELD( naturalLength, FIELD_FLOAT ),
DEFINE_FIELD( damping, FIELD_FLOAT ),
DEFINE_FIELD( relativeDamping, FIELD_FLOAT ),
// NOTE: These are stored as *relative* vectors, so we don't use FIELD_POSITION_VECTOR
DEFINE_FIELD( startPosition, FIELD_VECTOR ),
DEFINE_FIELD( endPosition, FIELD_VECTOR ),
DEFINE_FIELD( useLocalPositions, FIELD_BOOLEAN ),
DEFINE_FIELD( onlyStretch, FIELD_BOOLEAN ),
DEFINE_VPHYSPTR( pObjStart ),
DEFINE_VPHYSPTR( pObjEnd ),
END_DATADESC()
// BUGBUG: No way to delete a spring because springs get auto-deleted without notification
// when an object they are attached to is deleted.
// So there is no way to tell if the pointer is valid.
class CPhysicsSpring : public IPhysicsSpring, public IVP_Listener_Object
{
public:
CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring );
~CPhysicsSpring();
// IPhysicsSpring
void GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd );
void SetSpringConstant( float flSpringContant);
void SetSpringDamping( float flSpringDamping);
void SetSpringLength( float flSpringLength);
IPhysicsObject *GetStartObject( void ) { return m_pObjStart; }
IPhysicsObject *GetEndObject( void ) { return m_pObjEnd; }
void AttachListener();
void DetachListener();
// Object listener
virtual void event_object_deleted( IVP_Event_Object *);
virtual void event_object_created( IVP_Event_Object *) {}
virtual void event_object_revived( IVP_Event_Object *) {}
virtual void event_object_frozen ( IVP_Event_Object *) {}
void WriteToTemplate( vphysics_save_cphysicsspring_t &params );
private:
CPhysicsSpring( void );
IVP_Actuator_Spring *m_pSpring;
CPhysicsObject *m_pObjStart;
CPhysicsObject *m_pObjEnd;
};
CPhysicsSpring::CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring ) : m_pSpring(pSpring)
{
m_pObjStart = pObjectStart;
m_pObjEnd = pObjectEnd;
AttachListener();
}
void CPhysicsSpring::AttachListener()
{
if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
{
m_pObjStart->GetObject()->add_listener_object( this );
}
if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
{
m_pObjEnd->GetObject()->add_listener_object( this );
}
}
CPhysicsSpring::~CPhysicsSpring()
{
if ( m_pSpring )
{
delete m_pSpring;
DetachListener();
}
}
void CPhysicsSpring::DetachListener()
{
if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
{
m_pObjStart->GetObject()->remove_listener_object( this );
}
if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
{
m_pObjEnd->GetObject()->remove_listener_object( this );
}
m_pObjStart = NULL;
m_pObjEnd = NULL;
m_pSpring = NULL;
}
void CPhysicsSpring::event_object_deleted( IVP_Event_Object * )
{
// the spring is going to delete itself now, so NULL it.
DetachListener();
}
void CPhysicsSpring::GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd )
{
Vector localHL;
if ( !m_pSpring )
return;
if ( worldPositionStart )
{
const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(0);
ConvertPositionToHL( anchor->object_pos, localHL );
m_pObjStart->LocalToWorld( worldPositionStart, localHL );
}
if ( worldPositionEnd )
{
const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(1);
ConvertPositionToHL( anchor->object_pos, localHL );
m_pObjEnd->LocalToWorld( worldPositionEnd, localHL );
}
}
void CPhysicsSpring::SetSpringConstant( float flSpringConstant )
{
if ( m_pSpring )
{
float currentConstant = m_pSpring->get_constant();
if ( currentConstant != flSpringConstant )
{
m_pSpring->set_constant(flSpringConstant);
}
}
}
void CPhysicsSpring::SetSpringDamping( float flSpringDamping )
{
if ( m_pSpring )
{
m_pSpring->set_damp(flSpringDamping);
}
}
void CPhysicsSpring::SetSpringLength( float flSpringLength )
{
if ( m_pSpring )
{
float currentLengthIVP = m_pSpring->get_spring_length_zero_force();
float desiredLengthIVP = ConvertDistanceToIVP(flSpringLength);
// must change enough, or skip to keep objects sleeping
const float SPRING_LENGTH_EPSILON = 1e-3f;
if ( fabs(desiredLengthIVP-currentLengthIVP) < ConvertDistanceToIVP(SPRING_LENGTH_EPSILON) )
return;
m_pSpring->set_len( desiredLengthIVP );
}
}
void CPhysicsSpring::WriteToTemplate( vphysics_save_cphysicsspring_t &params )
{
if ( !m_pSpring )
{
memset(&params, 0, sizeof(params));
return;
}
params.constant = m_pSpring->get_constant();
params.naturalLength = ConvertDistanceToHL( m_pSpring->get_spring_length_zero_force() );
params.damping = m_pSpring->get_damp_factor();
params.relativeDamping = m_pSpring->get_rel_pos_damp();
const IVP_Anchor *anchor0 = m_pSpring->get_actuator_anchor(0);
ConvertPositionToHL( anchor0->object_pos, params.startPosition );
const IVP_Anchor *anchor1 = m_pSpring->get_actuator_anchor(1);
ConvertPositionToHL( anchor1->object_pos, params.endPosition );
params.useLocalPositions = true;
params.onlyStretch = m_pSpring->get_only_stretch() ? true : false;
params.pObjStart = m_pObjStart;
params.pObjEnd = m_pObjEnd;
}
IPhysicsSpring *CreateSpring( IVP_Environment *pEnvironment, CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, springparams_t *pParams )
{
// fill in template
IVP_Template_Spring spring_template;
spring_template.spring_values_are_relative=IVP_FALSE;
spring_template.spring_constant = pParams->constant;
spring_template.spring_len = ConvertDistanceToIVP( pParams->naturalLength );
spring_template.spring_damp = pParams->damping;
spring_template.rel_pos_damp = pParams->relativeDamping;
spring_template.spring_force_only_on_stretch = pParams->onlyStretch ? IVP_TRUE : IVP_FALSE;
// Create anchors for the objects
IVP_Template_Anchor anchorTemplateObjectStart, anchorTemplateObjectEnd;
// create spring
IVP_U_Float_Point ivpPosStart;
IVP_U_Float_Point ivpPosEnd;
if ( !pParams->useLocalPositions )
{
Vector local;
pObjectStart->WorldToLocal( &local, pParams->startPosition );
ConvertPositionToIVP( local, ivpPosStart );
pObjectEnd->WorldToLocal( &local, pParams->endPosition );
ConvertPositionToIVP( local, ivpPosEnd );
}
else
{
ConvertPositionToIVP( pParams->startPosition, ivpPosStart );
ConvertPositionToIVP( pParams->endPosition, ivpPosEnd );
}
anchorTemplateObjectStart.set_anchor_position_os( pObjectStart->GetObject(), &ivpPosStart );
anchorTemplateObjectEnd.set_anchor_position_os( pObjectEnd->GetObject(), &ivpPosEnd );
spring_template.anchors[0] = &anchorTemplateObjectStart;
spring_template.anchors[1] = &anchorTemplateObjectEnd;
IVP_Actuator_Spring *pSpring = pEnvironment->create_spring( &spring_template );
return new CPhysicsSpring( pObjectStart, pObjectEnd, pSpring );
}
bool SavePhysicsSpring( const physsaveparams_t &params, CPhysicsSpring *pSpring )
{
vphysics_save_cphysicsspring_t springTemplate;
memset( &springTemplate, 0, sizeof(springTemplate) );
pSpring->WriteToTemplate( springTemplate );
params.pSave->WriteAll( &springTemplate );
return true;
}
bool RestorePhysicsSpring( const physrestoreparams_t &params, CPhysicsSpring **ppSpring )
{
vphysics_save_cphysicsspring_t springTemplate;
memset( &springTemplate, 0, sizeof(springTemplate) );
params.pRestore->ReadAll( &springTemplate );
CPhysicsEnvironment *pEnvironment = (CPhysicsEnvironment *)params.pEnvironment;
if ( springTemplate.pObjStart && springTemplate.pObjEnd )
{
*ppSpring = (CPhysicsSpring *)pEnvironment->CreateSpring( springTemplate.pObjStart, springTemplate.pObjEnd, &springTemplate );
}
else
{
DevMsg( "Failed to restore spring enpoints\n");
*ppSpring = NULL;
}
return true;
}

View File

@ -0,0 +1,22 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_SPRING_H
#define PHYSICS_SPRING_H
#pragma once
class IPhysicsSpring;
class IVP_Environment;
class IVP_Real_Object;
struct springparams_t;
IPhysicsSpring *CreateSpring( IVP_Environment *pEnvironment, CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, springparams_t *pParams );
#endif // PHYSICS_SPRING_H

View File

@ -0,0 +1,247 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_TRACE_H
#define PHYSICS_TRACE_H
#ifdef _WIN32
#pragma once
#endif
#include "physics_globals.h"
class Vector;
class QAngle;
class CGameTrace;
class CTraceRay;
class IVP_Compact_Surface;
typedef CGameTrace trace_t;
struct Ray_t;
class IVP_Compact_Surface;
class IVP_Compact_Mopp;
class IConvexInfo;
enum
{
COLLIDE_POLY = 0,
COLLIDE_MOPP = 1,
COLLIDE_BALL = 2,
COLLIDE_VIRTUAL = 3,
};
class IPhysCollide
{
public:
virtual ~IPhysCollide() {}
//virtual void AddReference() = 0;
//virtual void ReleaseReference() = 0;
// get a surface manager
virtual IVP_SurfaceManager *CreateSurfaceManager( short & ) const = 0;
virtual void GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const = 0;
virtual unsigned int GetSerializationSize() const = 0;
virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const = 0;
virtual int GetVCollideIndex() const = 0;
virtual Vector GetMassCenter() const = 0;
virtual void SetMassCenter( const Vector &massCenter ) = 0;
virtual Vector GetOrthographicAreas() const = 0;
virtual void SetOrthographicAreas( const Vector &areas ) = 0;
virtual float GetSphereRadius() const = 0;
virtual void OutputDebugInfo() const = 0;
virtual PxShape *GetPxShape() = 0;
};
#define LEAFMAP_HAS_CUBEMAP 0x0001
#define LEAFMAP_HAS_SINGLE_VERTEX_SPAN 0x0002
#define LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS 0x0004
struct leafmap_t
{
void *pLeaf;
unsigned short vertCount;
byte flags;
byte spanCount;
unsigned short startVert[8];
void SetHasCubemap()
{
flags = LEAFMAP_HAS_CUBEMAP;
}
void SetSingleVertexSpan( int startVertIndex, int vertCountIn )
{
flags = 0;
flags |= LEAFMAP_HAS_SINGLE_VERTEX_SPAN;
startVert[0] = startVertIndex;
vertCount = vertCountIn;
}
int MaxSpans()
{
return sizeof(startVert) - sizeof(startVert[0]);
}
const byte *GetSpans() const
{
return reinterpret_cast<const byte *>(&startVert[1]);
}
byte *GetSpans()
{
return reinterpret_cast<byte *>(&startVert[1]);
}
void SetRLESpans( int startVertIndex, int spanCountIn, byte *pSpans )
{
flags = 0;
if ( spanCountIn > MaxSpans() )
return;
if ( spanCountIn == 1 )
{
SetSingleVertexSpan( startVertIndex, pSpans[0] );
return;
}
// write out a run length encoded list of verts to include in this model
flags |= LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS;
startVert[0] = startVertIndex;
vertCount = 0;
spanCount = spanCountIn;
byte *pSpanOut = GetSpans();
for ( int i = 0; i < spanCountIn; i++ )
{
pSpanOut[i] = pSpans[i];
if ( !(i & 1) )
{
vertCount += pSpans[i];
}
}
}
inline bool HasSpans() const { return (flags & (LEAFMAP_HAS_SINGLE_VERTEX_SPAN|LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS)) ? true : false; }
inline bool HasCubemap() const { return (flags & LEAFMAP_HAS_CUBEMAP) ? true : false; }
inline bool HasSingleVertexSpan() const { return (flags & LEAFMAP_HAS_SINGLE_VERTEX_SPAN) ? true : false; }
inline bool HasRLESpans() const { return (flags & LEAFMAP_HAS_MULTIPLE_VERTEX_SPANS) ? true : false; }
};
struct collidemap_t
{
int leafCount;
leafmap_t leafmap[1];
};
extern void InitLeafmap( IVP_Compact_Ledge *pLeaf, leafmap_t *pLeafmapOut );
class CPhysCollide : public IPhysCollide
{
public:
static CPhysCollide *UnserializeFromBuffer( const char *pBuffer, unsigned int size, int index, bool swap = false );
virtual const IVP_Compact_Surface *GetCompactSurface() const { return NULL; }
virtual Vector GetOrthographicAreas() const { return Vector(1,1,1); }
virtual float GetSphereRadius() const { return 0; }
virtual void ComputeOrthographicAreas( float epsilon ) {}
virtual void SetOrthographicAreas( const Vector &areas ) {}
virtual const collidemap_t *GetCollideMap() const { return NULL; }
virtual PxShape *GetPxShape() { return NULL; }
};
class ITraceObject
{
public:
virtual int SupportMap( const Vector &dir, Vector *pOut ) const = 0;
virtual Vector GetVertByIndex( int index ) const = 0;
virtual float Radius( void ) const = 0;
};
// This is the size of the vertex hash
#define CONVEX_HASH_SIZE 512
// The little hashing trick below allows 64K verts per hash entry
#define MAX_CONVEX_VERTS ((CONVEX_HASH_SIZE * (1<<16))-1)
class CPhysicsTrace
{
public:
CPhysicsTrace();
~CPhysicsTrace();
// Calculate the intersection of a swept box (mins/maxs) against an IVP object. All coords are in HL space.
void SweepBoxIVP( const Vector &start, const Vector &end, const Vector &mins, const Vector &maxs, const CPhysCollide *pSurface, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr );
void SweepBoxIVP( const Ray_t &raySrc, unsigned int contentsMask, IConvexInfo *pConvexInfo, const CPhysCollide *pSurface, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr );
// Calculate the intersection of a swept compact surface against another compact surface. All coords are in HL space.
// NOTE: BUGBUG: swept surface must be single convex!!!
void SweepIVP( const Vector &start, const Vector &end, const CPhysCollide *pSweptSurface, const QAngle &sweptAngles, const CPhysCollide *pSurface, const Vector &surfaceOrigin, const QAngle &surfaceAngles, trace_t *ptr );
// get an AABB for an oriented collide
void GetAABB( Vector *pMins, Vector *pMaxs, const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles );
// get the support map/extent for a collide along the axis given by "direction"
Vector GetExtent( const CPhysCollide *pCollide, const Vector &collideOrigin, const QAngle &collideAngles, const Vector &direction );
bool IsBoxIntersectingCone( const Vector &boxAbsMins, const Vector &boxAbsMaxs, const truncatedcone_t &cone );
};
class CVisitHash
{
public:
CVisitHash();
inline unsigned short VertIndexToID( int vertIndex );
inline void VisitVert( int vertIndex );
inline bool WasVisited( int vertIndex );
inline void NewVisit( void );
private:
// Store the current increment and the vertex ID (rotating hash) to guarantee no collisions
struct vertmarker_t
{
unsigned short visitID;
unsigned short vertID;
};
vertmarker_t m_vertVisit[CONVEX_HASH_SIZE];
unsigned short m_vertVisitID;
unsigned short m_isInUse;
};
// Calculate the intersection of a swept box (mins/maxs) against an IVP object. All coords are in HL space.
inline unsigned short CVisitHash::VertIndexToID( int vertIndex )
{
// A little hashing trick here:
// rotate the hash key each time you wrap around at 64K
// That way, the index will not collide until you've hit 64K # hash entries times
int high = vertIndex >> 16;
return (unsigned short) ((vertIndex + high) & 0xFFFF);
}
inline void CVisitHash::VisitVert( int vertIndex )
{
int index = vertIndex & (CONVEX_HASH_SIZE-1);
m_vertVisit[index].visitID = m_vertVisitID;
m_vertVisit[index].vertID = VertIndexToID(vertIndex);
}
inline bool CVisitHash::WasVisited( int vertIndex )
{
unsigned short hashIndex = vertIndex & (CONVEX_HASH_SIZE-1);
unsigned short id = VertIndexToID(vertIndex);
if ( m_vertVisit[hashIndex].visitID == m_vertVisitID && m_vertVisit[hashIndex].vertID == id )
return true;
return false;
}
inline void CVisitHash::NewVisit( void )
{
m_vertVisitID++;
if ( m_vertVisitID == 0 )
{
memset( m_vertVisit, 0, sizeof(m_vertVisit) );
}
}
extern IVP_SurfaceManager *CreateSurfaceManager( const CPhysCollide *pCollisionModel, short &collideType );
extern void OutputCollideDebugInfo( const CPhysCollide *pCollisionModel );
#endif // PHYSICS_TRACE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_VEHICLE_H
#define PHYSICS_VEHICLE_H
#ifdef _WIN32
#pragma once
#endif
struct vehicleparams_t;
class IPhysicsVehicleController;
class CPhysicsObject;
class CPhysicsEnvironment;
class IVP_Real_Object;
bool ShouldOverrideWheelContactFriction( float *pFrictionOut, IVP_Real_Object *pivp0, IVP_Real_Object *pivp1, IVP_U_Float_Point *pNormal );
IPhysicsVehicleController *CreateVehicleController( CPhysicsEnvironment *pEnv, CPhysicsObject *pBodyObject, const vehicleparams_t &params, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace );
#endif // PHYSICS_VEHICLE_H

View File

@ -0,0 +1,641 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Virtual mesh implementation. Cached terrain collision model
//
//=============================================================================
#include "cbase.h"
#include "convert.h"
#include "ivp_surface_manager.hxx"
#include "ivp_surman_polygon.hxx"
#include "ivp_template_surbuild.hxx"
#include "ivp_compact_surface.hxx"
#include <ivp_compact_ledge.hxx>
#include <ivp_ray_solver.hxx>
#include <ivp_compact_ledge_solver.hxx>
#include "ivp_surbuild_pointsoup.hxx"
#include "ivp_surbuild_ledge_soup.hxx"
#include "physics_trace.h"
#include "collisionutils.h"
#include "datamanager.h"
#include "utlbuffer.h"
#include "ledgewriter.h"
#include "tier1/mempool.h"
#include "tier0/memdbgon.h"
class CPhysCollideVirtualMesh;
CTSPool< CUtlVector<CPhysCollideVirtualMesh *> > g_MeshFrameLocksPool;
CTHREADLOCALPTR(CUtlVector<CPhysCollideVirtualMesh *>) g_pMeshFrameLocks;
// This is the surfacemanager class for IVP that implements the required functions by layering CPhysCollideVirtualMesh
class IVP_SurfaceManager_VirtualMesh : public IVP_SurfaceManager
{
public:
void add_reference_to_ledge(const IVP_Compact_Ledge *ledge);
void remove_reference_to_ledge(const IVP_Compact_Ledge *ledge);
void insert_all_ledges_hitting_ray(IVP_Ray_Solver *ray_solver, IVP_Real_Object *object);
void get_radius_and_radius_dev_to_given_center(const IVP_U_Float_Point *center, IVP_FLOAT *radius, IVP_FLOAT *radius_deviation) const;
virtual IVP_SURMAN_TYPE get_type() { return IVP_SURMAN_POLYGON; }
// assume mesh is never a single triangle
virtual const IVP_Compact_Ledge *get_single_convex() const;
void get_mass_center(IVP_U_Float_Point *mass_center_out) const;
void get_rotation_inertia( IVP_U_Float_Point *rotation_inertia_out ) const;
void get_all_ledges_within_radius(const IVP_U_Point *observer_os, IVP_DOUBLE radius,
const IVP_Compact_Ledge *root_ledge, IVP_Real_Object *other_object, const IVP_Compact_Ledge *other_reference_ledge,
IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges);
void get_all_terminal_ledges(IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges);
IVP_SurfaceManager_VirtualMesh( CPhysCollideVirtualMesh *pMesh );
virtual ~IVP_SurfaceManager_VirtualMesh();
private:
CPhysCollideVirtualMesh *m_pMesh;
};
// These are the managed objects for the LRU of terrain collisions
// These get created/destroyed dynamically by a resourcemanager
// These contain the uncompressed collision models for each displacement patch
// The idea is to have only the necessary instances of these in memory at any given time - never all of them
class CMeshInstance
{
public:
// resourcemanager
static unsigned int EstimatedSize( const virtualmeshlist_t &list );
static CMeshInstance *CreateResource( const virtualmeshlist_t &list );
static unsigned int ComputeRootLedgeSize( const byte *pHull );
void DestroyResource() { delete this; }
unsigned int Size() { return m_memSize; }
CMeshInstance *GetData() { return this; }
const triangleledge_t *GetLedges() { return (triangleledge_t *)m_pMemory; }
inline int HullCount() { return m_hullCount; }
const IVP_Compact_Ledge *GetOuterHull() { return (m_hullCount==1) ? (const IVP_Compact_Ledge *)(m_pMemory + m_hullOffset) : NULL; }
int GetRootLedges( IVP_Compact_Ledge **pLedges, int outCount )
{
int hullOffset = m_hullOffset;
int count = min(outCount, (int)m_hullCount);
for ( int i = 0; i < count; i++ )
{
pLedges[i] = (IVP_Compact_Ledge *)(m_pMemory + hullOffset);
hullOffset += sizeof(IVP_Compact_Ledge) + (sizeof(IVP_Compact_Triangle) * pLedges[i]->get_n_triangles());
}
return count;
}
// locals
CMeshInstance() { m_pMemory = 0; }
~CMeshInstance();
private:
void Init( const virtualmeshlist_t &list );
int m_memSize;
char *m_pMemory;
unsigned short m_hullOffset;
byte m_hullCount;
byte m_pad;
};
CMeshInstance::~CMeshInstance()
{
if ( m_pMemory )
{
ivp_free_aligned( m_pMemory );
m_pMemory = NULL;
}
}
unsigned int CMeshInstance::EstimatedSize( const virtualmeshlist_t &list )
{
int ledgeSize = sizeof(triangleledge_t) * list.triangleCount;
int pointSize = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
int hullSize = ComputeRootLedgeSize(list.pHull);
return ledgeSize + pointSize + hullSize;
}
// computes the unpacked size of the array of root ledges
unsigned int CMeshInstance::ComputeRootLedgeSize( const byte *pData )
{
if ( !pData )
return 0;
virtualmeshhull_t *pHeader = (virtualmeshhull_t *)pData;
packedhull_t *pHull = (packedhull_t *)(pHeader+1);
unsigned int size = pHeader->hullCount * sizeof(IVP_Compact_Ledge);
for ( int i = 0; i < pHeader->hullCount; i++ )
{
size += sizeof(IVP_Compact_Triangle) * pHull[i].triangleCount;
}
return size;
}
CMeshInstance *CMeshInstance::CreateResource( const virtualmeshlist_t &list )
{
CMeshInstance *pMesh = new CMeshInstance;
pMesh->Init( list );
return pMesh;
}
// flat memory footprint has triangleledges (ledge + 2 triangles for terrain), then has verts, then optional convex hull
void CMeshInstance::Init( const virtualmeshlist_t &list )
{
int ledgeSize = sizeof(triangleledge_t) * list.triangleCount;
int pointSize = sizeof(IVP_Compact_Poly_Point) * list.vertexCount;
int memSize = ledgeSize + pointSize + ComputeRootLedgeSize(list.pHull);
m_memSize = memSize;
m_hullCount = 0;
m_pMemory = (char *)ivp_malloc_aligned( memSize, 16 );
Assert( (intp(m_pMemory) & 15) == 0 ); // make sure it is aligned
IVP_Compact_Poly_Point *pPoints = (IVP_Compact_Poly_Point *)&m_pMemory[ledgeSize];
triangleledge_t *pLedges = (triangleledge_t *) m_pMemory;
memset( m_pMemory, 0, memSize );
int i;
for ( i = 0; i < list.vertexCount; i++ )
{
ConvertPositionToIVP( list.pVerts[i], pPoints[i] );
}
for ( i = 0; i < list.triangleCount; i++ )
{
Vector v0 = list.pVerts[list.indices[i*3+0]];
Vector v1 = list.pVerts[list.indices[i*3+1]];
Vector v2 = list.pVerts[list.indices[i*3+2]];
Assert( v0 != v1 && v1 != v2 && v0 != v2 );
CVPhysicsVirtualMeshWriter::InitTwoSidedTriangleLege( &pLedges[i], pPoints, list.indices[i*3+0], list.indices[i*3+1], list.indices[i*3+2], 0 );
}
Assert( list.triangleCount > 0 && list.triangleCount <= MAX_VIRTUAL_TRIANGLES );
// if there's a hull, build it out too
if ( list.pHull )
{
virtualmeshhull_t *pHeader = (virtualmeshhull_t *)list.pHull;
m_hullCount = pHeader->hullCount;
Assert( (ledgeSize + pointSize) < 65536 );
m_hullOffset = ledgeSize + pointSize;
byte *pMem = (byte *)m_pMemory + m_hullOffset;
#if _DEBUG
int hullSize = CVPhysicsVirtualMeshWriter::UnpackLedgeListFromHull( pMem, pHeader, pPoints );
Assert((m_hullOffset+hullSize)==memSize);
#else
CVPhysicsVirtualMeshWriter::UnpackLedgeListFromHull( pMem, pHeader, pPoints );
#endif
}
}
const int g_MeshSize = (2048 * 1024 * 4); // nillerusr: 2 MiB should be enough, old value causes problems in ep2
static CDataManager<CMeshInstance, virtualmeshlist_t, CMeshInstance *, CThreadFastMutex> g_MeshManager( g_MeshSize );
static int numIndices = 0, numTriangles = 0, numBaseTriangles = 0, numSplits = 0;
//-----------------------------------------------------------------------------
// Purpose: This allows for just-in-time procedural triangle soup data to be
// instanced & cached as IVP collision data (compact ledges)
//-----------------------------------------------------------------------------
// NOTE: This is the permanent in-memory representation. It holds the compressed data
// and the parameters necessary to request the proxy geometry as needed
class CPhysCollideVirtualMesh : public CPhysCollide
{
public:
// UNDONE: Unlike other CPhysCollide objects, operations the virtual mesh are
// non-const because they may instantiate the cache. This causes problems with the interface.
// Maybe the cache stuff should be mutable, but it amounts to the same kind of
// hackery to cast away const.
// get a surface manager
virtual IVP_SurfaceManager *CreateSurfaceManager( short &collideType ) const
{
collideType = COLLIDE_VIRTUAL;
// UNDONE: Figure out how to avoid this const_cast
return new IVP_SurfaceManager_VirtualMesh(const_cast<CPhysCollideVirtualMesh *>(this));
}
virtual void GetAllLedges( IVP_U_BigVector<IVP_Compact_Ledge> &ledges ) const
{
const triangleledge_t *pLedges = const_cast<CPhysCollideVirtualMesh *>(this)->AddRef()->GetLedges();
for ( int i = 0; i < m_ledgeCount; i++ )
{
ledges.add( const_cast<IVP_Compact_Ledge *>(&pLedges[i].ledge) );
}
const_cast<CPhysCollideVirtualMesh *>(this)->Release();
}
virtual unsigned int GetSerializationSize() const
{
if ( !m_pHull )
return 0;
return m_pHull->TotalSize();
}
virtual unsigned int SerializeToBuffer( char *pDest, bool bSwap = false ) const
{
unsigned int size = GetSerializationSize();
if ( size )
{
memcpy( pDest, m_pHull, size );
}
return size;
}
virtual int GetVCollideIndex() const { return 0; }
virtual void SetMassCenter( const Vector &massCenter ) {Assert(0); }
virtual Vector GetOrthographicAreas() const { return Vector(1,1,1);}
Vector GetMassCenter() const;
virtual float GetSphereRadius() const;
float GetSphereRadiusIVP() const;
void Init( const char *pBuffer, unsigned int size )
{
}
void GetAllLedgesWithinRadius( const IVP_U_Point *observer_os, IVP_DOUBLE radius, IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges, const IVP_Compact_Ledge *pRootLedge = NULL )
{
virtualmeshtrianglelist_t list;
list.triangleCount = 0;
Vector centerHL;
ConvertPositionToHL( *observer_os, centerHL );
float radiusHL = ConvertDistanceToHL(radius);
m_params.pMeshEventHandler->GetTrianglesInSphere( m_params.userData, centerHL, radiusHL, &list );
if ( list.triangleCount )
{
CMeshInstance *pMesh = AddRef();
const triangleledge_t *pLedges = pMesh->GetLedges();
FrameRelease();
// If we have two root ledges, then each one contains half the triangles
// only return triangles indexed under the root ledge being queried
int minTriangle = 0;
int maxTriangle = m_ledgeCount;
if ( pMesh->HullCount() > 1 )
{
Assert(pMesh->HullCount()==2);
IVP_Compact_Ledge *pRootNodes[2];
pMesh->GetRootLedges( pRootNodes, 2 );
int midTriangle = m_ledgeCount/2;
if ( pRootLedge == pRootNodes[0] )
{
maxTriangle = midTriangle;
}
else
{
minTriangle = midTriangle;
}
}
IVP_DOUBLE radiusSq = radius * radius;
for ( int i = 0; i < list.triangleCount; i++ )
{
Assert( list.triangleIndices[i] < m_ledgeCount );
if ( list.triangleIndices[i] < minTriangle || list.triangleIndices[i] >= maxTriangle )
continue;
const IVP_Compact_Ledge *ledge = &pLedges[list.triangleIndices[i]].ledge;
Assert(ledge->get_n_triangles() == 2);
const IVP_Compact_Triangle *triangle = ledge->get_first_triangle();
IVP_DOUBLE qdist = IVP_CLS.calc_qlen_PF_F_space(ledge, triangle, observer_os);
if ( qdist > radiusSq )
{
continue;
}
resulting_ledges->add( const_cast<IVP_Compact_Ledge *>(ledge) );
}
}
}
virtual void OutputDebugInfo() const
{
Msg("Virtual mesh!\n");
}
CPhysCollideVirtualMesh(const virtualmeshparams_t &params) : m_params(params), m_hMemory( INVALID_MEMHANDLE ), m_ledgeCount( 0 )
{
m_pHull = NULL;
if ( params.buildOuterHull )
{
BuildBoundingLedge();
}
}
virtual ~CPhysCollideVirtualMesh();
// adds a lock on the collsion memory :: MUST CALL Release() or FrameRelease corresponding to this call!!!
CMeshInstance *AddRef();
void BuildBoundingLedge();
static virtualmeshhull_t *CreateMeshBoundingHull( const virtualmeshlist_t &list );
static void DestroyMeshBoundingHull(virtualmeshhull_t *pHull) { CVPhysicsVirtualMeshWriter::DestroyPackedHull(pHull); }
static IVP_Compact_Surface *CreateBoundingSurfaceFromRange( const virtualmeshlist_t &list, int firstIndex, int indexCount );
int GetRootLedges( IVP_Compact_Ledge **pLedges, int outCount )
{
int count = AddRef()->GetRootLedges(pLedges, outCount);
FrameRelease();
return count;
}
IVP_Compact_Ledge *GetBoundingLedge()
{
IVP_Compact_Ledge *pLedge = const_cast<IVP_Compact_Ledge *>(AddRef()->GetOuterHull());
FrameRelease();
return pLedge;
}
// releases a lock on the collision memory
void Release();
// Analagous to Release, but happens at the end of the frame
void FrameRelease()
{
CUtlVector<CPhysCollideVirtualMesh *> *pLocks = g_pMeshFrameLocks;
if ( !pLocks )
{
g_pMeshFrameLocks = pLocks = g_MeshFrameLocksPool.GetObject();
Assert( pLocks );
}
pLocks->AddToTail(this);
}
inline void GetBounds( Vector &mins, Vector &maxs ) const
{
m_params.pMeshEventHandler->GetWorldspaceBounds( m_params.userData, &mins, &maxs );
}
private:
CMeshInstance *BuildLedges();
virtualmeshparams_t m_params;
virtualmeshhull_t *m_pHull;
memhandle_t m_hMemory;
short m_ledgeCount;
};
static void FlushFrameLocks()
{
CUtlVector<CPhysCollideVirtualMesh *> *pLocks = g_pMeshFrameLocks;
if ( pLocks )
{
for ( int i = 0; i < pLocks->Count(); i++ )
{
Assert( (*pLocks)[i] );
(*pLocks)[i]->Release();
}
pLocks->RemoveAll();
g_MeshFrameLocksPool.PutObject( g_pMeshFrameLocks );
g_pMeshFrameLocks = NULL;
}
}
void VirtualMeshPSI()
{
FlushFrameLocks();
}
Vector CPhysCollideVirtualMesh::GetMassCenter() const
{
Vector mins, maxs;
GetBounds( mins, maxs );
return 0.5 * (mins + maxs);
}
float CPhysCollideVirtualMesh::GetSphereRadius() const
{
Vector mins, maxs;
GetBounds( mins, maxs );
Vector point = 0.5 * (mins+maxs);
return (maxs - point).Length();
}
float CPhysCollideVirtualMesh::GetSphereRadiusIVP() const
{
return ConvertDistanceToIVP( GetSphereRadius() );
}
static CThreadFastMutex s_BuildVirtualMeshMutex;
CMeshInstance *CPhysCollideVirtualMesh::AddRef()
{
CMeshInstance *pMesh = g_MeshManager.LockResource( m_hMemory );
if ( !pMesh )
{
s_BuildVirtualMeshMutex.Lock();
pMesh = g_MeshManager.LockResource( m_hMemory );
if ( !pMesh )
{
pMesh = BuildLedges();
}
s_BuildVirtualMeshMutex.Unlock();
}
Assert( pMesh );
return pMesh;
}
void CPhysCollideVirtualMesh::Release()
{
g_MeshManager.UnlockResource( m_hMemory );
}
CPhysCollideVirtualMesh::~CPhysCollideVirtualMesh()
{
CVPhysicsVirtualMeshWriter::DestroyPackedHull(m_pHull);
g_MeshManager.DestroyResource( m_hMemory );
}
CMeshInstance *CPhysCollideVirtualMesh::BuildLedges()
{
virtualmeshlist_t list;
m_params.pMeshEventHandler->GetVirtualMesh( m_params.userData, &list );
if ( !list.pHull )
{
list.pHull = (byte *)m_pHull;
}
if ( list.triangleCount )
{
m_hMemory = g_MeshManager.CreateResource( list );
m_ledgeCount = list.triangleCount;
CMeshInstance *pMesh = g_MeshManager.LockResource( m_hMemory );
Assert( g_MeshManager.AvailableSize() != 0 );
return pMesh;
}
return NULL;
}
// build the outer ledge, split into two if necessary
void CPhysCollideVirtualMesh::BuildBoundingLedge()
{
virtualmeshlist_t list;
m_params.pMeshEventHandler->GetVirtualMesh( m_params.userData, &list );
m_pHull = CreateMeshBoundingHull(list);
}
virtualmeshhull_t *CPhysCollideVirtualMesh::CreateMeshBoundingHull( const virtualmeshlist_t &list )
{
virtualmeshhull_t *pHull = NULL;
if ( list.triangleCount )
{
IVP_Compact_Surface *pSurface = CreateBoundingSurfaceFromRange( list, 0, list.indexCount );
if ( pSurface )
{
const IVP_Compact_Ledge *pLedge = pSurface->get_compact_ledge_tree_root()->get_compact_hull();
if ( CVPhysicsVirtualMeshWriter::LedgeCanBePacked(pLedge, list) )
{
pHull = CVPhysicsVirtualMeshWriter::CreatePackedHullFromLedges( list, &pLedge, 1 );
}
else
{
// too big to pack to 8-bits, split in two
IVP_Compact_Surface *pSurface0 = CreateBoundingSurfaceFromRange( list, 0, list.indexCount/2 );
IVP_Compact_Surface *pSurface1 = CreateBoundingSurfaceFromRange( list, list.indexCount/2, list.indexCount/2 );
const IVP_Compact_Ledge *pLedges[2] = {pSurface0->get_compact_ledge_tree_root()->get_compact_hull(), pSurface1->get_compact_ledge_tree_root()->get_compact_hull()};
pHull = CVPhysicsVirtualMeshWriter::CreatePackedHullFromLedges( list, pLedges, 2 );
ivp_free_aligned(pSurface0);
ivp_free_aligned(pSurface1);
}
ivp_free_aligned(pSurface);
}
}
return pHull;
}
IVP_Compact_Surface *CPhysCollideVirtualMesh::CreateBoundingSurfaceFromRange( const virtualmeshlist_t &list, int firstIndex, int indexCount )
{
Assert( list.triangleCount );
IVP_U_Point triVerts[3];
IVP_U_Vector<IVP_U_Point> triList;
IVP_SurfaceBuilder_Ledge_Soup builder;
triList.add( &triVerts[0] );
triList.add( &triVerts[1] );
triList.add( &triVerts[2] );
int lastIndex = firstIndex + indexCount;
int firstTriangle = firstIndex/3;
int lastTriangle = lastIndex/3;
for ( int i = firstTriangle; i < lastTriangle; i++ )
{
ConvertPositionToIVP( list.pVerts[list.indices[i*3+0]], triVerts[0] );
ConvertPositionToIVP( list.pVerts[list.indices[i*3+1]], triVerts[1] );
ConvertPositionToIVP( list.pVerts[list.indices[i*3+2]], triVerts[2] );
IVP_Compact_Ledge *pLedge = IVP_SurfaceBuilder_Pointsoup::convert_pointsoup_to_compact_ledge( &triList );
builder.insert_ledge( pLedge );
}
// build a convex hull of those verts
IVP_Template_Surbuild_LedgeSoup params;
params.build_root_convex_hull = IVP_TRUE;
IVP_Compact_Surface *pSurface = builder.compile( &params );
#if _DEBUG
const IVP_Compact_Ledgetree_Node *node = pSurface->get_compact_ledge_tree_root();
IVP_Compact_Ledge *pLedge = const_cast<IVP_Compact_Ledge *>(node->get_compact_hull()); // we're going to write into client data on each vert before we throw this away
Assert(pLedge && !pLedge->is_terminal());
#endif
return pSurface;
}
CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t &params )
{
return new CPhysCollideVirtualMesh(params);
}
void DestroyVirtualMesh( CPhysCollide *pMesh )
{
delete pMesh;
}
//-----------------------------------------------------------------------------
// IVP_SurfaceManager_VirtualMesh
// This hooks the underlying collision model to IVP's surfacemanager interface
//-----------------------------------------------------------------------------
IVP_SurfaceManager_VirtualMesh::IVP_SurfaceManager_VirtualMesh( CPhysCollideVirtualMesh *pMesh ) : m_pMesh(pMesh)
{
}
IVP_SurfaceManager_VirtualMesh::~IVP_SurfaceManager_VirtualMesh()
{
FlushFrameLocks();
}
void IVP_SurfaceManager_VirtualMesh::add_reference_to_ledge(const IVP_Compact_Ledge *ledge)
{
m_pMesh->AddRef();
}
void IVP_SurfaceManager_VirtualMesh::remove_reference_to_ledge(const IVP_Compact_Ledge *ledge)
{
m_pMesh->Release();
}
// Implement the IVP raycast. This is done by testing each triangle (front & back) - so it's slow
void IVP_SurfaceManager_VirtualMesh::insert_all_ledges_hitting_ray(IVP_Ray_Solver *ray_solver, IVP_Real_Object *object)
{
IVP_Vector_of_Ledges_256 ledges;
IVP_Ray_Solver_Os ray_solver_os( ray_solver, object);
IVP_U_Point center(&ray_solver_os.ray_center_point);
m_pMesh->GetAllLedgesWithinRadius( &center, ray_solver_os.ray_length * 0.5f, &ledges );
for (int i=ledges.len()-1;i>=0;i--)
{
const IVP_Compact_Ledge *l = ledges.element_at(i);
ray_solver_os.check_ray_against_compact_ledge_os(l);
}
}
// Used to predict collision detection needs
void IVP_SurfaceManager_VirtualMesh::get_radius_and_radius_dev_to_given_center(const IVP_U_Float_Point *center, IVP_FLOAT *radius, IVP_FLOAT *radius_deviation) const
{
// UNDONE: Check radius_deviation to see if there is a useful optimization to be made here
*radius = m_pMesh->GetSphereRadiusIVP();
*radius_deviation = *radius;
}
// get a single convex if appropriate
const IVP_Compact_Ledge *IVP_SurfaceManager_VirtualMesh::get_single_convex() const
{
return m_pMesh->GetBoundingLedge();
}
// get a mass center for objects using this collision rep
void IVP_SurfaceManager_VirtualMesh::get_mass_center(IVP_U_Float_Point *mass_center_out) const
{
Vector center = m_pMesh->GetMassCenter();
ConvertPositionToIVP( center, *mass_center_out );
}
//-----------------------------------------------------------------------------
// Purpose: Compute a diagonalized inertia tensor.
//-----------------------------------------------------------------------------
void IVP_SurfaceManager_VirtualMesh::get_rotation_inertia( IVP_U_Float_Point *rotation_inertia_out ) const
{
// HACKHACK: No need for this because we only support static objects for now
rotation_inertia_out->set(1,1,1);
}
//-----------------------------------------------------------------------------
// Purpose: Query ledges (triangles in this case) in sphere
//-----------------------------------------------------------------------------
void IVP_SurfaceManager_VirtualMesh::get_all_ledges_within_radius(const IVP_U_Point *observer_os, IVP_DOUBLE radius,
const IVP_Compact_Ledge *root_ledge, IVP_Real_Object *other_object, const IVP_Compact_Ledge *other_reference_ledge,
IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges)
{
if ( !root_ledge )
{
IVP_Compact_Ledge *pLedges[2];
int count = m_pMesh->GetRootLedges( pLedges, ARRAYSIZE(pLedges) );
if ( count )
{
for ( int i = 0; i < count; i++ )
{
resulting_ledges->add( pLedges[i] ); // return the recursive/virtual outer hull
}
return;
}
}
m_pMesh->GetAllLedgesWithinRadius( observer_os, radius, resulting_ledges, root_ledge );
}
//-----------------------------------------------------------------------------
// Purpose: Query all of the ledges (triangles)
//-----------------------------------------------------------------------------
void IVP_SurfaceManager_VirtualMesh::get_all_terminal_ledges(IVP_U_BigVector<IVP_Compact_Ledge> *resulting_ledges)
{
m_pMesh->GetAllLedges( *resulting_ledges );
}

View File

@ -0,0 +1,19 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef PHYSICS_VIRTUALMESH_H
#define PHYSICS_VIRTUALMESH_H
#ifdef _WIN32
#pragma once
#endif
CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t &params );
void DestroyVirtualMesh( CPhysCollide *pSurf );
void DumpVirtualMeshStats();
void VirtualMeshPSI();
#endif // PHYSICS_VIRTUALMESH_H

View File

@ -0,0 +1,9 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: precompiled header for vphysics
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"

2476
vphysics-physx/trace.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// stdafx.cpp : source file that includes just the standard includes
// traceperf.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

View File

@ -0,0 +1,15 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "phyfile.h"
#include "vphysics_interface.h"
#include "tier0/icommandline.h"
#include "tier0/vprof.h"
// TODO: reference additional headers your program requires here

View File

@ -0,0 +1,406 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// traceperf.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "gametrace.h"
#include "fmtstr.h"
#include "appframework/appframework.h"
#include "filesystem.h"
#include "filesystem_init.h"
#include "tier1/tier1.h"
#include "tier2/tier2.h"
#include "tier3/tier3.h"
IPhysicsCollision *physcollision = NULL;
#define NUM_COLLISION_TESTS 2500
void ReadPHYFile(const char *name, vcollide_t &collide )
{
FileHandle_t fp = g_pFullFileSystem->Open(name, "rb");
if (!fp)
Error ("Couldn't open %s", name);
phyheader_t header;
g_pFullFileSystem->Read( &header, sizeof(header), fp );
if ( header.size != sizeof(header) || header.solidCount <= 0 )
return;
int fileSize = g_pFullFileSystem->Size(fp);
char *buf = (char *)_alloca( fileSize );
g_pFullFileSystem->Read( buf, fileSize, fp );
g_pFullFileSystem->Close( fp );
physcollision->VCollideLoad( &collide, header.solidCount, (const char *)buf, fileSize );
}
struct testlist_t
{
Vector start;
Vector end;
Vector normal;
bool hit;
};
struct benchresults_t
{
int collisionTests;
int collisionHits;
float totalTime;
float rayTime;
float boxTime;
};
testlist_t g_Traces[NUM_COLLISION_TESTS];
void Benchmark_PHY( const CPhysCollide *pCollide, benchresults_t *pOut )
{
int i;
Vector start = vec3_origin;
static Vector *targets = NULL;
static bool first = true;
static float test[2] = {1,1};
if ( first )
{
float radius = 0;
float theta = 0;
float phi = 0;
for ( int i = 0; i < NUM_COLLISION_TESTS; i++ )
{
radius += NUM_COLLISION_TESTS * 123.123f;
radius = fabs(fmod(radius, 128));
theta += NUM_COLLISION_TESTS * 0.76f;
theta = fabs(fmod(theta, DEG2RAD(360)));
phi += NUM_COLLISION_TESTS * 0.16666666f;
phi = fabs(fmod(phi, DEG2RAD(180)));
float st, ct, sp, cp;
SinCos( theta, &st, &ct );
SinCos( phi, &sp, &cp );
st = sin(theta);
ct = cos(theta);
sp = sin(phi);
cp = cos(phi);
g_Traces[i].start.x = radius * ct * sp;
g_Traces[i].start.y = radius * st * sp;
g_Traces[i].start.z = radius * cp;
}
first = false;
}
float duration = 0;
Vector size[2];
size[0].Init(0,0,0);
size[1].Init(16,16,16);
#if VPROF_LEVEL > 0
g_VProfCurrentProfile.Reset();
g_VProfCurrentProfile.ResetPeaks();
g_VProfCurrentProfile.Start();
#endif
#if TEST_BBOX
Vector mins, maxs;
physcollision->CollideGetAABB( &mins, &maxs, pCollide, Vector(-500, 200, -100), vec3_angle );
Vector extents = maxs - mins;
Vector center = 0.5f * (maxs+mins);
Msg("bbox: %.2f,%.2f, %.2f @ %.2f, %.2f, %.2f\n", extents.x, extents.y, extents.z, center.x, center.y, center.z );
#endif
unsigned int hitCount = 0;
double startTime = Plat_FloatTime();
trace_t tr;
for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
{
physcollision->TraceBox( g_Traces[i].start, start, -size[0], size[0], pCollide, vec3_origin, vec3_angle, &tr );
if ( tr.DidHit() )
{
g_Traces[i].end = tr.endpos;
g_Traces[i].normal = tr.plane.normal;
g_Traces[i].hit = true;
hitCount++;
}
else
{
g_Traces[i].hit = false;
}
}
for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
{
physcollision->TraceBox( g_Traces[i].start, start, -size[1], size[1], pCollide, vec3_origin, vec3_angle, &tr );
}
duration = Plat_FloatTime() - startTime;
#if VPROF_LEVEL > 0
g_VProfCurrentProfile.MarkFrame();
g_VProfCurrentProfile.Stop();
g_VProfCurrentProfile.Reset();
g_VProfCurrentProfile.ResetPeaks();
g_VProfCurrentProfile.Start();
#endif
hitCount = 0;
startTime = Plat_FloatTime();
for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
{
physcollision->TraceBox( g_Traces[i].start, start, -size[0], size[0], pCollide, vec3_origin, vec3_angle, &tr );
if ( tr.DidHit() )
{
g_Traces[i].end = tr.endpos;
g_Traces[i].normal = tr.plane.normal;
g_Traces[i].hit = true;
hitCount++;
}
else
{
g_Traces[i].hit = false;
}
#if VPROF_LEVEL > 0
g_VProfCurrentProfile.MarkFrame();
#endif
}
double midTime = Plat_FloatTime();
for ( i = 0; i < NUM_COLLISION_TESTS; i++ )
{
physcollision->TraceBox( g_Traces[i].start, start, -size[1], size[1], pCollide, vec3_origin, vec3_angle, &tr );
#if VPROF_LEVEL > 0
g_VProfCurrentProfile.MarkFrame();
#endif
}
double endTime = Plat_FloatTime();
duration = endTime - startTime;
pOut->collisionTests = NUM_COLLISION_TESTS;
pOut->collisionHits = hitCount;
pOut->totalTime = duration * 1000.0f;
pOut->rayTime = (midTime - startTime) * 1000.0f;
pOut->boxTime = (endTime - midTime)*1000.0f;
#if VPROF_LEVEL > 0
g_VProfCurrentProfile.Stop();
g_VProfCurrentProfile.OutputReport( VPRT_FULL & ~VPRT_HIERARCHY, NULL );
#endif
}
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
//-----------------------------------------------------------------------------
// The application object
//-----------------------------------------------------------------------------
class CBenchmarkApp : public CDefaultAppSystemGroup< CSteamAppSystemGroup >
{
typedef CDefaultAppSystemGroup< CSteamAppSystemGroup > BaseClass;
public:
// Methods of IApplication
virtual bool Create();
virtual bool PreInit( );
virtual int Main();
virtual void PostShutdown();
bool SetupSearchPaths();
private:
bool ParseArguments();
};
DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT( CBenchmarkApp );
//-----------------------------------------------------------------------------
// The application object
//-----------------------------------------------------------------------------
bool CBenchmarkApp::Create()
{
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
// Add in the cvar factory
//AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() );
//AddSystem( cvarModule, VENGINE_CVAR_INTERFACE_VERSION );
AppSystemInfo_t appSystems[] =
{
{ "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
{ "", "" } // Required to terminate the list
};
bool bRet = AddSystems( appSystems );
if ( bRet )
{
physcollision = (IPhysicsCollision*)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION );
if ( !physcollision )
return false;
}
return bRet;
}
bool CBenchmarkApp::SetupSearchPaths()
{
CFSSteamSetupInfo steamInfo;
steamInfo.m_pDirectoryName = NULL;
steamInfo.m_bOnlyUseDirectoryName = false;
steamInfo.m_bToolsMode = true;
steamInfo.m_bSetSteamDLLPath = true;
steamInfo.m_bSteam = g_pFullFileSystem->IsSteam();
if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
return false;
CFSMountContentInfo fsInfo;
fsInfo.m_pFileSystem = g_pFullFileSystem;
fsInfo.m_bToolsMode = true;
fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
if ( FileSystem_MountContent( fsInfo ) != FS_OK )
return false;
// Finally, load the search paths for the "GAME" path.
CFSSearchPathsInit searchPathsInit;
searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath;
searchPathsInit.m_pFileSystem = g_pFullFileSystem;
if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
return false;
g_pFullFileSystem->AddSearchPath( steamInfo.m_GameInfoPath, "SKIN", PATH_ADD_TO_HEAD );
FileSystem_AddSearchPath_Platform( g_pFullFileSystem, steamInfo.m_GameInfoPath );
return true;
}
bool CBenchmarkApp::PreInit( )
{
CreateInterfaceFn factory = GetFactory();
ConnectTier1Libraries( &factory, 1 );
ConnectTier2Libraries( &factory, 1 );
ConnectTier3Libraries( &factory, 1 );
if ( !g_pFullFileSystem || !physcollision )
{
Warning( "benchmark is missing a required interface!\n" );
return false;
}
return SetupSearchPaths();//( NULL, false, true );
}
void CBenchmarkApp::PostShutdown()
{
DisconnectTier3Libraries();
DisconnectTier2Libraries();
DisconnectTier1Libraries();
}
struct baseline_t
{
float total;
float ray;
float box;
};
// current baseline measured on Core2DuoE6600
baseline_t g_Baselines[] =
{
{ 40.56f, 10.64f, 29.92f}, // bench01a.phy
{ 38.13f, 10.76f, 27.37f }, // bicycle01a.phy
{ 25.46f, 8.34f, 17.13f }, // furnituretable001a.phy
{ 12.65f, 6.02f, 6.62f }, // gravestone003a.phy
{ 40.58f, 16.49f, 24.10f }, // combineinnerwall001a.phy
};
const float g_TotalBaseline = 157.38f;
/*
Benchmark models\props_c17\bench01a.phy!
33.90 ms [1.20 X] 2500/2500 hits
8.95 ms rays [1.19 X] 24.95 ms boxes [1.20 X]
Benchmark models\props_junk\bicycle01a.phy!
30.55 ms [1.25 X] 803/2500 hits
8.96 ms rays [1.20 X] 21.59 ms boxes [1.27 X]
Benchmark models\props_c17\furnituretable001a.phy!
20.61 ms [1.24 X] 755/2500 hits
6.88 ms rays [1.21 X] 13.73 ms boxes [1.25 X]
Benchmark models\props_c17\gravestone003a.phy!
9.13 ms [1.39 X] 2500/2500 hits
4.34 ms rays [1.39 X] 4.79 ms boxes [1.38 X]
Benchmark models\props_combine\combineinnerwall001a.phy!
33.04 ms [1.23 X] 985/2500 hits
13.37 ms rays [1.23 X] 19.67 ms boxes [1.23 X]
127.22s total [1.24 X]!
*/
#define IMPROVEMENT_FACTOR(x,baseline) (baseline/(x))
#define IMPROVEMENT_PERCENT(x,baseline) (((baseline-(x)) / baseline) * 100.0f)
#include <windows.h>
//-----------------------------------------------------------------------------
// The application object
//-----------------------------------------------------------------------------
int CBenchmarkApp::Main()
{
const char *pFileNames[] =
{
"models\\props_c17\\bench01a.phy",
"models\\props_junk\\bicycle01a.phy",
"models\\props_c17\\furnituretable001a.phy",
"models\\props_c17\\gravestone003a.phy",
"models\\props_combine\\combineinnerwall001a.phy",
};
vcollide_t testModels[ARRAYSIZE(pFileNames)];
for ( int i = 0; i < ARRAYSIZE(pFileNames); i++ )
{
ReadPHYFile( pFileNames[i], testModels[i] );
}
SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS );
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST );
float totalTime = 0.0f;
int loopCount = ARRAYSIZE(pFileNames);
#if VPROF_LEVEL > 0
// loopCount = 3;
#endif
for ( int i = 0; i < loopCount; i++ )
{
if ( testModels[i].solidCount < 1 )
{
Msg("Failed to load %s, skipping test!\n", pFileNames[i] );
continue;
}
Msg("Benchmark %s!\n\n", pFileNames[i] );
benchresults_t results;
memset( &results, 0, sizeof(results));
int numRepeats = 3;
#if VPROF_LEVEL > 0
numRepeats = 1;
#endif
for ( int j = 0; j < numRepeats; j++ )
{
Benchmark_PHY( testModels[i].solids[0], &results );
}
Msg("%.2f ms [%.2f X] %d/%d hits\n", results.totalTime, IMPROVEMENT_FACTOR(results.totalTime, g_Baselines[i].total), results.collisionHits, results.collisionTests);
Msg("%.2f ms rays \t[%.2f X] \t%.2f ms boxes [%.2f X]\n",
results.rayTime, IMPROVEMENT_FACTOR(results.rayTime, g_Baselines[i].ray),
results.boxTime, IMPROVEMENT_FACTOR(results.boxTime, g_Baselines[i].box));
totalTime += results.totalTime;
}
SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS );
Msg("\n%.2fs total \t[%.2f X]!\n", totalTime, IMPROVEMENT_FACTOR(totalTime, g_TotalBaseline) );
return 0;
}

View File

@ -0,0 +1,43 @@
//-----------------------------------------------------------------------------
// VBSP.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR "..\.."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,..\common,..\vmpi"
$PreprocessorDefinitions "$BASE;MACRO_MATHLIB;PROTECTED_THINGS_DISABLE"
$FloatingPointModel "Precise (/fp:precise)"
}
}
$Project "traceperf"
{
$Folder "Source Files"
{
$File "stdafx.cpp"
$File "traceperf.cpp"
}
$Folder "Header Files"
{
$File "stdafx.h"
$File "$SRCDIR\public\vphysics_interface.h"
}
$Folder "Link Libraries"
{
$Lib appframework
$Lib mathlib
$Lib tier2
$Lib tier3
}
}

View File

@ -0,0 +1,940 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "vcollide_parse_private.h"
#include "tier1/strtools.h"
#include "vphysics/constraints.h"
#include "vphysics/vehicles.h"
#include "filesystem_helpers.h"
#include "bspfile.h"
#include "utlbuffer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static void ReadVector( const char *pString, Vector& out )
{
float x, y, z;
sscanf( pString, "%f %f %f", &x, &y, &z );
out[0] = x;
out[1] = y;
out[2] = z;
}
static void ReadAngles( const char *pString, QAngle& out )
{
float x, y, z;
sscanf( pString, "%f %f %f", &x, &y, &z );
out[0] = x;
out[1] = y;
out[2] = z;
}
static void ReadVector4D( const char *pString, Vector4D& out )
{
float x, y, z, w;
sscanf( pString, "%f %f %f %f", &x, &y, &z, &w );
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
}
class CVPhysicsParse : public IVPhysicsKeyParser
{
public:
~CVPhysicsParse() {}
CVPhysicsParse( const char *pKeyData );
void NextBlock( void );
const char *GetCurrentBlockName( void );
bool Finished( void );
void ParseSolid( solid_t *pSolid, IVPhysicsKeyHandler *unknownKeyHandler );
void ParseFluid( fluid_t *pFluid, IVPhysicsKeyHandler *unknownKeyHandler );
void ParseRagdollConstraint( constraint_ragdollparams_t *pConstraint, IVPhysicsKeyHandler *unknownKeyHandler );
void ParseSurfaceTable( int *table, IVPhysicsKeyHandler *unknownKeyHandler );
void ParseSurfaceTablePacked( CUtlVector<char> &out );
void ParseVehicle( vehicleparams_t *pVehicle, IVPhysicsKeyHandler *unknownKeyHandler );
void ParseCustom( void *pCustom, IVPhysicsKeyHandler *unknownKeyHandler );
void SkipBlock( void ) { ParseCustom(NULL, NULL); }
private:
void ParseVehicleAxle( vehicle_axleparams_t &axle );
void ParseVehicleWheel( vehicle_wheelparams_t &wheel );
void ParseVehicleSuspension( vehicle_suspensionparams_t &suspension );
void ParseVehicleBody( vehicle_bodyparams_t &body );
void ParseVehicleEngine( vehicle_engineparams_t &engine );
void ParseVehicleEngineBoost( vehicle_engineparams_t &engine );
void ParseVehicleSteering( vehicle_steeringparams_t &steering );
const char *m_pText;
char m_blockName[MAX_KEYVALUE];
};
CVPhysicsParse::CVPhysicsParse( const char *pKeyData )
{
m_pText = pKeyData;
NextBlock();
}
void CVPhysicsParse::NextBlock( void )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( !Q_strcmp(value, "{") )
{
V_strcpy_safe( m_blockName, key );
return;
}
}
// Make sure m_blockName is initialized -- should this be done?
m_blockName[ 0 ] = 0;
}
const char *CVPhysicsParse::GetCurrentBlockName( void )
{
if ( m_pText )
return m_blockName;
return NULL;
}
bool CVPhysicsParse::Finished( void )
{
if ( m_pText )
return false;
return true;
}
void CVPhysicsParse::ParseSolid( solid_t *pSolid, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
if ( unknownKeyHandler )
{
unknownKeyHandler->SetDefaults( pSolid );
}
else
{
memset( pSolid, 0, sizeof(*pSolid) );
}
// disable these until the ragdoll is created
pSolid->params.enableCollisions = false;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
if ( !Q_stricmp( key, "index" ) )
{
pSolid->index = atoi(value);
}
else if ( !Q_stricmp( key, "name" ) )
{
Q_strncpy( pSolid->name, value, sizeof(pSolid->name) );
}
else if ( !Q_stricmp( key, "parent" ) )
{
Q_strncpy( pSolid->parent, value, sizeof(pSolid->parent) );
}
else if ( !Q_stricmp( key, "surfaceprop" ) )
{
Q_strncpy( pSolid->surfaceprop, value, sizeof(pSolid->surfaceprop) );
}
else if ( !Q_stricmp( key, "mass" ) )
{
pSolid->params.mass = atof(value);
}
else if ( !Q_stricmp( key, "massCenterOverride" ) )
{
ReadVector( value, pSolid->massCenterOverride );
pSolid->params.massCenterOverride = &pSolid->massCenterOverride;
}
else if ( !Q_stricmp( key, "inertia" ) )
{
pSolid->params.inertia = atof(value);
}
else if ( !Q_stricmp( key, "damping" ) )
{
pSolid->params.damping = atof(value);
}
else if ( !Q_stricmp( key, "rotdamping" ) )
{
pSolid->params.rotdamping = atof(value);
}
else if ( !Q_stricmp( key, "volume" ) )
{
pSolid->params.volume = atof(value);
}
else if ( !Q_stricmp( key, "drag" ) )
{
pSolid->params.dragCoefficient = atof(value);
}
else if ( !Q_stricmp( key, "rollingdrag" ) )
{
//pSolid->params.rollingDrag = atof(value);
}
else
{
if ( unknownKeyHandler )
{
unknownKeyHandler->ParseKeyValue( pSolid, key, value );
}
}
}
}
void CVPhysicsParse::ParseRagdollConstraint( constraint_ragdollparams_t *pConstraint, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
if ( unknownKeyHandler )
{
unknownKeyHandler->SetDefaults( pConstraint );
}
else
{
memset( pConstraint, 0, sizeof(*pConstraint) );
pConstraint->childIndex = -1;
pConstraint->parentIndex = -1;
}
// BUGBUG: xmin/xmax, ymin/ymax, zmin/zmax specify clockwise rotations.
// BUGBUG: HL rotations are counter-clockwise, so reverse these limits at some point!!!
pConstraint->useClockwiseRotations = true;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
if ( !Q_stricmp( key, "parent" ) )
{
pConstraint->parentIndex = atoi( value );
}
else if ( !Q_stricmp( key, "child" ) )
{
pConstraint->childIndex = atoi( value );
}
else if ( !Q_stricmp( key, "xmin" ) )
{
pConstraint->axes[0].minRotation = atof( value );
}
else if ( !Q_stricmp( key, "xmax" ) )
{
pConstraint->axes[0].maxRotation = atof( value );
}
else if ( !Q_stricmp( key, "xfriction" ) )
{
pConstraint->axes[0].angularVelocity = 0;
pConstraint->axes[0].torque = atof( value );
}
else if ( !Q_stricmp( key, "ymin" ) )
{
pConstraint->axes[1].minRotation = atof( value );
}
else if ( !Q_stricmp( key, "ymax" ) )
{
pConstraint->axes[1].maxRotation = atof( value );
}
else if ( !Q_stricmp( key, "yfriction" ) )
{
pConstraint->axes[1].angularVelocity = 0;
pConstraint->axes[1].torque = atof( value );
}
else if ( !Q_stricmp( key, "zmin" ) )
{
pConstraint->axes[2].minRotation = atof( value );
}
else if ( !Q_stricmp( key, "zmax" ) )
{
pConstraint->axes[2].maxRotation = atof( value );
}
else if ( !Q_stricmp( key, "zfriction" ) )
{
pConstraint->axes[2].angularVelocity = 0;
pConstraint->axes[2].torque = atof( value );
}
else
{
if ( unknownKeyHandler )
{
unknownKeyHandler->ParseKeyValue( pConstraint, key, value );
}
}
}
}
void CVPhysicsParse::ParseFluid( fluid_t *pFluid, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
pFluid->index = -1;
if ( unknownKeyHandler )
{
unknownKeyHandler->SetDefaults( pFluid );
}
else
{
memset( pFluid, 0, sizeof(*pFluid) );
// HACKHACK: This is a reasonable default even though it is hardcoded
V_strcpy_safe( pFluid->surfaceprop, "water" );
}
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
if ( !Q_stricmp( key, "index" ) )
{
pFluid->index = atoi( value );
}
else if ( !Q_stricmp( key, "damping" ) )
{
pFluid->params.damping = atof( value );
}
else if ( !Q_stricmp( key, "surfaceplane" ) )
{
ReadVector4D( value, pFluid->params.surfacePlane );
}
else if ( !Q_stricmp( key, "currentvelocity" ) )
{
ReadVector( value, pFluid->params.currentVelocity );
}
else if ( !Q_stricmp( key, "contents" ) )
{
pFluid->params.contents = atoi( value );
}
else if ( !Q_stricmp( key, "surfaceprop" ) )
{
Q_strncpy( pFluid->surfaceprop, value, sizeof(pFluid->surfaceprop) );
}
else
{
if ( unknownKeyHandler )
{
unknownKeyHandler->ParseKeyValue( pFluid, key, value );
}
}
}
}
void CVPhysicsParse::ParseSurfaceTable( int *table, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
int propIndex = physprops->GetSurfaceIndex( key );
int tableIndex = atoi(value);
if ( tableIndex >= 0 && tableIndex < 128 )
{
table[tableIndex] = propIndex;
}
}
}
void CVPhysicsParse::ParseSurfaceTablePacked( CUtlVector<char> &out )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
int lastIndex = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
int len = Q_strlen( key );
int outIndex = out.AddMultipleToTail( len + 1 );
memcpy( &out[outIndex], key, len+1 );
int tableIndex = atoi(value);
Assert( tableIndex == lastIndex + 1);
lastIndex = tableIndex;
}
}
void CVPhysicsParse::ParseVehicleAxle( vehicle_axleparams_t &axle )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
memset( &axle, 0, sizeof(axle) );
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
// parse subchunks
if ( value[0] == '{' )
{
if ( !Q_stricmp( key, "wheel" ) )
{
ParseVehicleWheel( axle.wheels );
}
else if ( !Q_stricmp( key, "suspension" ) )
{
ParseVehicleSuspension( axle.suspension );
}
else
{
SkipBlock();
}
}
else if ( !Q_stricmp( key, "offset" ) )
{
ReadVector( value, axle.offset );
}
else if ( !Q_stricmp( key, "wheeloffset" ) )
{
ReadVector( value, axle.wheelOffset );
}
else if ( !Q_stricmp( key, "torquefactor" ) )
{
axle.torqueFactor = atof( value );
}
else if ( !Q_stricmp( key, "brakefactor" ) )
{
axle.brakeFactor = atof( value );
}
}
}
void CVPhysicsParse::ParseVehicleWheel( vehicle_wheelparams_t &wheel )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
if ( !Q_stricmp( key, "radius" ) )
{
wheel.radius = atof( value );
}
else if ( !Q_stricmp( key, "mass" ) )
{
wheel.mass = atof( value );
}
else if ( !Q_stricmp( key, "inertia" ) )
{
wheel.inertia = atof(value);
}
else if ( !Q_stricmp( key, "damping" ) )
{
wheel.damping = atof( value );
}
else if ( !Q_stricmp( key, "rotdamping" ) )
{
wheel.rotdamping = atof( value );
}
else if ( !Q_stricmp( key, "frictionscale" ) )
{
wheel.frictionScale = atof( value );
}
else if ( !Q_stricmp( key, "material" ) )
{
wheel.materialIndex = physprops->GetSurfaceIndex( value );
}
else if ( !Q_stricmp( key, "skidmaterial" ) )
{
wheel.skidMaterialIndex = physprops->GetSurfaceIndex( value );
}
else if ( !Q_stricmp( key, "brakematerial" ) )
{
wheel.brakeMaterialIndex = physprops->GetSurfaceIndex( value );
}
}
}
void CVPhysicsParse::ParseVehicleSuspension( vehicle_suspensionparams_t &suspension )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
if ( !Q_stricmp( key, "springconstant" ) )
{
suspension.springConstant = atof( value );
}
else if ( !Q_stricmp( key, "springdamping" ) )
{
suspension.springDamping = atof( value );
}
else if ( !Q_stricmp( key, "stabilizerconstant" ) )
{
suspension.stabilizerConstant = atof( value );
}
else if ( !Q_stricmp( key, "springdampingcompression" ) )
{
suspension.springDampingCompression = atof( value );
}
else if ( !Q_stricmp( key, "maxbodyforce" ) )
{
suspension.maxBodyForce = atof( value );
}
}
}
void CVPhysicsParse::ParseVehicleBody( vehicle_bodyparams_t &body )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
if ( !Q_stricmp( key, "massCenterOverride" ) )
{
ReadVector( value, body.massCenterOverride );
}
else if ( !Q_stricmp( key, "addgravity" ) )
{
body.addGravity = atof( value );
}
else if ( !Q_stricmp( key, "maxAngularVelocity" ) )
{
body.maxAngularVelocity = atof( value );
}
else if ( !Q_stricmp( key, "massOverride" ) )
{
body.massOverride = atof( value );
}
else if ( !Q_stricmp( key, "tiltforce" ) )
{
body.tiltForce = atof( value );
}
else if ( !Q_stricmp( key, "tiltforceheight" ) )
{
body.tiltForceHeight = atof( value );
}
else if ( !Q_stricmp( key, "countertorquefactor" ) )
{
body.counterTorqueFactor = atof( value );
}
else if ( !Q_stricmp( key, "keepuprighttorque" ) )
{
body.keepUprightTorque = atof( value );
}
}
}
void CVPhysicsParse::ParseVehicleEngineBoost( vehicle_engineparams_t &engine )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
// parse subchunks
if ( !Q_stricmp( key, "force" ) )
{
engine.boostForce = atof( value );
}
else if ( !Q_stricmp( key, "duration" ) )
{
engine.boostDuration = atof( value );
}
else if ( !Q_stricmp( key, "delay" ) )
{
engine.boostDelay = atof( value );
}
else if ( !Q_stricmp( key, "maxspeed" ) )
{
engine.boostMaxSpeed = atof( value );
}
else if ( !Q_stricmp( key, "torqueboost" ) )
{
engine.torqueBoost = atoi( value ) != 0 ? true : false;
}
}
}
void CVPhysicsParse::ParseVehicleEngine( vehicle_engineparams_t &engine )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
// parse subchunks
if ( value[0] == '{' )
{
if ( !Q_stricmp( key, "boost" ) )
{
ParseVehicleEngineBoost( engine );
}
else
{
SkipBlock();
}
}
else if ( !Q_stricmp( key, "gear" ) )
{
// Protect against exploits/overruns
if ( engine.gearCount < ARRAYSIZE(engine.gearRatio) )
{
engine.gearRatio[engine.gearCount] = atof( value );
engine.gearCount++;
}
else
{
Assert( 0 );
}
}
else if ( !Q_stricmp( key, "horsepower" ) )
{
engine.horsepower = atof( value );
}
else if ( !Q_stricmp( key, "maxSpeed" ) )
{
engine.maxSpeed = atof( value );
}
else if ( !Q_stricmp( key, "maxReverseSpeed" ) )
{
engine.maxRevSpeed = atof( value );
}
else if ( !Q_stricmp( key, "axleratio" ) )
{
engine.axleRatio = atof( value );
}
else if ( !Q_stricmp( key, "maxRPM" ) )
{
engine.maxRPM = atof( value );
}
else if ( !Q_stricmp( key, "throttleTime" ) )
{
engine.throttleTime = atof( value );
}
else if ( !Q_stricmp( key, "AutoTransmission" ) )
{
engine.isAutoTransmission = atoi( value ) != 0 ? true : false;
}
else if ( !Q_stricmp( key, "shiftUpRPM" ) )
{
engine.shiftUpRPM = atof( value );
}
else if ( !Q_stricmp( key, "shiftDownRPM" ) )
{
engine.shiftDownRPM = atof( value );
}
else if ( !Q_stricmp( key, "autobrakeSpeedGain" ) )
{
engine.autobrakeSpeedGain = atof( value );
}
else if ( !Q_stricmp( key, "autobrakeSpeedFactor" ) )
{
engine.autobrakeSpeedFactor = atof( value );
}
}
}
void CVPhysicsParse::ParseVehicleSteering( vehicle_steeringparams_t &steering )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
return;
// parse subchunks
if ( !Q_stricmp( key, "degreesSlow" ) )
{
steering.degreesSlow = atof( value );
}
else if ( !Q_stricmp( key, "degreesFast" ) )
{
steering.degreesFast = atof( value );
}
else if ( !Q_stricmp( key, "degreesBoost" ) )
{
steering.degreesBoost = atof( value );
}
else if ( !Q_stricmp( key, "fastcarspeed" ) )
{
steering.speedFast = atof( value );
}
else if ( !Q_stricmp( key, "slowcarspeed" ) )
{
steering.speedSlow = atof( value );
}
else if ( !Q_stricmp( key, "slowsteeringrate" ) )
{
steering.steeringRateSlow = atof( value );
}
else if ( !Q_stricmp( key, "faststeeringrate" ) )
{
steering.steeringRateFast = atof( value );
}
else if ( !Q_stricmp( key, "steeringRestRateSlow" ) )
{
steering.steeringRestRateSlow = atof( value );
}
else if ( !Q_stricmp( key, "steeringRestRateFast" ) )
{
steering.steeringRestRateFast = atof( value );
}
else if ( !Q_stricmp( key, "throttleSteeringRestRateFactor" ) )
{
steering.throttleSteeringRestRateFactor = atof( value );
}
else if ( !Q_stricmp( key, "boostSteeringRestRateFactor" ) )
{
steering.boostSteeringRestRateFactor = atof( value );
}
else if ( !Q_stricmp( key, "boostSteeringRateFactor" ) )
{
steering.boostSteeringRateFactor = atof( value );
}
else if ( !Q_stricmp( key, "steeringExponent" ) )
{
steering.steeringExponent = atof( value );
}
else if ( !Q_stricmp( key, "turnThrottleReduceSlow" ) )
{
steering.turnThrottleReduceSlow = atof( value );
}
else if ( !Q_stricmp( key, "turnThrottleReduceFast" ) )
{
steering.turnThrottleReduceFast = atof( value );
}
else if ( !Q_stricmp( key, "brakeSteeringRateFactor" ) )
{
steering.brakeSteeringRateFactor = atof( value );
}
else if ( !Q_stricmp( key, "powerSlideAccel" ) )
{
steering.powerSlideAccel = atof( value );
}
else if ( !Q_stricmp( key, "skidallowed" ) )
{
steering.isSkidAllowed = atoi( value ) != 0 ? true : false;
}
else if ( !Q_stricmp( key, "dustcloud" ) )
{
steering.dustCloud = atoi( value ) != 0 ? true : false;
}
}
}
void CVPhysicsParse::ParseVehicle( vehicleparams_t *pVehicle, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
if ( unknownKeyHandler )
{
unknownKeyHandler->SetDefaults( pVehicle );
}
else
{
memset( pVehicle, 0, sizeof(*pVehicle) );
}
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( key[0] == '}' )
{
NextBlock();
return;
}
// parse subchunks
if ( value[0] == '{' )
{
if ( !Q_stricmp( key, "axle" ) )
{
// Protect against exploits/overruns
if ( pVehicle->axleCount < ARRAYSIZE(pVehicle->axles) )
{
ParseVehicleAxle( pVehicle->axles[pVehicle->axleCount] );
pVehicle->axleCount++;
}
else
{
Assert( 0 );
}
}
else if ( !Q_stricmp( key, "body" ) )
{
ParseVehicleBody( pVehicle->body );
}
else if ( !Q_stricmp( key, "engine" ) )
{
ParseVehicleEngine( pVehicle->engine );
}
else if ( !Q_stricmp( key, "steering" ) )
{
ParseVehicleSteering( pVehicle->steering );
}
else
{
SkipBlock();
}
}
else if ( !Q_stricmp( key, "wheelsperaxle" ) )
{
pVehicle->wheelsPerAxle = atoi( value );
}
}
}
void CVPhysicsParse::ParseCustom( void *pCustom, IVPhysicsKeyHandler *unknownKeyHandler )
{
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
key[0] = 0;
int indent = 0;
if ( unknownKeyHandler )
{
unknownKeyHandler->SetDefaults( pCustom );
}
while ( m_pText )
{
m_pText = ParseKeyvalue( m_pText, key, value );
if ( m_pText )
{
if ( key[0] == '{' )
{
indent++;
}
else if ( value[0] == '{' )
{
// They've got a named block here
// Increase our indent, and let them parse the key
indent++;
if ( unknownKeyHandler )
{
unknownKeyHandler->ParseKeyValue( pCustom, key, value );
}
}
else if ( key[0] == '}' )
{
indent--;
if ( indent < 0 )
{
NextBlock();
return;
}
}
else
{
if ( unknownKeyHandler )
{
unknownKeyHandler->ParseKeyValue( pCustom, key, value );
}
}
}
}
}
IVPhysicsKeyParser *CreateVPhysicsKeyParser( const char *pKeyData )
{
return new CVPhysicsParse( pKeyData );
}
void DestroyVPhysicsKeyParser( IVPhysicsKeyParser *pParser )
{
delete pParser;
}
//-----------------------------------------------------------------------------
// Helper functions for parsing script file
//-----------------------------------------------------------------------------
const char *ParseKeyvalue( const char *pBuffer, char (&key)[MAX_KEYVALUE], char (&value)[MAX_KEYVALUE] )
{
// Make sure value is always null-terminated.
value[0] = 0;
pBuffer = ParseFile( pBuffer, key, NULL );
// no value on a close brace
if ( key[0] == '}' && key[1] == 0 )
{
value[0] = 0;
return pBuffer;
}
Q_strlower( key );
pBuffer = ParseFile( pBuffer, value, NULL );
Q_strlower( value );
return pBuffer;
}

View File

@ -0,0 +1,28 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VCOLLIDE_PARSE_PRIVATE_H
#define VCOLLIDE_PARSE_PRIVATE_H
#ifdef _WIN32
#pragma once
#endif
#include "vcollide_parse.h"
#define MAX_KEYVALUE 1024
class IVPhysicsKeyParser;
class CPackedPhysicsDescription;
const char *ParseKeyvalue( const char *pBuffer, OUT_Z_ARRAY char (&key)[MAX_KEYVALUE], OUT_Z_ARRAY char (&value)[MAX_KEYVALUE] );
IVPhysicsKeyParser *CreateVPhysicsKeyParser( const char *pKeyData );
void DestroyVPhysicsKeyParser( IVPhysicsKeyParser * );
const char *PackVCollideText( IPhysicsCollision *physcollision, const char *pTextIn, int *pSizeOut, bool storeSolidNames, bool storeSurfacepropsAsNames );
CPackedPhysicsDescription *CreatePackedDescription( const char *pPackedBuffer, int packedSize );
void DestroyPackedDescription( CPackedPhysicsDescription *pPhysics );
#endif // VCOLLIDE_PARSE_PRIVATE_H

136
vphysics-physx/vphysics.vpc Normal file
View File

@ -0,0 +1,136 @@
//-----------------------------------------------------------------------------
// VPHYSICS.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE;.;$SRCDIR\ivp\ivp_intern;$SRCDIR\ivp\ivp_collision;$SRCDIR\ivp\ivp_physics;$SRCDIR\ivp\ivp_surface_manager;$SRCDIR\ivp\ivp_utility;$SRCDIR\ivp\ivp_controller;$SRCDIR\ivp\ivp_compact_builder;$SRCDIR\ivp\havana\havok;$SRCDIR\ivp\havana"
$PreprocessorDefinitions "$BASE;VPHYSICS_EXPORTS;HAVANA_CONSTRAINTS;HAVOK_MOPP"
$Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
$Create/UsePCHThroughFile "cbase.h"
$PrecompiledHeaderFile "$(IntDir)\vphysics.pch"
// Language
$EnableRunTimeTypeInfo "No (/GR-)"
}
$Compiler [$WIN32]
{
$EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)"
}
$Linker
{
$AdditionalDependencies "$BASE odbc32.lib odbccp32.lib" [$WIN32]
$SystemLibraries "iconv" [$OSXALL]
}
}
$Project "vphysics"
{
$Folder "Source Files"
{
$File "stdafx.cpp"
{
$Configuration
{
$Compiler
{
$Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
}
}
}
$File "convert.cpp" \
"$SRCDIR\public\filesystem_helpers.cpp"
{
$Configuration
{
$Compiler
{
$Create/UsePrecompiledHeader "Not Using Precompiled Headers"
}
}
}
$File "ledgewriter.cpp"
$File "main.cpp"
$File "physics_airboat.cpp"
$File "physics_collide.cpp"
$File "physics_constraint.cpp"
$File "physics_controller_raycast_vehicle.cpp"
$File "physics_environment.cpp"
$File "physics_fluid.cpp"
$File "physics_friction.cpp"
$File "physics_material.cpp"
$File "physics_motioncontroller.cpp"
$File "physics_object.cpp"
$File "physics_shadow.cpp"
$File "physics_spring.cpp"
$File "physics_vehicle.cpp"
$File "physics_virtualmesh.cpp"
$File "trace.cpp"
$File "vcollide_parse.cpp"
$File "vphysics_saverestore.cpp"
}
$Folder "Header Files"
{
$File "cbase.h"
$File "convert.h"
$File "linear_solver.h"
$File "physics_airboat.h"
$File "physics_constraint.h"
$File "physics_controller_raycast_vehicle.h"
$File "physics_environment.h"
$File "physics_fluid.h"
$File "physics_friction.h"
$File "physics_material.h"
$File "physics_motioncontroller.h"
$File "physics_object.h"
$File "physics_shadow.h"
$File "physics_spring.h"
$File "physics_trace.h"
$File "physics_vehicle.h"
$File "vcollide_parse_private.h"
$File "vphysics_internal.h"
$File "vphysics_saverestore.h"
}
$Folder "Public Header Files"
{
$File "$SRCDIR\public\vphysics\collision_set.h"
$File "$SRCDIR\public\vphysics\constraints.h"
$File "$SRCDIR\public\datamap.h"
$File "$SRCDIR\public\filesystem_helpers.h"
$File "$SRCDIR\public\vphysics\friction.h"
$File "$SRCDIR\public\vphysics\object_hash.h"
$File "$SRCDIR\public\vphysics\performance.h"
$File "$SRCDIR\public\vphysics\player_controller.h"
$File "$SRCDIR\public\vphysics\stats.h"
$File "$SRCDIR\public\vcollide.h"
$File "$SRCDIR\public\vcollide_parse.h"
$File "$SRCDIR\public\vphysics\vehicles.h"
$File "$SRCDIR\public\vphysics_interface.h"
$File "$SRCDIR\public\vphysics_interfaceV30.h"
}
$Folder "Link Libraries"
{
$Lib "$LIBCOMMON/havana_constraints"
$Lib "$LIBCOMMON/hk_base"
$Lib "$LIBCOMMON/hk_math"
$Lib "$LIBCOMMON/ivp_compactbuilder"
$Lib "$LIBCOMMON/ivp_physics"
$Lib mathlib
$Lib tier2
}
}

View File

@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VPHYSICS_INTERNAL_H
#define VPHYSICS_INTERNAL_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/memalloc.h"
extern class IPhysics *g_PhysicsInternal;
//-----------------------------------------------------------------------------
// Memory debugging
//-----------------------------------------------------------------------------
#if defined(_DEBUG) || defined(USE_MEM_DEBUG)
#define BEGIN_IVP_ALLOCATION() MemAlloc_PushAllocDbgInfo("IVP: " __FILE__ , __LINE__ )
#define END_IVP_ALLOCATION() MemAlloc_PopAllocDbgInfo()
#else
#define BEGIN_IVP_ALLOCATION() 0
#define END_IVP_ALLOCATION() 0
#endif
#endif // VPHYSICS_INTERNAL_H

View File

@ -0,0 +1,224 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Phys pointer association
//-----------------------------------------------------------------------------
static CUtlMap<void *, void *> s_VPhysPtrMap( 0, 0, DefLessFunc(void *) );
CVPhysPtrSaveRestoreOps g_VPhysPtrSaveRestoreOps;
CVPhysPtrUtlVectorSaveRestoreOps g_VPhysPtrUtlVectorSaveRestoreOps;
//-----------------------------------------------------------------------------
// Phys pointer association
//-----------------------------------------------------------------------------
static void AddPtrAssociation( void *pOldValue, void *pNewValue )
{
s_VPhysPtrMap.Insert( pOldValue, pNewValue );
}
//-----------------------------------------------------------------------------
// Purpose: Save/load part of CPhysicsEnvironment
//-----------------------------------------------------------------------------
static bool NoPhysSaveFunc( const physsaveparams_t &params, void * )
{
AssertMsg( 0, "Physics cannot save the specified type" );
return false;
}
bool CPhysicsEnvironment::Save( const physsaveparams_t &params )
{
const PhysInterfaceId_t type = params.type;
Assert( type >= 0 && type < PIID_NUM_TYPES );
static PhysSaveFunc_t saveFuncs[PIID_NUM_TYPES] =
{
NoPhysSaveFunc,
(PhysSaveFunc_t)SavePhysicsObject,
(PhysSaveFunc_t)SavePhysicsFluidController,
(PhysSaveFunc_t)SavePhysicsSpring,
(PhysSaveFunc_t)SavePhysicsConstraintGroup,
(PhysSaveFunc_t)SavePhysicsConstraint,
(PhysSaveFunc_t)SavePhysicsShadowController,
(PhysSaveFunc_t)SavePhysicsPlayerController,
(PhysSaveFunc_t)SavePhysicsMotionController,
(PhysSaveFunc_t)SavePhysicsVehicleController,
};
if ( type >= 0 && type < PIID_NUM_TYPES )
{
params.pSave->WriteData( (char *)&params.pObject, sizeof(void*) );
return (*saveFuncs[type])( params, params.pObject );
}
return false;
}
static bool NoPhysRestoreFunc( const physrestoreparams_t &params, void ** )
{
AssertMsg( 0, "Physics cannot save the specified type" );
return false;
}
CVPhysPtrSaveRestoreOps::CVPhysPtrSaveRestoreOps()
{
}
void CPhysicsEnvironment::PreRestore( const physprerestoreparams_t &params )
{
g_VPhysPtrSaveRestoreOps.PreRestore();
for ( int i = 0; i < params.recreatedObjectCount; i++ )
{
AddPtrAssociation( params.recreatedObjectList[i].pOldObject, params.recreatedObjectList[i].pNewObject );
}
}
bool CPhysicsEnvironment::Restore( const physrestoreparams_t &params )
{
const PhysInterfaceId_t type = params.type;
Assert( type >= 0 && type < PIID_NUM_TYPES );
static PhysRestoreFunc_t restoreFuncs[PIID_NUM_TYPES] =
{
NoPhysRestoreFunc,
(PhysRestoreFunc_t)RestorePhysicsObject,
(PhysRestoreFunc_t)RestorePhysicsFluidController,
(PhysRestoreFunc_t)RestorePhysicsSpring,
(PhysRestoreFunc_t)RestorePhysicsConstraintGroup,
(PhysRestoreFunc_t)RestorePhysicsConstraint,
(PhysRestoreFunc_t)RestorePhysicsShadowController,
(PhysRestoreFunc_t)RestorePhysicsPlayerController,
(PhysRestoreFunc_t)RestorePhysicsMotionController,
(PhysRestoreFunc_t)RestorePhysicsVehicleController,
};
if ( type >= 0 && type < PIID_NUM_TYPES )
{
void *pOldObject;
params.pRestore->ReadData( (char *)&pOldObject, sizeof(void*), 0 );
if ( (*restoreFuncs[type])( params, params.ppObject ) )
{
AddPtrAssociation( pOldObject, *params.ppObject );
if ( type == PIID_IPHYSICSOBJECT )
{
m_objects.AddToTail( (IPhysicsObject *)(*params.ppObject) );
}
return true;
}
}
return false;
}
void CPhysicsEnvironment::PostRestore()
{
g_VPhysPtrSaveRestoreOps.PostRestore();
}
//-----------------------------------------------------------------------------
// Purpose: Fixes up pointers beteween vphysics objects
//-----------------------------------------------------------------------------
void CVPhysPtrSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
{
char *pField = (char *)fieldInfo.pField;
int nObjects = fieldInfo.pTypeDesc->fieldSize;
for ( int i = 0; i < nObjects; i++ )
{
pSave->WriteData( (char*)pField, sizeof(void*) );
pField += sizeof(void*);
}
}
//-------------------------------------
void CVPhysPtrSaveRestoreOps::PreRestore()
{
Assert( s_VPhysPtrMap.Count() == 0 );
}
//-------------------------------------
void CVPhysPtrSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
{
void **ppField = (void **)fieldInfo.pField;
int nObjects = fieldInfo.pTypeDesc->fieldSize;
for ( int i = 0; i < nObjects; i++ )
{
pRestore->ReadData( (char *)ppField, sizeof(void*), 0 );
int iNewVal = s_VPhysPtrMap.Find( *ppField );
if ( iNewVal != s_VPhysPtrMap.InvalidIndex() )
{
*ppField = s_VPhysPtrMap[iNewVal];
}
else
{
*ppField = NULL;
}
++ppField;
}
}
//-------------------------------------
void CVPhysPtrSaveRestoreOps::PostRestore()
{
s_VPhysPtrMap.RemoveAll();
PostRestorePhysicsObject();
PostRestorePhysicsConstraintGroup();
}
//-----------------------------------------------------------------------------
void CVPhysPtrUtlVectorSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
{
Assert( fieldInfo.pTypeDesc->fieldSize == 1 );
VPhysPtrVector *pUtlVector = (VPhysPtrVector*)fieldInfo.pField;
int nObjects = pUtlVector->Count();
pSave->WriteInt( &nObjects );
for ( int i = 0; i < nObjects; i++ )
{
pSave->WriteData( (char*)&pUtlVector->Element(i), sizeof(void*) );
}
}
void CVPhysPtrUtlVectorSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
{
Assert( fieldInfo.pTypeDesc->fieldSize == 1 );
VPhysPtrVector *pUtlVector = (VPhysPtrVector*)fieldInfo.pField;
int nObjects;
pRestore->ReadInt( &nObjects );
pUtlVector->AddMultipleToTail( nObjects );
for ( int i = 0; i < nObjects; i++ )
{
void **ppElem = (void**)(&pUtlVector->Element(i));
pRestore->ReadData( (char *)ppElem, sizeof(void*), 0 );
int iNewVal = s_VPhysPtrMap.Find( *ppElem );
if ( iNewVal != s_VPhysPtrMap.InvalidIndex() )
{
*ppElem = s_VPhysPtrMap[iNewVal];
}
else
{
*ppElem = NULL;
}
}
}

View File

@ -0,0 +1,119 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VPHYSICS_SAVERESTORE_H
#define VPHYSICS_SAVERESTORE_H
#if defined( _WIN32 )
#pragma once
#endif
#include "datamap.h"
#include "utlmap.h"
#include "isaverestore.h"
#include "utlvector.h"
//-------------------------------------
class ISave;
class IRestore;
class CPhysicsObject;
class CPhysicsFluidController;
class CPhysicsSpring;
class CPhysicsConstraint;
class CPhysicsConstraintGroup;
class CShadowController;
class CPlayerController;
class CPhysicsMotionController;
class CVehicleController;
struct physsaveparams_t;
struct physrestoreparams_t;
class ISaveRestoreOps;
//-----------------------------------------------------------------------------
// Purpose: Fixes up pointers beteween vphysics objects
//-----------------------------------------------------------------------------
class CVPhysPtrSaveRestoreOps : public CDefSaveRestoreOps
{
public:
CVPhysPtrSaveRestoreOps();
void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave );
void PreRestore();
void PostRestore();
void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore );
};
extern CVPhysPtrSaveRestoreOps g_VPhysPtrSaveRestoreOps;
#define DEFINE_VPHYSPTR(name) \
{ FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, &g_VPhysPtrSaveRestoreOps, NULL }
#define DEFINE_VPHYSPTR_ARRAY(name,count) \
{ FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, count, FTYPEDESC_SAVE, NULL, &g_VPhysPtrSaveRestoreOps, NULL }
//-----------------------------------------------------------------------------
class CVPhysPtrUtlVectorSaveRestoreOps : public CVPhysPtrSaveRestoreOps
{
public:
void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave );
void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore );
private:
typedef CUtlVector<intp> VPhysPtrVector;
};
extern CVPhysPtrUtlVectorSaveRestoreOps g_VPhysPtrUtlVectorSaveRestoreOps;
#define DEFINE_VPHYSPTR_UTLVECTOR(name) \
{ FIELD_CUSTOM, #name, { offsetof(classNameTypedef,name), 0 }, 1, FTYPEDESC_SAVE, NULL, &g_VPhysPtrUtlVectorSaveRestoreOps, NULL }
//-----------------------------------------------------------------------------
typedef bool (*PhysSaveFunc_t)( const physsaveparams_t &params, void *pCastedObject ); // second parameter for convenience
typedef bool (*PhysRestoreFunc_t)( const physrestoreparams_t &params, void **ppCastedObject );
bool SavePhysicsObject( const physsaveparams_t &params, CPhysicsObject *pObject );
bool RestorePhysicsObject( const physrestoreparams_t &params, CPhysicsObject **ppObject );
bool SavePhysicsFluidController( const physsaveparams_t &params, CPhysicsFluidController *pFluidObject );
bool RestorePhysicsFluidController( const physrestoreparams_t &params, CPhysicsFluidController **ppFluidObject );
bool SavePhysicsSpring( const physsaveparams_t &params, CPhysicsSpring *pSpring );
bool RestorePhysicsSpring( const physrestoreparams_t &params, CPhysicsSpring **ppSpring );
bool SavePhysicsConstraint( const physsaveparams_t &params, CPhysicsConstraint *pConstraint );
bool RestorePhysicsConstraint( const physrestoreparams_t &params, CPhysicsConstraint **ppConstraint );
bool SavePhysicsConstraintGroup( const physsaveparams_t &params, CPhysicsConstraintGroup *pConstraintGroup );
bool RestorePhysicsConstraintGroup( const physrestoreparams_t &params, CPhysicsConstraintGroup **ppConstraintGroup );
void PostRestorePhysicsConstraintGroup();
bool SavePhysicsShadowController( const physsaveparams_t &params, IPhysicsShadowController *pShadowController );
bool RestorePhysicsShadowController( const physrestoreparams_t &params, IPhysicsShadowController **ppShadowController );
bool RestorePhysicsShadowControllerInternal( const physrestoreparams_t &params, IPhysicsShadowController **ppShadowController, CPhysicsObject *pObject );
bool SavePhysicsPlayerController( const physsaveparams_t &params, CPlayerController *pPlayerController );
bool RestorePhysicsPlayerController( const physrestoreparams_t &params, CPlayerController **ppPlayerController );
bool SavePhysicsMotionController( const physsaveparams_t &params, IPhysicsMotionController *pMotionController );
bool RestorePhysicsMotionController( const physrestoreparams_t &params, IPhysicsMotionController **ppMotionController );
bool SavePhysicsVehicleController( const physsaveparams_t &params, CVehicleController *pVehicleController );
bool RestorePhysicsVehicleController( const physrestoreparams_t &params, CVehicleController **ppVehicleController );
//-----------------------------------------------------------------------------
ISaveRestoreOps* MaterialIndexDataOps();
#endif // VPHYSICS_SAVERESTORE_H

95
vphysics-physx/wscript Executable file
View File

@ -0,0 +1,95 @@
#! /usr/bin/env python
# encoding: utf-8
from waflib import Utils
import os
top = '.'
PROJECT_NAME = 'vphysics'
def options(opt):
# stub
return
def configure(conf):
conf.env.append_unique('DEFINES',[
'VPHYSICS_EXPORTS',
'HAVANA_CONSTRAINTS',
'HAVOK_MOPP'
])
conf.env.append_unique('LINKFLAGS', [
# "-L/home/nillerusr/projects/PhysX/physx/install/linux/PhysX/bin/linux.clang/release/"
"-L/home/nillerusr/projects/PhysX/physx/install/linux/PhysX/bin/linux.clang/debug/"
])
conf.check(lib='PhysX_static_64', uselib_store='PHYSX')
conf.check(lib='PhysXFoundation_static_64', uselib_store='PHYSX_FOUNDATION')
conf.check(lib='PhysXCommon_static_64', uselib_store='PHYSX_COMMON')
conf.check(lib='PhysXPvdSDK_static_64', uselib_store='PHYSX_PVD')
conf.check(lib='PhysXExtensions_static_64', uselib_store='PHYSX_EXT')
conf.check(lib='PhysXCooking_static_64', uselib_store='PHYSX_COOKING')
def build(bld):
source = [
'convert.cpp',
'../public/filesystem_helpers.cpp',
'ledgewriter.cpp',
'main.cpp',
'physics_airboat.cpp',
'physics_collide.cpp',
'physics_constraint.cpp',
'physics_controller_raycast_vehicle.cpp',
'physics_environment.cpp',
'physics_fluid.cpp',
'physics_friction.cpp',
'physics_material.cpp',
'physics_motioncontroller.cpp',
'physics_object.cpp',
'physics_shadow.cpp',
'physics_spring.cpp',
'physics_vehicle.cpp',
'physics_virtualmesh.cpp',
'trace.cpp',
'vcollide_parse.cpp',
'vphysics_saverestore.cpp',
'../public/tier0/memoverride.cpp'
]
includes = [
'.',
'../public',
'../public/tier0',
'../public/tier1',
'../ivp/ivp_intern',
'../ivp/ivp_collision',
'../ivp/ivp_physics',
'../ivp/ivp_surface_manager',
'../ivp/ivp_utility',
'../ivp/ivp_controller',
'../ivp/ivp_compact_builder',
'../ivp/havana/havok',
'../ivp/havana',
'/home/nillerusr/projects/PhysX/physx/install/linux/PhysX/include',
'/home/nillerusr/projects/PhysX/physx/install/linux/PxShared/include'
]
defines = []
libs = ['tier0','havana_constraints','hk_math','hk_base','ivp_compactbuilder','ivp_physics','tier1','tier2','vstdlib','mathlib', 'PHYSX', 'PHYSX_PVD', 'PHYSX_EXT', 'PHYSX_COOKING', 'PHYSX_FOUNDATION', 'PHYSX_COMMON']
install_path = bld.env.LIBDIR
bld.shlib(
source = source,
target = PROJECT_NAME,
name = PROJECT_NAME,
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = bld.get_taskgen_count()
)

View File

@ -0,0 +1,3 @@
LIBRARY vphysics_360.dll
EXPORTS
CreateInterface @1

14
waf vendored

File diff suppressed because one or more lines are too long

66
wscript
View File

@ -26,21 +26,6 @@ FC_CHECK='''extern "C" {
int main() { return (int)FcInit(); }
'''
CPP_64BIT_CHECK='''
#define TEST(a) (sizeof(void*) == a ? 1 : -1)
int g_Test[TEST(8)];
int main () { return 0; }
'''
CPP_32BIT_CHECK='''
#define TEST(a) (sizeof(void*) == a ? 1 : -1)
int g_Test[TEST(4)];
int main () { return 0; }
'''
Context.Context.line_just = 55 # should fit for everything on 80x26
projects={
@ -87,7 +72,7 @@ projects={
'vgui2/vgui_surfacelib',
'vguimatsurface',
'video',
'vphysics',
'vphysics-physx',
'vpklib',
'vstdlib',
'vtf',
@ -140,7 +125,6 @@ projects={
'tier1',
'tier2',
'tier3',
'vgui2/vgui_controls',
'vphysics',
'vpklib',
'vstdlib',
@ -171,11 +155,6 @@ def get_taskgen_count(self):
except: idx = 0 # don't set tg_idx_count to not increase counter
return idx
@Configure.conf
def run_test(self, fragment, msg):
result = self.check_cxx(fragment=fragment, msg=msg, mandatory = False)
return False if result == None else True
def define_platform(conf):
conf.env.DEDICATED = conf.options.DEDICATED
conf.env.TESTS = conf.options.TESTS
@ -183,12 +162,6 @@ def define_platform(conf):
conf.env.GL = conf.options.GL and not conf.options.TESTS and not conf.options.DEDICATED
conf.env.OPUS = conf.options.OPUS
arch32 = conf.run_test(CPP_32BIT_CHECK, 'Testing 32bit support')
arch64 = conf.run_test(CPP_64BIT_CHECK, 'Testing 64bit support')
if not (arch32 ^ arch64):
conf.fatal('Your compiler sucks')
if conf.options.DEDICATED:
conf.options.SDL = False
conf.define('DEDICATED', 1)
@ -213,7 +186,7 @@ def define_platform(conf):
conf.env.SDL = 1
conf.define('USE_SDL', 1)
if arch64:
if conf.options.ALLOW64:
conf.define('PLATFORM_64BITS', 1)
if conf.env.DEST_OS == 'linux':
@ -279,14 +252,11 @@ def define_platform(conf):
'NDEBUG'
])
conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION)
def options(opt):
grp = opt.add_option_group('Common options')
grp.add_option('-4', '--32bits', action = 'store_true', dest = 'TARGET32', default = False,
help = 'allow targetting 32-bit engine(Linux/Windows/OSX x86 only) [default: %default]')
grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False,
help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]')
grp.add_option('-d', '--dedicated', action = 'store_true', dest = 'DEDICATED', default = False,
help = 'build dedicated server [default: %default]')
@ -332,7 +302,7 @@ def options(opt):
def check_deps(conf):
if conf.env.DEST_OS != 'win32':
conf.check_cc(lib='dl', mandatory=False)
conf.check_cc(lib='bz2', mandatory=True)
conf.check_cc(lib='bz2', mandatory=False)
conf.check_cc(lib='rt', mandatory=False)
if not conf.env.LIB_M: # HACK: already added in xcompile!
@ -440,24 +410,19 @@ def configure(conf):
# subsystem=bld.env.MSVC_SUBSYSTEM
# TODO: wrapper around bld.stlib, bld.shlib and so on?
conf.env.MSVC_SUBSYSTEM = 'WINDOWS,5.01'
conf.env.MSVC_TARGETS = ['x64'] # explicitly request x86 target for MSVC
if conf.options.TARGET32:
conf.env.MSVC_TARGETS = ['x86']
conf.env.MSVC_TARGETS = ['x86'] # explicitly request x86 target for MSVC
if conf.options.ALLOW64:
conf.env.MSVC_TARGETS = ['x64']
if sys.platform == 'win32':
conf.load('msvc_pdb_ext msdev msvs msvcdeps')
conf.load('subproject xcompile compiler_c compiler_cxx gccdeps gitversion clang_compilation_database strip_on_install_v2 waf_unit_test enforce_pic')
conf.load('msvc_pdb_ext msdev msvs')
conf.load('subproject xcompile compiler_c compiler_cxx gitversion clang_compilation_database strip_on_install_v2 waf_unit_test enforce_pic')
if conf.env.DEST_OS == 'win32' and conf.env.DEST_CPU == 'amd64':
conf.load('masm')
elif conf.env.DEST_OS == 'darwin':
conf.load('mm_hook')
conf.env.BIT32_MANDATORY = conf.options.TARGET32
if conf.env.BIT32_MANDATORY:
Logs.info('WARNING: will build engine for 32-bit target')
conf.load('force_32bit')
define_platform(conf)
conf.define('GIT_COMMIT_HASH', conf.env.GIT_VERSION)
if conf.env.TOGLES:
projects['game'] += ['togles']
@ -470,6 +435,11 @@ def configure(conf):
if conf.options.OPUS or conf.env.DEST_OS == 'android':
projects['game'] += ['engine/voice_codecs/opus']
conf.env.BIT32_MANDATORY = not conf.options.ALLOW64
if conf.env.BIT32_MANDATORY:
Logs.info('WARNING: will build engine for 32-bit target')
conf.load('force_32bit')
if conf.options.DISABLE_WARNS:
compiler_optional_flags = ['-w']
else:
@ -527,7 +497,7 @@ def configure(conf):
flags += ['-fsigned-char']
if conf.env.DEST_CPU == 'arm':
flags += ['-march=armv7-a', '-mfpu=neon-vfpv4']
flags += ['-mfpu=neon-vfpv4']
if conf.env.DEST_OS == 'freebsd':
linkflags += ['-lexecinfo']
@ -551,11 +521,11 @@ def configure(conf):
if conf.options.BUILD_TYPE == 'debug':
linkflags += [
'/FORCE:MULTIPLE',
'/INCREMENTAL:NO',
'/NODEFAULTLIB:libc',
'/NODEFAULTLIB:libcd',
'/NODEFAULTLIB:libcmt',
'/FORCE',
'/LARGEADDRESSAWARE'
]
else: