make original vphysics copy to track changes

This commit is contained in:
nillerusr
2023-10-16 07:57:53 +03:00
parent ee6a6d0b37
commit 490bd8b42d
57 changed files with 27697 additions and 0 deletions

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

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

@@ -0,0 +1,365 @@
//========= 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 )
{
#if USE_CACHE_OBJECT
IVP_Cache_Object *cache = pObject->get_cache_object_no_lock();
if ( translate )
{
cache->transform_position_to_object_coords( &pointIn, &pointOut );
}
else
{
cache->transform_vector_to_object_coords( &pointIn, &pointOut );
}
#else
const IVP_U_Matrix *pMatrix = GetTmpObjectMatrix( pObject );
if ( translate )
{
pMatrix->inline_vimult4( &pointIn, &pointOut );
}
else
{
pMatrix->inline_vimult3( &pointIn, &pointOut );
}
#endif
}
void TransformLocalToIVP( const IVP_U_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
#if USE_CACHE_OBJECT
IVP_Cache_Object *cache = pObject->get_cache_object_no_lock();
if ( translate )
{
IVP_U_Float_Point floatPointIn;
floatPointIn.set( &pointIn );
cache->transform_position_to_world_coords( &floatPointIn, &pointOut );
}
else
{
cache->transform_vector_to_world_coords( &pointIn, &pointOut );
}
#else
const IVP_U_Matrix *pMatrix = GetTmpObjectMatrix( pObject );
if ( translate )
{
pMatrix->inline_vmult4( &pointIn, &pointOut );
}
else
{
pMatrix->inline_vmult3( &pointIn, &pointOut );
}
#endif
}
void TransformLocalToIVP( const IVP_U_Float_Point &pointIn, IVP_U_Point &pointOut, IVP_Real_Object *pObject, bool translate )
{
#if USE_CACHE_OBJECT
IVP_Cache_Object *cache = pObject->get_cache_object_no_lock();
if ( translate )
{
cache->transform_position_to_world_coords( &pointIn, &pointOut );
}
else
{
IVP_U_Point doublePointIn;
doublePointIn.set( &pointIn );
cache->transform_vector_to_world_coords( &doublePointIn, &pointOut );
}
#else
const IVP_U_Matrix *pMatrix = GetTmpObjectMatrix( pObject );
IVP_U_Float_Point out;
if ( translate )
{
pMatrix->inline_vmult4( &pointIn, &out );
}
else
{
pMatrix->inline_vmult3( &pointIn, &out );
}
pointOut.set( &out );
#endif
}
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

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

@@ -0,0 +1,242 @@
//========= 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"
#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);
}
#if defined(_WIN32) && !defined(_XBOX)
//HMODULE gPhysicsDLLHandle;
#pragma warning (disable:4100)
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
if ( fdwReason == DLL_PROCESS_ATTACH )
{
// ivp_set_message_print_function( ivu_string_print_function );
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
// store out module handle
//gPhysicsDLLHandle = (HMODULE)hinstDLL;
}
else if ( fdwReason == DLL_PROCESS_DETACH )
{
}
return TRUE;
}
#endif // _WIN32
#ifdef POSIX
void __attribute__ ((constructor)) vphysics_init(void);
void vphysics_init(void)
{
// ivp_set_message_print_function( ivu_string_print_function );
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
}
#endif
// 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 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();
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 );
//-----------------------------------------------------------------------------
// 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;
}
// In release build, each of these libraries must contain a symbol that indicates it is also a release build
// You MUST disable this in order to run a release vphysics.dll with a debug library.
// This should not usually be necessary
// #if !defined(_DEBUG) && defined(_WIN32)
// extern int ivp_physics_lib_is_a_release_build;
// extern int ivp_compactbuilder_lib_is_a_release_build;
// extern int hk_base_lib_is_a_release_build;
// extern int hk_math_lib_is_a_release_build;
// extern int havana_constraints_lib_is_a_release_build;
// void DebugTestFunction()
// {
// ivp_physics_lib_is_a_release_build = 0;
// ivp_compactbuilder_lib_is_a_release_build = 0;
// hk_base_lib_is_a_release_build = 0;
// hk_math_lib_is_a_release_build = 0;
// havana_constraints_lib_is_a_release_build = 0;
// }
// #endif

View File

@@ -0,0 +1,260 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "interface.h"
#include "vphysics/object_hash.h"
#include "vphysics/collision_set.h"
#include "tier1/tier1.h"
#include "ivu_vhash.hxx"
#include "PxPhysicsAPI.h"
using namespace physx;
#if defined(_WIN32) && !defined(_X360)
#define WIN32_LEAN_AND_MEAN
#include <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;
PxCoocking
// simple 32x32 bit array
class CPhysicsCollisionSet : public IPhysicsCollisionSet
{
public:
~CPhysicsCollisionSet() {}
CPhysicsCollisionSet()
{
memset( m_bits, 0, sizeof(m_bits) );
}
void EnableCollisions( int index0, int index1 )
{
Assert(index0<32&&index1<32);
m_bits[index0] |= 1<<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);
gPxPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gPxFoundation, PxTolerancesScale(), recordMemoryAllocations, gPxPvd);
if( !gPxPhysics )
{
Error("PxCreatePhysics failed!\n");
return INIT_FAILED;
}
return INIT_OK;
}
void CPhysicsInterface::Shutdown()
{
if( gPxPhysics )
gPxPhysics->release();
if( gPxFoundation )
gPxFoundation->release();
BaseClass::Shutdown( );
}
//-----------------------------------------------------------------------------
// Query interface
//-----------------------------------------------------------------------------
void *CPhysicsInterface::QueryInterface( const char *pInterfaceName )
{
// Loading the datacache DLL mounts *all* interfaces
// This includes the backward-compatible interfaces + other vphysics interfaces
CreateInterfaceFn factory = Sys_GetFactoryThis(); // This silly construction is necessary
return factory( pInterfaceName, NULL ); // to prevent the LTCG compiler from crashing.
}
//-----------------------------------------------------------------------------
// Implementation of IPhysics
//-----------------------------------------------------------------------------
IPhysicsEnvironment *CPhysicsInterface::CreateEnvironment( void )
{
IPhysicsEnvironment *pEnvironment = CreatePhysicsEnvironment();
m_envList.AddToTail( pEnvironment );
return pEnvironment;
}
void CPhysicsInterface::DestroyEnvironment( IPhysicsEnvironment *pEnvironment )
{
m_envList.FindAndRemove( pEnvironment );
delete pEnvironment;
}
IPhysicsEnvironment *CPhysicsInterface::GetActiveEnvironmentByIndex( int index )
{
if ( index < 0 || index >= m_envList.Count() )
return NULL;
return m_envList[index];
}
IPhysicsObjectPairHash *CPhysicsInterface::CreateObjectPairHash()
{
return ::CreateObjectPairHash();
}
void CPhysicsInterface::DestroyObjectPairHash( IPhysicsObjectPairHash *pHash )
{
delete pHash;
}
// holds a cache of these by id.
// NOTE: This is stuffed into vphysics.dll as a sneaky way of sharing the memory between
// client and server in single player. So you can't have different client/server rules.
IPhysicsCollisionSet *CPhysicsInterface::FindOrCreateCollisionSet( unsigned int id, int maxElementCount )
{
if ( !m_pCollisionSetHash )
{
m_pCollisionSetHash = new IVP_VHash_Store(256);
}
Assert( id != 0 );
Assert( maxElementCount <= 32 );
if ( maxElementCount > 32 )
return NULL;
IPhysicsCollisionSet *pSet = FindCollisionSet( id );
if ( pSet )
return pSet;
intp index = m_collisionSets.AddToTail();
m_pCollisionSetHash->add_elem( (void *)(intp)id, (void *)(intp)(index+1) );
return &m_collisionSets[index];
}
IPhysicsCollisionSet *CPhysicsInterface::FindCollisionSet( unsigned int id )
{
if ( m_pCollisionSetHash )
{
intp index = (intp)m_pCollisionSetHash->find_elem( (void *)(intp)id );
if ( index > 0 )
{
Assert( index <= m_collisionSets.Count() );
if ( index <= m_collisionSets.Count() )
{
return &m_collisionSets[index-1];
}
}
}
return NULL;
}
void CPhysicsInterface::DestroyAllCollisionSets()
{
m_collisionSets.Purge();
delete m_pCollisionSetHash;
m_pCollisionSetHash = NULL;
}

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

File diff suppressed because it is too large Load Diff

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,176 @@
//========= 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"
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 );
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;
};
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,231 @@
//========= 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();
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,199 @@
//========= 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 )
{
IVP_Synapse_Friction *pFriction = m_pFriction;
if ( index == 1 )
{
pFriction = m_pContactPoint->get_synapse(!m_synapseIndex);
}
return static_cast<IPhysicsObject *>(pFriction->get_object()->client_data);
}
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,9 @@
#include "PxPhysicsAPI.h"
using namespace physx;
extern PxFoundation *gPxFoundation;
extern PxPvd *gPxPvd;
extern PxPhysics *gPxPhysics;

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

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,244 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PHYSICS_TRACE_H
#define PHYSICS_TRACE_H
#ifdef _WIN32
#pragma once
#endif
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;
};
#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; }
};
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"

2474
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 <20> 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

80
vphysics-physx/wscript Executable file
View File

@@ -0,0 +1,80 @@
#! /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'
])
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'
]
defines = []
libs = ['tier0','havana_constraints','hk_math','hk_base','ivp_compactbuilder','ivp_physics','tier1','tier2','vstdlib','mathlib']
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