Quake 4 integrated with DoomRTX

This commit is contained in:
Justin Marshall
2026-05-09 22:10:40 -07:00
parent 8c4a087aa9
commit d37f87e493
436 changed files with 277587 additions and 10254 deletions
File diff suppressed because it is too large Load Diff
+407
View File
@@ -0,0 +1,407 @@
#ifndef __CLIP_H__
#define __CLIP_H__
// RAVEN BEGIN
// ddynerman: SD's clip sector code
const int CLIPSECTOR_DEPTH = 6;
const int CLIPSECTOR_WIDTH = 1 << CLIPSECTOR_DEPTH;
// RAVEN END
/*
===============================================================================
Handles collision detection with the world and between physics objects.
===============================================================================
*/
#define CLIPMODEL_ID_TO_JOINT_HANDLE( id ) ( ( id ) >= 0 ? INVALID_JOINT : ((jointHandle_t) ( -1 - id )) )
#define JOINT_HANDLE_TO_CLIPMODEL_ID( id ) ( -1 - id )
class idClip;
class idClipModel;
class idEntity;
//===============================================================
//
// idClipModel
//
//===============================================================
class idClipModel {
friend class idClip;
public:
idClipModel( void );
explicit idClipModel( const char *name );
explicit idClipModel( const idTraceModel &trm, const idMaterial *material = NULL );
explicit idClipModel( const int renderModelHandle );
explicit idClipModel( const idClipModel *model );
~idClipModel( void );
// RAVEN BEGIN
// ddynerman: SD's clip sector code
void UpdateDynamicContents( void );
// RAVEN END
bool LoadModel( const char *name );
void LoadModel( const idTraceModel &trm, const idMaterial *material, bool notHashed = false );
void LoadModel( const int renderModelHandle );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// RAVEN BEGIN
// ddynerman: multiple clip worlds
void Link( void ); // must have been linked with an entity and id before
void Link( idEntity *ent, int newId, const idVec3 &newOrigin, const idMat3 &newAxis, int renderModelHandle = -1 );
// RAVEN END
void Unlink( void ); // unlink from sectors
void SetPosition( const idVec3 &newOrigin, const idMat3 &newAxis ); // unlinks the clip model
void Translate( const idVec3 &translation ); // unlinks the clip model
void Rotate( const idRotation &rotation ); // unlinks the clip model
void Enable( void ); // enable for clipping
void Disable( void ); // keep linked but disable for clipping
void SetContents( int newContents ); // override contents
int GetContents( void ) const;
void SetEntity( idEntity *newEntity );
idEntity * GetEntity( void ) const;
void SetId( int newId );
int GetId( void ) const;
void SetOwner( idEntity *newOwner );
idEntity * GetOwner( void ) const;
const idBounds & GetBounds( void ) const;
const idBounds & GetAbsBounds( void ) const;
const idVec3 & GetOrigin( void ) const;
const idMat3 & GetAxis( void ) const;
bool IsTraceModel( void ) const; // returns true if this is a trace model
bool IsRenderModel( void ) const; // returns true if this is a render model
bool IsLinked( void ) const; // returns true if the clip model is linked
bool IsEnabled( void ) const; // returns true if enabled for collision detection
bool IsEqual( const idTraceModel &trm ) const;
idCollisionModel * GetCollisionModel( void ) const; // returns handle used to collide vs this model
const idTraceModel * GetTraceModel( void ) const;
void GetMassProperties( const float density, float &mass, idVec3 &centerOfMass, idMat3 &inertiaTensor ) const;
static void ClearTraceModelCache( void );
static int TraceModelCacheSize( void );
static void SaveTraceModels( idSaveGame *savefile );
static void RestoreTraceModels( idRestoreGame *savefile );
private:
bool enabled; // true if this clip model is used for clipping
// RAVEN BEGIN
bool checked; // Splash's clip model code
// RAVEN END
idEntity * entity; // entity using this clip model
int id; // id for entities that use multiple clip models
idEntity * owner; // owner of the entity that owns this clip model
idVec3 origin; // origin of clip model
idMat3 axis; // orientation of clip model
idBounds bounds; // bounds
idBounds absBounds; // absolute bounds
int contents; // all contents ored together
idCollisionModel * collisionModel; // handle to collision model
int traceModelIndex; // trace model used for collision detection
int renderModelHandle; // render model def handle
struct clipLink_s * clipLinks; // links into sectors
int touchCount;
void Init( void ); // initialize
void FreeModel( void );
void Link_r( struct clipSector_s *node );
static void CacheCollisionModels( void );
static int AllocTraceModel( const idTraceModel &trm, const idMaterial *material, bool notHashed = false );
static void ReplaceTraceModel( int index, const idTraceModel &trm, const idMaterial *material, bool notHashed = false );
static void FreeTraceModel( int traceModelIndex );
static int CopyTraceModel( const int traceModelIndex );
static idTraceModel * GetCachedTraceModel( int traceModelIndex );
static idCollisionModel*GetCachedCollisionModel( int traceModelIndex );
static int GetTraceModelHashKey( const idTraceModel &trm );
};
ID_INLINE void idClipModel::Translate( const idVec3 &translation ) {
Unlink();
origin += translation;
}
ID_INLINE void idClipModel::Rotate( const idRotation &rotation ) {
Unlink();
origin *= rotation;
axis *= rotation.ToMat3();
}
ID_INLINE void idClipModel::Enable( void ) {
enabled = true;
}
ID_INLINE void idClipModel::Disable( void ) {
enabled = false;
}
ID_INLINE void idClipModel::SetContents( int newContents ) {
contents = newContents;
// RAVEN BEGIN
// ddynerman: SD's clip sector code
UpdateDynamicContents();
// RAVEN END
}
ID_INLINE int idClipModel::GetContents( void ) const {
return contents;
}
ID_INLINE void idClipModel::SetEntity( idEntity *newEntity ) {
entity = newEntity;
}
ID_INLINE idEntity *idClipModel::GetEntity( void ) const {
return entity;
}
ID_INLINE void idClipModel::SetId( int newId ) {
id = newId;
}
ID_INLINE int idClipModel::GetId( void ) const {
return id;
}
ID_INLINE void idClipModel::SetOwner( idEntity *newOwner ) {
owner = newOwner;
}
ID_INLINE idEntity *idClipModel::GetOwner( void ) const {
return owner;
}
ID_INLINE const idBounds &idClipModel::GetBounds( void ) const {
return bounds;
}
ID_INLINE const idBounds &idClipModel::GetAbsBounds( void ) const {
return absBounds;
}
ID_INLINE const idVec3 &idClipModel::GetOrigin( void ) const {
return origin;
}
ID_INLINE const idMat3 &idClipModel::GetAxis( void ) const {
return axis;
}
ID_INLINE bool idClipModel::IsRenderModel( void ) const {
return ( renderModelHandle != -1 );
}
ID_INLINE bool idClipModel::IsTraceModel( void ) const {
return ( traceModelIndex != -1 );
}
ID_INLINE bool idClipModel::IsLinked( void ) const {
return ( clipLinks != NULL );
}
ID_INLINE bool idClipModel::IsEnabled( void ) const {
return enabled;
}
ID_INLINE bool idClipModel::IsEqual( const idTraceModel &trm ) const {
return ( traceModelIndex != -1 && *GetCachedTraceModel( traceModelIndex ) == trm );
}
ID_INLINE const idTraceModel *idClipModel::GetTraceModel( void ) const {
if ( !IsTraceModel() ) {
return NULL;
}
return idClipModel::GetCachedTraceModel( traceModelIndex );
}
//===============================================================
//
// idClip
//
//===============================================================
class idClip {
friend class idClipModel;
public:
idClip( void );
void Init( void );
void Shutdown( void );
// clip versus the rest of the world
// RAVEN BEGIN
// nmckenzie: we have cases where both a guy and his target need to be ignored by a translation
bool Translation( trace_t &results, const idVec3 &start, const idVec3 &end,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, const idEntity *passEntity2 = 0 );
// RAVEN END
bool Rotation( trace_t &results, const idVec3 &start, const idRotation &rotation,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
bool Motion( trace_t &results, const idVec3 &start, const idVec3 &end, const idRotation &rotation,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
int Contacts( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity );
// RAVEN BEGIN
// AReis: Added ability to get the entity that was touched as well.
int Contents( const idVec3 &start,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, idEntity **touchedEntity = NULL );
// RAVEN END
// special case translations versus the rest of the world
bool TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end,
int contentMask, const idEntity *passEntity );
bool TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds,
int contentMask, const idEntity *passEntity );
// clip versus a specific model
void TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
void RotationModel( trace_t &results, const idVec3 &start, const idRotation &rotation,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
int ContactsModel( contactInfo_t *contacts, const int maxContacts, const idVec3 &start, const idVec6 &dir, const float depth,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
int ContentsModel( const idVec3 &start,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask,
idCollisionModel *model, const idVec3 &modelOrigin, const idMat3 &modelAxis );
// clip versus all entities but not the world
// RAVEN BEGIN
// nmckenzie: had to add a second pass entity so we can safely ignore both a guy and his target in some cases
void TranslationEntities( trace_t &results, const idVec3 &start, const idVec3 &end,
const idClipModel *mdl, const idMat3 &trmAxis, int contentMask, const idEntity *passEntity, const idEntity *passEntity2 = 0 );
// RAVEN END
// get a contact feature
bool GetModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, idFixedWinding &winding ) const;
// get entities/clip models within or touching the given bounds
int EntitiesTouchingBounds( const idBounds &bounds, int contentMask, idEntity **entityList, int maxCount ) const;
int ClipModelsTouchingBounds( const idBounds &bounds, int contentMask, idClipModel **clipModelList, int maxCount ) const;
// RAVEN BEGIN
// ddynerman: another helper function, useful in MP
int PlayersTouchingBounds( const idBounds &bounds, int contentMask, idPlayer **entityList, int maxCount ) const;
// RAVEN END
const idBounds & GetWorldBounds( void ) const;
idCollisionModel * GetWorldCollisionModel( void ) const { return world; }
// RAVEN BEGIN
// ddynerman: change to static
static idClipModel * DefaultClipModel( void );
static void FreeDefaultClipModel( void );
// RAVEN END
// stats and debug drawing
void PrintStatistics( void );
void DrawClipModels( const idVec3 &eye, const float radius, const idEntity *passEntity, const idTypeInfo* type = NULL );
bool DrawModelContactFeature( const contactInfo_t &contact, const idClipModel *clipModel, int lifetime ) const;
// RAVEN BEGIN
// rjohnson: added debug hud support
void DebugHudStatistics( void );
void ClearStatistics( void );
// RAVEN END
// RAVEN BEGIN
// ddynerman: SD's clip sector code
void CoordsForBounds( int* coords, idBounds& bounds ) const;
void DrawClipSectors( void ) const;
void DrawAreaClipSectors( float range ) const;
static void UpdateDynamicContents( struct clipSector_s* sector );
static void UpdateDynamicContents( idClipModel* clipModel );
// RAVEN END
private:
// RAVEN BEGIN
// ddynerman: SD's clip sector code
idVec3 nodeScale;
idVec3 nodeOffset;
idVec3 nodeOffsetVisual;
// ddynerman: change to static
static idClipModel defaultClipModel;
// RAVEN END
struct clipSector_s * clipSectors;
idCollisionModel * world;
idBounds worldBounds;
idClipModel temporaryClipModel;
mutable int touchCount;
// statistics
int numTranslations;
int numRotations;
int numMotions;
int numRenderModelTraces;
int numContents;
int numContacts;
private:
struct clipSector_s * CreateClipSectors_r( const int depth, const idBounds &bounds, idVec3 &maxSector );
void ClipModelsTouchingBounds_r( const struct clipSector_s *node, struct listParms_s &parms ) const;
const idTraceModel * TraceModelForClipModel( const idClipModel *mdl ) const;
// RAVEN BEGIN
// nmckenzie: had to add a second pass entity so we can safely ignore both a guy and his target in some cases
int GetTraceClipModels( const idBounds &bounds, int contentMask, const idEntity *passEntity, idClipModel **clipModelList, const idEntity *passEntity2 = 0 ) const;
// RAVEN END
void TraceRenderModel( trace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, const idMat3 &axis, idClipModel *touch ) const;
// RAVEN BEGIN
// ddynerman: SD's clip sector code
void GetClipSectorsStaticContents( void );
// RAVEN END
};
ID_INLINE bool idClip::TracePoint( trace_t &results, const idVec3 &start, const idVec3 &end, int contentMask, const idEntity *passEntity ) {
Translation( results, start, end, NULL, mat3_identity, contentMask, passEntity );
return ( results.fraction < 1.0f );
}
ID_INLINE bool idClip::TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, int contentMask, const idEntity *passEntity ) {
temporaryClipModel.LoadModel( idTraceModel( bounds ), NULL, true );
Translation( results, start, end, &temporaryClipModel, mat3_identity, contentMask, passEntity );
return ( results.fraction < 1.0f );
}
ID_INLINE const idBounds & idClip::GetWorldBounds( void ) const {
return worldBounds;
}
// RAVEN BEGIN
// ddynerman: SD's clip sector code
ID_INLINE void idClip::CoordsForBounds( int* coords, idBounds& bounds ) const {
float fCoords[ 4 ];
fCoords[ 0 ] = ( bounds[ 0 ].x - nodeOffset.x ) * nodeScale.x;
fCoords[ 1 ] = ( bounds[ 0 ].y - nodeOffset.y ) * nodeScale.y;
fCoords[ 2 ] = ( bounds[ 1 ].x - nodeOffset.x ) * nodeScale.x;
fCoords[ 3 ] = ( bounds[ 1 ].y - nodeOffset.y ) * nodeScale.y;
int i;
for( i = 0; i < 4; i++ ) {
coords[ i ] = idMath::FtoiFast( fCoords[ i ] );
if( coords[ i ] < 0 ) {
coords[ i ] = 0;
} else if( coords[ i ] > CLIPSECTOR_WIDTH - 1 ) {
coords[ i ] = CLIPSECTOR_WIDTH - 1;
}
}
coords[ 2 ]++; coords[ 3 ]++;
}
// RAVEN END
#endif /* !__CLIP_H__ */
+66
View File
@@ -0,0 +1,66 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idClass, idForce )
END_CLASS
idList<idForce*> idForce::forceList;
/*
================
idForce::idForce
================
*/
idForce::idForce( void ) {
forceList.Append( this );
}
/*
================
idForce::~idForce
================
*/
idForce::~idForce( void ) {
forceList.Remove( this );
}
/*
================
idForce::DeletePhysics
================
*/
void idForce::DeletePhysics( const idPhysics *phys ) {
int i;
for ( i = 0; i < forceList.Num(); i++ ) {
forceList[i]->RemovePhysics( phys );
}
}
/*
================
idForce::ClearForceList
================
*/
void idForce::ClearForceList( void ) {
forceList.Clear();
}
/*
================
idForce::Evaluate
================
*/
void idForce::Evaluate( int time ) {
}
/*
================
idForce::RemovePhysics
================
*/
void idForce::RemovePhysics( const idPhysics *phys ) {
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef __FORCE_H__
#define __FORCE_H__
/*
===============================================================================
Force base class
A force object applies a force to a physics object.
===============================================================================
*/
class idEntity;
class idPhysics;
class idForce : public idClass {
public:
CLASS_PROTOTYPE( idForce );
idForce( void );
virtual ~idForce( void );
static void DeletePhysics( const idPhysics *phys );
static void ClearForceList( void );
public: // common force interface
// evalulate the force up to the given time
virtual void Evaluate( int time );
// removes any pointers to the physics object
virtual void RemovePhysics( const idPhysics *phys );
private:
static idList<idForce*> forceList;
};
#endif /* !__FORCE_H__ */
+109
View File
@@ -0,0 +1,109 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idForce, idForce_Constant )
END_CLASS
/*
================
idForce_Constant::idForce_Constant
================
*/
idForce_Constant::idForce_Constant( void ) {
force = vec3_zero;
physics = NULL;
id = 0;
point = vec3_zero;
}
/*
================
idForce_Constant::~idForce_Constant
================
*/
idForce_Constant::~idForce_Constant( void ) {
}
/*
================
idForce_Constant::Save
================
*/
void idForce_Constant::Save( idSaveGame *savefile ) const {
savefile->WriteVec3( force );
// TOSAVE: idPhysics * physics
savefile->WriteInt( id );
savefile->WriteVec3( point );
}
/*
================
idForce_Constant::Restore
================
*/
void idForce_Constant::Restore( idRestoreGame *savefile ) {
// Owner needs to call SetPhysics!!
savefile->ReadVec3( force );
savefile->ReadInt( id );
savefile->ReadVec3( point );
}
/*
================
idForce_Constant::SetPosition
================
*/
void idForce_Constant::SetPosition( idPhysics *physics, int id, const idVec3 &point ) {
this->physics = physics;
this->id = id;
this->point = point;
}
/*
================
idForce_Constant::SetForce
================
*/
void idForce_Constant::SetForce( const idVec3 &force ) {
this->force = force;
}
/*
================
idForce_Constant::SetPhysics
================
*/
void idForce_Constant::SetPhysics( idPhysics *physics ) {
this->physics = physics;
}
/*
================
idForce_Constant::Evaluate
================
*/
void idForce_Constant::Evaluate( int time ) {
idVec3 p;
if ( !physics ) {
return;
}
p = physics->GetOrigin( id ) + point * physics->GetAxis( id );
physics->AddForce( id, p, force );
}
/*
================
idForce_Constant::RemovePhysics
================
*/
void idForce_Constant::RemovePhysics( const idPhysics *phys ) {
if ( physics == phys ) {
physics = NULL;
}
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef __FORCE_CONSTANT_H__
#define __FORCE_CONSTANT_H__
/*
===============================================================================
Constant force
===============================================================================
*/
class idForce_Constant : public idForce {
public:
CLASS_PROTOTYPE( idForce_Constant );
idForce_Constant( void );
virtual ~idForce_Constant( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// constant force
void SetForce( const idVec3 &force );
// set force position
void SetPosition( idPhysics *physics, int id, const idVec3 &point );
void SetPhysics( idPhysics *physics );
public: // common force interface
virtual void Evaluate( int time );
virtual void RemovePhysics( const idPhysics *phys );
private:
// force properties
idVec3 force;
idPhysics * physics;
int id;
idVec3 point;
};
#endif /* !__FORCE_CONSTANT_H__ */
+131
View File
@@ -0,0 +1,131 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idForce, idForce_Drag )
END_CLASS
/*
================
idForce_Drag::idForce_Drag
================
*/
idForce_Drag::idForce_Drag( void ) {
damping = 0.5f;
dragPosition = vec3_zero;
physics = NULL;
id = 0;
p = vec3_zero;
dragPosition = vec3_zero;
}
/*
================
idForce_Drag::~idForce_Drag
================
*/
idForce_Drag::~idForce_Drag( void ) {
}
/*
================
idForce_Drag::Init
================
*/
void idForce_Drag::Init( float damping ) {
if ( damping >= 0.0f && damping < 1.0f ) {
this->damping = damping;
}
}
/*
================
idForce_Drag::SetPhysics
================
*/
void idForce_Drag::SetPhysics( idPhysics *phys, int id, const idVec3 &p ) {
this->physics = phys;
this->id = id;
this->p = p;
}
/*
================
idForce_Drag::SetDragPosition
================
*/
void idForce_Drag::SetDragPosition( const idVec3 &pos ) {
this->dragPosition = pos;
}
/*
================
idForce_Drag::GetDragPosition
================
*/
const idVec3 &idForce_Drag::GetDragPosition( void ) const {
return this->dragPosition;
}
/*
================
idForce_Drag::GetDraggedPosition
================
*/
const idVec3 idForce_Drag::GetDraggedPosition( void ) const {
return ( physics->GetOrigin( id ) + p * physics->GetAxis( id ) );
}
/*
================
idForce_Drag::Evaluate
================
*/
void idForce_Drag::Evaluate( int time ) {
float l1, l2, mass;
idVec3 dragOrigin, dir1, dir2, velocity, centerOfMass;
idMat3 inertiaTensor;
idRotation rotation;
idClipModel *clipModel;
if ( !physics ) {
return;
}
clipModel = physics->GetClipModel( id );
if ( clipModel != NULL && clipModel->IsTraceModel() ) {
clipModel->GetMassProperties( 1.0f, mass, centerOfMass, inertiaTensor );
} else {
centerOfMass.Zero();
}
centerOfMass = physics->GetOrigin( id ) + centerOfMass * physics->GetAxis( id );
dragOrigin = physics->GetOrigin( id ) + p * physics->GetAxis( id );
dir1 = dragPosition - centerOfMass;
dir2 = dragOrigin - centerOfMass;
l1 = dir1.Normalize();
l2 = dir2.Normalize();
rotation.Set( centerOfMass, dir2.Cross( dir1 ), RAD2DEG( idMath::ACos( dir1 * dir2 ) ) );
physics->SetAngularVelocity( rotation.ToAngularVelocity() / MS2SEC( gameLocal.GetMSec() ), id );
// RAVEN BEGIN
// bdube: use GetMSec access rather than USERCMD_TIME
velocity = physics->GetLinearVelocity( id ) * damping + dir1 * ( ( l1 - l2 ) * ( 1.0f - damping ) / MS2SEC( gameLocal.GetMSec ( ) ) );
// RAVEN END
physics->SetLinearVelocity( velocity, id );
}
/*
================
idForce_Drag::RemovePhysics
================
*/
void idForce_Drag::RemovePhysics( const idPhysics *phys ) {
if ( physics == phys ) {
physics = NULL;
}
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef __FORCE_DRAG_H__
#define __FORCE_DRAG_H__
/*
===============================================================================
Drag force
===============================================================================
*/
class idForce_Drag : public idForce {
public:
CLASS_PROTOTYPE( idForce_Drag );
idForce_Drag( void );
virtual ~idForce_Drag( void );
// initialize the drag force
void Init( float damping );
// set physics object being dragged
void SetPhysics( idPhysics *physics, int id, const idVec3 &p );
// set position to drag towards
void SetDragPosition( const idVec3 &pos );
// get the position dragged towards
const idVec3 & GetDragPosition( void ) const;
// get the position on the dragged physics object
const idVec3 GetDraggedPosition( void ) const;
public: // common force interface
virtual void Evaluate( int time );
virtual void RemovePhysics( const idPhysics *phys );
private:
// properties
float damping;
// positioning
idPhysics * physics; // physics object
int id; // clip model id of physics object
idVec3 p; // position on clip model
idVec3 dragPosition; // drag towards this position
};
#endif /* !__FORCE_DRAG_H__ */
+272
View File
@@ -0,0 +1,272 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idForce, idForce_Field )
END_CLASS
/*
================
idForce_Field::idForce_Field
================
*/
idForce_Field::idForce_Field( void ) {
type = FORCEFIELD_UNIFORM;
applyType = FORCEFIELD_APPLY_FORCE;
magnitude = 0.0f;
dir.Set( 0, 0, 1 );
randomTorque = 0.0f;
playerOnly = false;
monsterOnly = false;
clipModel = NULL;
// RAVEN BEGIN
// bdube: added last apply time
lastApplyTime = -1;
owner = NULL;
// RAVEN END
}
/*
================
idForce_Field::~idForce_Field
================
*/
idForce_Field::~idForce_Field( void ) {
if ( this->clipModel ) {
delete this->clipModel;
}
}
/*
================
idForce_Field::Save
================
*/
void idForce_Field::Save( idSaveGame *savefile ) const {
savefile->WriteInt( type );
savefile->WriteInt( applyType);
savefile->WriteFloat( magnitude );
savefile->WriteVec3( dir );
savefile->WriteFloat( randomTorque );
savefile->WriteBool( playerOnly );
savefile->WriteBool( monsterOnly );
savefile->WriteClipModel( clipModel );
savefile->WriteInt ( lastApplyTime ); // cnicholson: Added unsaved var
// TOSAVE: idEntity* owner;
}
/*
================
idForce_Field::Restore
================
*/
void idForce_Field::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( (int &)type );
savefile->ReadInt( (int &)applyType);
savefile->ReadFloat( magnitude );
savefile->ReadVec3( dir );
savefile->ReadFloat( randomTorque );
savefile->ReadBool( playerOnly );
savefile->ReadBool( monsterOnly );
savefile->ReadClipModel( clipModel );
savefile->ReadInt ( lastApplyTime ); // cnicholson: Added unrestored var
}
/*
================
idForce_Field::SetClipModel
================
*/
void idForce_Field::SetClipModel( idClipModel *clipModel ) {
if ( this->clipModel && clipModel != this->clipModel ) {
delete this->clipModel;
}
this->clipModel = clipModel;
}
/*
================
idForce_Field::Uniform
================
*/
void idForce_Field::Uniform( const idVec3 &force ) {
dir = force;
magnitude = dir.Normalize();
type = FORCEFIELD_UNIFORM;
}
/*
================
idForce_Field::Explosion
================
*/
void idForce_Field::Explosion( float force ) {
magnitude = force;
type = FORCEFIELD_EXPLOSION;
}
/*
================
idForce_Field::Implosion
================
*/
void idForce_Field::Implosion( float force ) {
magnitude = force;
type = FORCEFIELD_IMPLOSION;
}
/*
================
idForce_Field::RandomTorque
================
*/
void idForce_Field::RandomTorque( float force ) {
randomTorque = force;
}
/*
================
idForce_Field::Evaluate
================
*/
void idForce_Field::Evaluate( int time ) {
int numClipModels, i;
idBounds bounds;
idVec3 force, torque, angularVelocity;
idClipModel *cm, *clipModelList[ MAX_GENTITIES ];
assert( clipModel );
bounds.FromTransformedBounds( clipModel->GetBounds(), clipModel->GetOrigin(), clipModel->GetAxis() );
// RAVEN BEGIN
// ddynerman: multiple clip worlds
numClipModels = gameLocal.ClipModelsTouchingBounds( owner, bounds, -1, clipModelList, MAX_GENTITIES );
// RAVEN END
for ( i = 0; i < numClipModels; i++ ) {
cm = clipModelList[ i ];
if ( !cm->IsTraceModel() ) {
continue;
}
idEntity *entity = cm->GetEntity();
if ( !entity ) {
continue;
}
idPhysics *physics = entity->GetPhysics();
if ( playerOnly ) {
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( !physics->IsType( idPhysics_Player::GetClassType() ) ) {
// RAVEN END
continue;
}
} else if ( monsterOnly ) {
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( !physics->IsType( idPhysics_Monster::GetClassType() ) ) {
continue;
}
}
// nrausch: It was undesireable to have gibs and discarded weapons bouncing on jump pads
if ( gameLocal.isMultiplayer ) {
if ( entity->IsType( idItem::GetClassType() ) ) {
continue;
}
if ( entity->IsType( rvClientPhysics::GetClassType() ) ) {
continue;
}
if ( entity->IsType( idPlayer::GetClassType() ) ) {
if ( ((idPlayer*)entity)->health <= 0 ) {
continue;
}
}
}
// ddynerman: multiple clip worlds
if ( !gameLocal.ContentsModel( owner, cm->GetOrigin(), cm, cm->GetAxis(), -1,
clipModel->GetCollisionModel(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) {
// RAVEN END
continue;
}
switch( type ) {
case FORCEFIELD_UNIFORM: {
force = dir;
break;
}
case FORCEFIELD_EXPLOSION: {
force = cm->GetOrigin() - clipModel->GetOrigin();
force.Normalize();
break;
}
case FORCEFIELD_IMPLOSION: {
force = clipModel->GetOrigin() - cm->GetOrigin();
force.Normalize();
break;
}
default: {
gameLocal.Error( "idForce_Field: invalid type" );
break;
}
}
if ( randomTorque != 0.0f ) {
torque[0] = gameLocal.random.CRandomFloat();
torque[1] = gameLocal.random.CRandomFloat();
torque[2] = gameLocal.random.CRandomFloat();
if ( torque.Normalize() == 0.0f ) {
torque[2] = 1.0f;
}
}
switch( applyType ) {
case FORCEFIELD_APPLY_FORCE: {
if ( randomTorque != 0.0f ) {
entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
}
else {
entity->AddForce( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
}
break;
}
case FORCEFIELD_APPLY_VELOCITY: {
physics->SetLinearVelocity( force * magnitude, cm->GetId() );
if ( randomTorque != 0.0f ) {
angularVelocity = physics->GetAngularVelocity( cm->GetId() );
physics->SetAngularVelocity( 0.5f * (angularVelocity + torque * randomTorque), cm->GetId() );
}
break;
}
case FORCEFIELD_APPLY_IMPULSE: {
if ( randomTorque != 0.0f ) {
entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin() + torque.Cross( dir ) * randomTorque, dir * magnitude );
}
else {
entity->ApplyImpulse( gameLocal.world, cm->GetId(), cm->GetOrigin(), force * magnitude );
}
break;
}
default: {
gameLocal.Error( "idForce_Field: invalid apply type" );
break;
}
}
// RAVEN BEGIN
// bdube: added last apply time
lastApplyTime = time;
// RAVEN END
}
}
+92
View File
@@ -0,0 +1,92 @@
#ifndef __FORCE_FIELD_H__
#define __FORCE_FIELD_H__
/*
===============================================================================
Force field
===============================================================================
*/
enum forceFieldType {
FORCEFIELD_UNIFORM,
FORCEFIELD_EXPLOSION,
FORCEFIELD_IMPLOSION
};
enum forceFieldApplyType {
FORCEFIELD_APPLY_FORCE,
FORCEFIELD_APPLY_VELOCITY,
FORCEFIELD_APPLY_IMPULSE
};
class idForce_Field : public idForce {
public:
CLASS_PROTOTYPE( idForce_Field );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
idForce_Field( void );
virtual ~idForce_Field( void );
// uniform constant force
void Uniform( const idVec3 &force );
// explosion from clip model origin
void Explosion( float force );
// implosion towards clip model origin
void Implosion( float force );
// add random torque
void RandomTorque( float force );
// should the force field apply a force, velocity or impulse
void SetApplyType( const forceFieldApplyType type ) { applyType = type; }
// make the force field only push players
void SetPlayerOnly( bool set ) { playerOnly = set; }
// make the force field only push monsters
void SetMonsterOnly( bool set ) { monsterOnly = set; }
// clip model describing the extents of the force field
void SetClipModel( idClipModel *clipModel );
// RAVEN BEGIN
// ddynerman: owner information
void SetOwner( idEntity* ent );
// bdube: added last apply time
int GetLastApplyTime( void ) const;
// RAVEN END
public: // common force interface
virtual void Evaluate( int time );
private:
// force properties
forceFieldType type;
forceFieldApplyType applyType;
float magnitude;
idVec3 dir;
float randomTorque;
bool playerOnly;
bool monsterOnly;
idClipModel * clipModel;
// RAVEN BEGIN
// bdube: added last apply time
int lastApplyTime;
idEntity* owner;
// RAVEN END
};
// RAVEN BEGIN
// bdube: added last apply time
ID_INLINE int idForce_Field::GetLastApplyTime ( void ) const {
return lastApplyTime;
}
// ddynerman: owner information
ID_INLINE void idForce_Field::SetOwner( idEntity* ent ) {
owner = ent;
}
// RAVEN END
#endif /* !__FORCE_FIELD_H__ */
+163
View File
@@ -0,0 +1,163 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idForce, idForce_Spring )
END_CLASS
/*
================
idForce_Spring::idForce_Spring
================
*/
idForce_Spring::idForce_Spring( void ) {
Kstretch = 100.0f;
Kcompress = 100.0f;
damping = 0.0f;
restLength = 0.0f;
physics1 = NULL;
id1 = 0;
p1 = vec3_zero;
physics2 = NULL;
id2 = 0;
p2 = vec3_zero;
}
/*
================
idForce_Spring::~idForce_Spring
================
*/
idForce_Spring::~idForce_Spring( void ) {
}
/*
================
idForce_Spring::InitSpring
================
*/
void idForce_Spring::InitSpring( float Kstretch, float Kcompress, float damping, float restLength ) {
this->Kstretch = Kstretch;
this->Kcompress = Kcompress;
this->damping = damping;
this->restLength = restLength;
}
/*
================
idForce_Spring::SetPosition
================
*/
void idForce_Spring::SetPosition( idPhysics *physics1, int id1, const idVec3 &p1, idPhysics *physics2, int id2, const idVec3 &p2 ) {
this->physics1 = physics1;
this->id1 = id1;
this->p1 = p1;
this->physics2 = physics2;
this->id2 = id2;
this->p2 = p2;
}
/*
================
idForce_Spring::Evaluate
================
*/
void idForce_Spring::Evaluate( int time ) {
float length;
idMat3 axis;
idVec3 pos1, pos2, velocity1, velocity2, force, dampingForce;
impactInfo_t info;
pos1 = p1;
pos2 = p2;
velocity1 = velocity2 = vec3_origin;
if ( physics1 ) {
axis = physics1->GetAxis( id1 );
pos1 = physics1->GetOrigin( id1 );
pos1 += p1 * axis;
if ( damping > 0.0f ) {
physics1->GetImpactInfo( id1, pos1, &info );
velocity1 = info.velocity;
}
}
if ( physics2 ) {
axis = physics2->GetAxis( id2 );
pos2 = physics2->GetOrigin( id2 );
pos2 += p2 * axis;
if ( damping > 0.0f ) {
physics2->GetImpactInfo( id2, pos2, &info );
velocity2 = info.velocity;
}
}
force = pos2 - pos1;
dampingForce = ( damping * ( ((velocity2 - velocity1) * force) / (force * force) ) ) * force;
length = force.Normalize();
// if the spring is stretched
if ( length > restLength ) {
if ( Kstretch > 0.0f ) {
force = ( Square( length - restLength ) * Kstretch ) * force - dampingForce;
if ( physics1 ) {
physics1->AddForce( id1, pos1, force );
}
if ( physics2 ) {
physics2->AddForce( id2, pos2, -force );
}
}
}
else {
if ( Kcompress > 0.0f ) {
force = ( Square( length - restLength ) * Kcompress ) * force - dampingForce;
if ( physics1 ) {
physics1->AddForce( id1, pos1, -force );
}
if ( physics2 ) {
physics2->AddForce( id2, pos2, force );
}
}
}
}
/*
================
idForce_Spring::RemovePhysics
================
*/
void idForce_Spring::RemovePhysics( const idPhysics *phys ) {
if ( physics1 == phys ) {
physics1 = NULL;
}
if ( physics2 == phys ) {
physics2 = NULL;
}
}
/*
================
idForce_Spring::Save
================
*/
void idForce_Spring::Save( idSaveGame *savefile ) const {
savefile->WriteFloat ( Kstretch );
savefile->WriteFloat ( Kcompress );
savefile->WriteFloat ( damping );
savefile->WriteFloat ( restLength );
}
/*
================
idForce_Spring::Restore
================
*/
void idForce_Spring::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat ( Kstretch );
savefile->ReadFloat ( Kcompress );
savefile->ReadFloat ( damping );
savefile->ReadFloat ( restLength );
}
+51
View File
@@ -0,0 +1,51 @@
#ifndef __FORCE_SPRING_H__
#define __FORCE_SPRING_H__
/*
===============================================================================
Spring force
===============================================================================
*/
class idForce_Spring : public idForce {
public:
CLASS_PROTOTYPE( idForce_Spring );
idForce_Spring( void );
virtual ~idForce_Spring( void );
// initialize the spring
void InitSpring( float Kstretch, float Kcompress, float damping, float restLength );
// set the entities and positions on these entities the spring is attached to
void SetPosition( idPhysics *physics1, int id1, const idVec3 &p1,
idPhysics *physics2, int id2, const idVec3 &p2 );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public: // common force interface
virtual void Evaluate( int time );
virtual void RemovePhysics( const idPhysics *phys );
private:
// spring properties
float Kstretch;
float Kcompress;
float damping;
float restLength;
// positioning
idPhysics * physics1; // first physics object
int id1; // clip model id of first physics object
idVec3 p1; // position on clip model
idPhysics * physics2; // second physics object
int id2; // clip model id of second physics object
idVec3 p2; // position on clip model
};
#endif /* !__FORCE_SPRING_H__ */
+56
View File
@@ -0,0 +1,56 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
ABSTRACT_DECLARATION( idClass, idPhysics )
END_CLASS
/*
================
idPhysics::~idPhysics
================
*/
idPhysics::~idPhysics( void ) {
}
/*
================
idPhysics::Save
================
*/
void idPhysics::Save( idSaveGame *savefile ) const {
}
/*
================
idPhysics::Restore
================
*/
void idPhysics::Restore( idRestoreGame *savefile ) {
}
/*
================
idPhysics::SetClipBox
================
*/
void idPhysics::SetClipBox( const idBounds &bounds, float density ) {
SetClipModel( new idClipModel( idTraceModel( bounds ) ), density );
}
/*
================
idPhysics::SnapTimeToPhysicsFrame
================
*/
int idPhysics::SnapTimeToPhysicsFrame( int t ) {
int s;
// RAVEN BEGIN
// bdube: use GetMSec access rather than USERCMD_TIME
s = t + gameLocal.GetMSec() - 1;
return ( s - s % gameLocal.GetMSec() );
// RAVEN END
}
+179
View File
@@ -0,0 +1,179 @@
#ifndef __PHYSICS_H__
#define __PHYSICS_H__
/*
===============================================================================
Physics abstract class
A physics object is a tool to manipulate the position and orientation of
an entity. The physics object is a container for idClipModels used for
collision detection. The physics deals with moving these collision models
through the world according to the laws of physics or other rules.
The mass of a clip model is the volume of the clip model times the density.
An arbitrary mass can however be set for specific clip models or the
whole physics object. The contents of a clip model is a set of bit flags
that define the contents. The clip mask defines the contents a clip model
collides with.
The linear velocity of a physics object is a vector that defines the
translation of the center of mass in units per second. The angular velocity
of a physics object is a vector that passes through the center of mass. The
direction of this vector defines the axis of rotation and the magnitude
defines the rate of rotation about the axis in radians per second.
The gravity is the change in velocity per second due to gravitational force.
Entities update their visual position and orientation from the physics
using GetOrigin() and GetAxis(). Direct origin and axis changes of
entities should go through the physics. In other words the physics origin
and axis are updated first and the entity updates it's visual position
from the physics.
===============================================================================
*/
#define CONTACT_EPSILON 0.25f // maximum contact seperation distance
class idEntity;
typedef struct impactInfo_s {
float invMass; // inverse mass
idMat3 invInertiaTensor; // inverse inertia tensor
idVec3 position; // impact position relative to center of mass
idVec3 velocity; // velocity at the impact position
} impactInfo_t;
class idPhysics : public idClass {
public:
ABSTRACT_PROTOTYPE( idPhysics );
virtual ~idPhysics( void );
static int SnapTimeToPhysicsFrame( int t );
// Must not be virtual
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public: // common physics interface
// set pointer to entity using physics
virtual void SetSelf( idEntity *e ) = 0;
// clip models
virtual void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true ) = 0;
virtual void SetClipBox( const idBounds &bounds, float density );
virtual idClipModel * GetClipModel( int id = 0 ) const = 0;
virtual int GetNumClipModels( void ) const = 0;
// get/set the mass of a specific clip model or the whole physics object
virtual void SetMass( float mass, int id = -1 ) = 0;
virtual float GetMass( int id = -1 ) const = 0;
// RAVEN BEGIN
// bdube: added center mass
// get the center of mass origin
virtual idVec3 GetCenterMass ( int id = -1 ) const = 0;
// RAVEN END
// get/set the contents of a specific clip model or the whole physics object
virtual void SetContents( int contents, int id = -1 ) = 0;
virtual int GetContents( int id = -1 ) const = 0;
// get/set the contents a specific clip model or the whole physics object collides with
virtual void SetClipMask( int mask, int id = -1 ) = 0;
virtual int GetClipMask( int id = -1 ) const = 0;
// get the bounds of a specific clip model or the whole physics object
virtual const idBounds & GetBounds( int id = -1 ) const = 0;
virtual const idBounds & GetAbsBounds( int id = -1 ) const = 0;
// evaluate the physics with the given time step, returns true if the object moved
virtual bool Evaluate( int timeStepMSec, int endTimeMSec ) = 0;
// update the time without moving
virtual void UpdateTime( int endTimeMSec ) = 0;
// get the last physics update time
virtual int GetTime( void ) const = 0;
// collision interaction between different physics objects
virtual void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const = 0;
virtual void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) = 0;
virtual void AddForce( const int id, const idVec3 &point, const idVec3 &force ) = 0;
virtual void Activate( void ) = 0;
virtual void PutToRest( void ) = 0;
virtual bool IsAtRest( void ) const = 0;
virtual int GetRestStartTime( void ) const = 0;
virtual bool IsPushable( void ) const = 0;
// RAVEN BEGIN
// bdube: water interraction
virtual bool IsInWater ( void ) const = 0;
// RAVEN END
// save and restore the physics state
virtual void SaveState( void ) = 0;
virtual void RestoreState( void ) = 0;
// set the position and orientation in master space or world space if no master set
virtual void SetOrigin( const idVec3 &newOrigin, int id = -1 ) = 0;
virtual void SetAxis( const idMat3 &newAxis, int id = -1 ) = 0;
// translate or rotate the physics object in world space
virtual void Translate( const idVec3 &translation, int id = -1 ) = 0;
virtual void Rotate( const idRotation &rotation, int id = -1 ) = 0;
// get the position and orientation in world space
virtual const idVec3 & GetOrigin( int id = 0 ) const = 0;
virtual const idMat3 & GetAxis( int id = 0 ) const = 0;
// set linear and angular velocity
virtual void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 ) = 0;
virtual void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 ) = 0;
// get linear and angular velocity
virtual const idVec3 & GetLinearVelocity( int id = 0 ) const = 0;
virtual const idVec3 & GetAngularVelocity( int id = 0 ) const = 0;
// gravity
virtual void SetGravity( const idVec3 &newGravity ) = 0;
virtual const idVec3 & GetGravity( void ) const = 0;
virtual const idVec3 & GetGravityNormal( void ) const = 0;
// get first collision when translating or rotating this physics object
virtual void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const = 0;
virtual void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const = 0;
virtual int ClipContents( const idClipModel *model ) const = 0;
// disable/enable the clip models contained by this physics object
virtual void DisableClip( void ) = 0;
virtual void EnableClip( void ) = 0;
// link/unlink the clip models contained by this physics object
virtual void UnlinkClip( void ) = 0;
virtual void LinkClip( void ) = 0;
// contacts
virtual bool EvaluateContacts( void ) = 0;
virtual int GetNumContacts( void ) const = 0;
virtual const contactInfo_t &GetContact( int num ) const = 0;
virtual void ClearContacts( void ) = 0;
virtual void AddContactEntity( idEntity *e ) = 0;
virtual void RemoveContactEntity( idEntity *e ) = 0;
// ground contacts
virtual bool HasGroundContacts( void ) const = 0;
virtual bool IsGroundEntity( int entityNum ) const = 0;
virtual bool IsGroundClipModel( int entityNum, int id ) const = 0;
// RAVEN BEGIN
// abahr
virtual const idVec3 GetContactNormal() const { return vec3_zero; }
virtual const idVec3 GetGroundContactNormal() const { return vec3_zero; }
virtual idEntity* GetSelf() const = 0;
// RAVEN END
// set the master entity for objects bound to a master
virtual void SetMaster( idEntity *master, const bool orientated = true ) = 0;
// set pushed state
virtual void SetPushed( int deltaTime ) = 0;
virtual const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const = 0;
virtual const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const = 0;
// get blocking info, returns NULL if the object is not blocked
virtual const trace_t * GetBlockingInfo( void ) const = 0;
virtual idEntity * GetBlockingEntity( void ) const = 0;
// movement end times in msec for reached events at the end of predefined motion
virtual int GetLinearEndTime( void ) const = 0;
virtual int GetAngularEndTime( void ) const = 0;
// networking
virtual void WriteToSnapshot( idBitMsgDelta &msg ) const = 0;
virtual void ReadFromSnapshot( const idBitMsgDelta &msg ) = 0;
// RAVEN BEGIN
// kfuller: we want to debug draw the bbox
virtual void DebugDraw() {}
// RAVEN END
};
#endif /* !__PHYSICS_H__ */
File diff suppressed because it is too large Load Diff
+988
View File
@@ -0,0 +1,988 @@
#ifndef __PHYSICS_AF_H__
#define __PHYSICS_AF_H__
/*
===================================================================================
Articulated Figure physics
Employs a constraint force based dynamic simulation using a lagrangian
multiplier method to solve for the constraint forces.
===================================================================================
*/
class idAFConstraint;
class idAFConstraint_Fixed;
class idAFConstraint_BallAndSocketJoint;
class idAFConstraint_BallAndSocketJointFriction;
class idAFConstraint_UniversalJoint;
class idAFConstraint_UniversalJointFriction;
class idAFConstraint_CylindricalJoint;
class idAFConstraint_Hinge;
class idAFConstraint_HingeFriction;
class idAFConstraint_HingeSteering;
class idAFConstraint_Slider;
class idAFConstraint_Line;
class idAFConstraint_Plane;
class idAFConstraint_Spring;
class idAFConstraint_Contact;
class idAFConstraint_ContactFriction;
class idAFConstraint_ConeLimit;
class idAFConstraint_PyramidLimit;
class idAFBody;
class idAFTree;
class idPhysics_AF;
typedef enum {
CONSTRAINT_INVALID,
CONSTRAINT_FIXED,
CONSTRAINT_BALLANDSOCKETJOINT,
CONSTRAINT_UNIVERSALJOINT,
CONSTRAINT_HINGE,
CONSTRAINT_HINGESTEERING,
CONSTRAINT_SLIDER,
CONSTRAINT_CYLINDRICALJOINT,
CONSTRAINT_LINE,
CONSTRAINT_PLANE,
CONSTRAINT_SPRING,
CONSTRAINT_CONTACT,
CONSTRAINT_FRICTION,
CONSTRAINT_CONELIMIT,
CONSTRAINT_PYRAMIDLIMIT
} constraintType_t;
//===============================================================
//
// idAFConstraint
//
//===============================================================
// base class for all constraints
class idAFConstraint {
friend class idPhysics_AF;
friend class idAFTree;
public:
idAFConstraint( void );
virtual ~idAFConstraint( void );
constraintType_t GetType( void ) const { return type; }
const idStr & GetName( void ) const { return name; }
idAFBody * GetBody1( void ) const { return body1; }
idAFBody * GetBody2( void ) const { return body2; }
void SetPhysics( idPhysics_AF *p ) { physics = p; }
const idVecX & GetMultiplier( void );
virtual void SetBody1( idAFBody *body );
virtual void SetBody2( idAFBody *body );
virtual void DebugDraw( void );
virtual void GetForce( idAFBody *body, idVec6 &force );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
constraintType_t type; // constraint type
idStr name; // name of constraint
idAFBody * body1; // first constrained body
idAFBody * body2; // second constrained body, NULL for world
idPhysics_AF * physics; // for adding additional constraints like limits
// simulation variables set by Evaluate
idMatX J1, J2; // matrix with left hand side of constraint equations
idVecX c1, c2; // right hand side of constraint equations
idVecX lo, hi, e; // low and high bounds and lcp epsilon
idAFConstraint * boxConstraint; // constraint the boxIndex refers to
int boxIndex[6]; // indexes for special box constrained variables
// simulation variables used during calculations
idMatX invI; // transformed inertia
idMatX J; // transformed constraint matrix
idVecX s; // temp solution
idVecX lm; // lagrange multipliers
int firstIndex; // index of the first constraint row in the lcp matrix
struct constraintFlags_s {
bool allowPrimary : 1; // true if the constraint can be used as a primary constraint
bool frameConstraint : 1; // true if this constraint is added to the frame constraints
bool noCollision : 1; // true if body1 and body2 never collide with each other
bool isPrimary : 1; // true if this is a primary constraint
bool isZero : 1; // true if 's' is zero during calculations
} fl;
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
void InitSize( int size );
};
// fixed or rigid joint which allows zero degrees of freedom
// constrains body1 to have a fixed position and orientation relative to body2
class idAFConstraint_Fixed : public idAFConstraint {
public:
idAFConstraint_Fixed( const idStr &name, idAFBody *body1, idAFBody *body2 );
void SetRelativeOrigin( const idVec3 &origin ) { this->offset = origin; }
void SetRelativeAxis( const idMat3 &axis ) { this->relAxis = axis; }
virtual void SetBody1( idAFBody *body );
virtual void SetBody2( idAFBody *body );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 offset; // offset of body1 relative to body2 in body2 space
idMat3 relAxis; // rotation of body1 relative to body2
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
void InitOffset( void );
};
// ball and socket or spherical joint which allows 3 degrees of freedom
// constrains body1 relative to body2 with a ball and socket joint
class idAFConstraint_BallAndSocketJoint : public idAFConstraint {
public:
idAFConstraint_BallAndSocketJoint( const idStr &name, idAFBody *body1, idAFBody *body2 );
~idAFConstraint_BallAndSocketJoint( void );
void SetAnchor( const idVec3 &worldPosition );
idVec3 GetAnchor( void ) const;
void SetNoLimit( void );
void SetConeLimit( const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis );
void SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis,
const float angle1, const float angle2, const idVec3 &body1Axis );
void SetLimitEpsilon( const float e );
void SetFriction( const float f ) { friction = f; }
float GetFriction( void ) const;
virtual void DebugDraw( void );
virtual void GetForce( idAFBody *body, idVec6 &force );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 anchor1; // anchor in body1 space
idVec3 anchor2; // anchor in body2 space
float friction; // joint friction
idAFConstraint_ConeLimit *coneLimit; // cone shaped limit
idAFConstraint_PyramidLimit *pyramidLimit; // pyramid shaped limit
idAFConstraint_BallAndSocketJointFriction *fc; // friction constraint
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// ball and socket joint friction
class idAFConstraint_BallAndSocketJointFriction : public idAFConstraint {
public:
idAFConstraint_BallAndSocketJointFriction( void );
void Setup( idAFConstraint_BallAndSocketJoint *cc );
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
idAFConstraint_BallAndSocketJoint *joint;
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// universal, Cardan or Hooke joint which allows 2 degrees of freedom
// like a ball and socket joint but also constrains the rotation about the cardan shafts
class idAFConstraint_UniversalJoint : public idAFConstraint {
public:
idAFConstraint_UniversalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 );
~idAFConstraint_UniversalJoint( void );
void SetAnchor( const idVec3 &worldPosition );
idVec3 GetAnchor( void ) const;
void SetShafts( const idVec3 &cardanShaft1, const idVec3 &cardanShaft2 );
void GetShafts( idVec3 &cardanShaft1, idVec3 &cardanShaft2 ) { cardanShaft1 = shaft1; cardanShaft2 = shaft2; }
void SetNoLimit( void );
void SetConeLimit( const idVec3 &coneAxis, const float coneAngle );
void SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis,
const float angle1, const float angle2 );
void SetLimitEpsilon( const float e );
void SetFriction( const float f ) { friction = f; }
float GetFriction( void ) const;
virtual void DebugDraw( void );
virtual void GetForce( idAFBody *body, idVec6 &force );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 anchor1; // anchor in body1 space
idVec3 anchor2; // anchor in body2 space
idVec3 shaft1; // body1 cardan shaft in body1 space
idVec3 shaft2; // body2 cardan shaft in body2 space
idVec3 axis1; // cardan axis in body1 space
idVec3 axis2; // cardan axis in body2 space
float friction; // joint friction
idAFConstraint_ConeLimit *coneLimit; // cone shaped limit
idAFConstraint_PyramidLimit *pyramidLimit; // pyramid shaped limit
idAFConstraint_UniversalJointFriction *fc; // friction constraint
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// universal joint friction
class idAFConstraint_UniversalJointFriction : public idAFConstraint {
public:
idAFConstraint_UniversalJointFriction( void );
void Setup( idAFConstraint_UniversalJoint *cc );
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
idAFConstraint_UniversalJoint *joint; // universal joint
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// cylindrical joint which allows 2 degrees of freedom
// constrains body1 to lie on a line relative to body2 and allows only translation along and rotation about the line
class idAFConstraint_CylindricalJoint : public idAFConstraint {
public:
idAFConstraint_CylindricalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// hinge, revolute or pin joint which allows 1 degree of freedom
// constrains all motion of body1 relative to body2 except the rotation about the hinge axis
class idAFConstraint_Hinge : public idAFConstraint {
public:
idAFConstraint_Hinge( const idStr &name, idAFBody *body1, idAFBody *body2 );
~idAFConstraint_Hinge( void );
void SetAnchor( const idVec3 &worldPosition );
idVec3 GetAnchor( void ) const;
void SetAxis( const idVec3 &axis );
void GetAxis( idVec3 &a1, idVec3 &a2 ) const { a1 = axis1; a2 = axis2; }
idVec3 GetAxis( void ) const;
void SetNoLimit( void );
void SetLimit( const idVec3 &axis, const float angle, const idVec3 &body1Axis );
void SetLimitEpsilon( const float e );
float GetAngle( void ) const;
void SetSteerAngle( const float degrees );
void SetSteerSpeed( const float speed );
void SetFriction( const float f ) { friction = f; }
float GetFriction( void ) const;
virtual void DebugDraw( void );
virtual void GetForce( idAFBody *body, idVec6 &force );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 anchor1; // anchor in body1 space
idVec3 anchor2; // anchor in body2 space
idVec3 axis1; // axis in body1 space
idVec3 axis2; // axis in body2 space
idMat3 initialAxis; // initial axis of body1 relative to body2
float friction; // hinge friction
idAFConstraint_ConeLimit *coneLimit; // cone limit
idAFConstraint_HingeSteering *steering; // steering
idAFConstraint_HingeFriction *fc; // friction constraint
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// hinge joint friction
class idAFConstraint_HingeFriction : public idAFConstraint {
public:
idAFConstraint_HingeFriction( void );
void Setup( idAFConstraint_Hinge *cc );
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
idAFConstraint_Hinge * hinge; // hinge
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// constrains two bodies attached to each other with a hinge to get a specified relative orientation
class idAFConstraint_HingeSteering : public idAFConstraint {
public:
idAFConstraint_HingeSteering( void );
void Setup( idAFConstraint_Hinge *cc );
void SetSteerAngle( const float degrees ) { steerAngle = degrees; }
void SetSteerSpeed( const float speed ) { steerSpeed = speed; }
void SetEpsilon( const float e ) { epsilon = e; }
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idAFConstraint_Hinge * hinge; // hinge
float steerAngle; // desired steer angle in degrees
float steerSpeed; // steer speed
float epsilon; // lcp epsilon
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// slider, prismatic or translational constraint which allows 1 degree of freedom
// constrains body1 to lie on a line relative to body2, the orientation is also fixed relative to body2
class idAFConstraint_Slider : public idAFConstraint {
public:
idAFConstraint_Slider( const idStr &name, idAFBody *body1, idAFBody *body2 );
void SetAxis( const idVec3 &ax );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 axis; // axis along which body1 slides in body2 space
idVec3 offset; // offset of body1 relative to body2
idMat3 relAxis; // rotation of body1 relative to body2
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// line constraint which allows 4 degrees of freedom
// constrains body1 to lie on a line relative to body2, does not constrain the orientation.
class idAFConstraint_Line : public idAFConstraint {
public:
idAFConstraint_Line( const idStr &name, idAFBody *body1, idAFBody *body2 );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// plane constraint which allows 5 degrees of freedom
// constrains body1 to lie in a plane relative to body2, does not constrain the orientation.
class idAFConstraint_Plane : public idAFConstraint {
public:
idAFConstraint_Plane( const idStr &name, idAFBody *body1, idAFBody *body2 );
void SetPlane( const idVec3 &normal, const idVec3 &anchor );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 anchor1; // anchor in body1 space
idVec3 anchor2; // anchor in body2 space
idVec3 planeNormal; // plane normal in body2 space
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// spring constraint which allows 6 or 5 degrees of freedom based on the spring limits
// constrains body1 relative to body2 with a spring
class idAFConstraint_Spring : public idAFConstraint {
public:
idAFConstraint_Spring( const idStr &name, idAFBody *body1, idAFBody *body2 );
void SetAnchor( const idVec3 &worldAnchor1, const idVec3 &worldAnchor2 );
void SetSpring( const float stretch, const float compress, const float damping, const float restLength );
void SetLimit( const float minLength, const float maxLength );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 anchor1; // anchor in body1 space
idVec3 anchor2; // anchor in body2 space
float kstretch; // spring constant when stretched
float kcompress; // spring constant when compressed
float damping; // spring damping
float restLength; // rest length of spring
float minLength; // minimum spring length
float maxLength; // maximum spring length
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// constrains body1 to either be in contact with or move away from body2
class idAFConstraint_Contact : public idAFConstraint {
public:
idAFConstraint_Contact( void );
~idAFConstraint_Contact( void );
void Setup( idAFBody *b1, idAFBody *b2, contactInfo_t &c );
const contactInfo_t & GetContact( void ) const { return contact; }
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void GetCenter( idVec3 &center );
protected:
contactInfo_t contact; // contact information
idAFConstraint_ContactFriction *fc; // contact friction
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// contact friction
class idAFConstraint_ContactFriction : public idAFConstraint {
public:
idAFConstraint_ContactFriction( void );
void Setup( idAFConstraint_Contact *cc );
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
idAFConstraint_Contact *cc; // contact constraint
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// constrains an axis attached to body1 to be inside a cone relative to body2
class idAFConstraint_ConeLimit : public idAFConstraint {
public:
idAFConstraint_ConeLimit( void );
void Setup( idAFBody *b1, idAFBody *b2, const idVec3 &coneAnchor, const idVec3 &coneAxis,
const float coneAngle, const idVec3 &body1Axis );
void SetAnchor( const idVec3 &coneAnchor );
void SetBody1Axis( const idVec3 &body1Axis );
void SetEpsilon( const float e ) { epsilon = e; }
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 coneAnchor; // top of the cone in body2 space
idVec3 coneAxis; // cone axis in body2 space
idVec3 body1Axis; // axis in body1 space that should stay within the cone
float cosAngle; // cos( coneAngle / 2 )
float sinHalfAngle; // sin( coneAngle / 4 )
float cosHalfAngle; // cos( coneAngle / 4 )
float epsilon; // lcp epsilon
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
// constrains an axis attached to body1 to be inside a pyramid relative to body2
class idAFConstraint_PyramidLimit : public idAFConstraint {
public:
idAFConstraint_PyramidLimit( void );
void Setup( idAFBody *b1, idAFBody *b2, const idVec3 &pyramidAnchor,
const idVec3 &pyramidAxis, const idVec3 &baseAxis,
const float pyramidAngle1, const float pyramidAngle2, const idVec3 &body1Axis );
void SetAnchor( const idVec3 &pyramidAxis );
void SetBody1Axis( const idVec3 &body1Axis );
void SetEpsilon( const float e ) { epsilon = e; }
bool Add( idPhysics_AF *phys, float invTimeStep );
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
virtual void Save( idSaveGame *saveFile ) const;
virtual void Restore( idRestoreGame *saveFile );
protected:
idVec3 pyramidAnchor; // top of the pyramid in body2 space
idMat3 pyramidBasis; // pyramid basis in body2 space with base[2] being the pyramid axis
idVec3 body1Axis; // axis in body1 space that should stay within the cone
float cosAngle[2]; // cos( pyramidAngle / 2 )
float sinHalfAngle[2]; // sin( pyramidAngle / 4 )
float cosHalfAngle[2]; // cos( pyramidAngle / 4 )
float epsilon; // lcp epsilon
protected:
virtual void Evaluate( float invTimeStep );
virtual void ApplyFriction( float invTimeStep );
};
//===============================================================
//
// idAFBody
//
//===============================================================
typedef struct AFBodyPState_s {
idVec3 worldOrigin; // position in world space
idMat3 worldAxis; // axis at worldOrigin
idVec6 spatialVelocity; // linear and rotational velocity of body
idVec6 externalForce; // external force and torque applied to body
} AFBodyPState_t;
class idAFBody {
friend class idPhysics_AF;
friend class idAFTree;
public:
idAFBody( void );
idAFBody( const idStr &name, idClipModel *clipModel, float density );
~idAFBody( void );
void Init( void );
const idStr & GetName( void ) const { return name; }
const idVec3 & GetWorldOrigin( void ) const { return current->worldOrigin; }
const idMat3 & GetWorldAxis( void ) const { return current->worldAxis; }
const idVec3 & GetLinearVelocity( void ) const { return current->spatialVelocity.SubVec3(0); }
const idVec3 & GetAngularVelocity( void ) const { return current->spatialVelocity.SubVec3(1); }
idVec3 GetPointVelocity( const idVec3 &point ) const;
const idVec3 & GetCenterOfMass( void ) const { return centerOfMass; }
void SetClipModel( idClipModel *clipModel );
idClipModel * GetClipModel( void ) const { return clipModel; }
void SetClipMask( const int mask ) { clipMask = mask; fl.clipMaskSet = true; }
int GetClipMask( void ) const { return clipMask; }
void SetSelfCollision( const bool enable ) { fl.selfCollision = enable; }
void SetWorldOrigin( const idVec3 &origin ) { current->worldOrigin = origin; }
void SetWorldAxis( const idMat3 &axis ) { current->worldAxis = axis; }
void SetLinearVelocity( const idVec3 &linear ) const { current->spatialVelocity.SubVec3(0) = linear; }
void SetAngularVelocity( const idVec3 &angular ) const { current->spatialVelocity.SubVec3(1) = angular; }
void SetFriction( float linear, float angular, float contact );
float GetContactFriction( void ) const { return contactFriction; }
void SetBouncyness( float bounce );
float GetBouncyness( void ) const { return bouncyness; }
void SetDensity( float density, const idMat3 &inertiaScale = mat3_identity );
float GetInverseMass( void ) const { return invMass; }
idMat3 GetInverseWorldInertia( void ) const { return current->worldAxis.Transpose() * inverseInertiaTensor * current->worldAxis; }
void SetFrictionDirection( const idVec3 &dir );
bool GetFrictionDirection( idVec3 &dir ) const;
void SetContactMotorDirection( const idVec3 &dir );
bool GetContactMotorDirection( idVec3 &dir ) const;
void SetContactMotorVelocity( float vel ) { contactMotorVelocity = vel; }
float GetContactMotorVelocity( void ) const { return contactMotorVelocity; }
void SetContactMotorForce( float force ) { contactMotorForce = force; }
float GetContactMotorForce( void ) const { return contactMotorForce; }
void AddForce( const idVec3 &point, const idVec3 &force );
void InverseWorldSpatialInertiaMultiply( idVecX &dst, const float *v ) const;
idVec6 & GetResponseForce( int index ) { return reinterpret_cast<idVec6 &>(response[ index * 8 ]); }
void Save( idSaveGame *saveFile );
void Restore( idRestoreGame *saveFile );
private:
// properties
idStr name; // name of body
idAFBody * parent; // parent of this body
idList<idAFBody *> children; // children of this body
idClipModel * clipModel; // model used for collision detection
idAFConstraint * primaryConstraint; // primary constraint (this->constraint->body1 = this)
idList<idAFConstraint *>constraints; // all constraints attached to this body
idAFTree * tree; // tree structure this body is part of
float linearFriction; // translational friction
float angularFriction; // rotational friction
float contactFriction; // friction with contact surfaces
float bouncyness; // bounce
int clipMask; // contents this body collides with
idVec3 frictionDir; // specifies a single direction of friction in body space
idVec3 contactMotorDir; // contact motor direction
float contactMotorVelocity; // contact motor velocity
float contactMotorForce; // maximum force applied to reach the motor velocity
// derived properties
float mass; // mass of body
float invMass; // inverse mass
idVec3 centerOfMass; // center of mass of body
idMat3 inertiaTensor; // inertia tensor
idMat3 inverseInertiaTensor; // inverse inertia tensor
// physics state
AFBodyPState_t state[2];
AFBodyPState_t * current; // current physics state
AFBodyPState_t * next; // next physics state
AFBodyPState_t saved; // saved physics state
idVec3 atRestOrigin; // origin at rest
idMat3 atRestAxis; // axis at rest
// simulation variables used during calculations
idMatX inverseWorldSpatialInertia; // inverse spatial inertia in world space
idMatX I, invI; // transformed inertia
idMatX J; // transformed constraint matrix
idVecX s; // temp solution
idVecX totalForce; // total force acting on body
idVecX auxForce; // force from auxiliary constraints
idVecX acceleration; // acceleration
float * response; // forces on body in response to auxiliary constraint forces
int * responseIndex; // index to response forces
int numResponses; // number of response forces
int maxAuxiliaryIndex; // largest index of an auxiliary constraint constraining this body
int maxSubTreeAuxiliaryIndex; // largest index of an auxiliary constraint constraining this body or one of it's children
struct bodyFlags_s {
bool clipMaskSet : 1; // true if this body has a clip mask set
bool selfCollision : 1; // true if this body can collide with other bodies of this AF
bool spatialInertiaSparse: 1; // true if the spatial inertia matrix is sparse
bool useFrictionDir : 1; // true if a single friction direction should be used
bool useContactMotorDir : 1; // true if a contact motor should be used
bool isZero : 1; // true if 's' is zero during calculations
} fl;
};
//===============================================================
//
// idAFTree
//
//===============================================================
class idAFTree {
friend class idPhysics_AF;
public:
void Factor( void ) const;
void Solve( int auxiliaryIndex = 0 ) const;
void Response( const idAFConstraint *constraint, int row, int auxiliaryIndex ) const;
void CalculateForces( float timeStep ) const;
void SetMaxSubTreeAuxiliaryIndex( void );
void SortBodies( void );
void SortBodies_r( idList<idAFBody*>&sortedList, idAFBody *body );
void DebugDraw( const idVec4 &color ) const;
private:
idList<idAFBody *> sortedBodies;
};
//===============================================================
//
// idPhysics_AF
//
//===============================================================
typedef struct AFPState_s {
int atRest; // >= 0 if articulated figure is at rest
float noMoveTime; // time the articulated figure is hardly moving
float activateTime; // time since last activation
float lastTimeStep; // last time step
idVec6 pushVelocity; // velocity with which the af is pushed
} AFPState_t;
typedef struct AFCollision_s {
trace_t trace;
idAFBody * body;
} AFCollision_t;
class idPhysics_AF : public idPhysics_Base {
public:
CLASS_PROTOTYPE( idPhysics_AF );
idPhysics_AF( void );
~idPhysics_AF( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// initialisation
int AddBody( idAFBody *body ); // returns body id
void AddConstraint( idAFConstraint *constraint );
void AddFrameConstraint( idAFConstraint *constraint );
// force a body to have a certain id
void ForceBodyId( idAFBody *body, int newId );
// get body or constraint id
int GetBodyId( idAFBody *body ) const;
int GetBodyId( const char *bodyName ) const;
int GetConstraintId( idAFConstraint *constraint ) const;
int GetConstraintId( const char *constraintName ) const;
// number of bodies and constraints
int GetNumBodies( void ) const;
int GetNumConstraints( void ) const;
// retrieve body or constraint
idAFBody * GetBody( const char *bodyName ) const;
idAFBody * GetBody( const int id ) const;
idAFBody * GetMasterBody( void ) const { return masterBody; }
idAFConstraint * GetConstraint( const char *constraintName ) const;
idAFConstraint * GetConstraint( const int id ) const;
// delete body or constraint
void DeleteBody( const char *bodyName );
void DeleteBody( const int id );
void DeleteConstraint( const char *constraintName );
void DeleteConstraint( const int id );
// get all the contact constraints acting on the body
int GetBodyContactConstraints( const int id, idAFConstraint_Contact *contacts[], int maxContacts ) const;
// set the default friction for bodies
void SetDefaultFriction( float linear, float angular, float contact );
// suspend settings
void SetSuspendSpeed( const idVec2 &velocity, const idVec2 &acceleration );
// set the time and tolerances used to determine if the simulation can be suspended when the figure hardly moves for a while
void SetSuspendTolerance( const float noMoveTime, const float translationTolerance, const float rotationTolerance );
// set minimum and maximum simulation time in seconds
void SetSuspendTime( const float minTime, const float maxTime );
// set the time scale value
void SetTimeScale( const float ts ) { timeScale = ts; }
// set time scale ramp
void SetTimeScaleRamp( const float start, const float end );
// set the joint friction scale
void SetJointFrictionScale( const float scale ) { jointFrictionScale = scale; }
// set joint friction dent
void SetJointFrictionDent( const float dent, const float start, const float end );
// get the current joint friction scale
float GetJointFrictionScale( void ) const;
// set the contact friction scale
void SetContactFrictionScale( const float scale ) { contactFrictionScale = scale; }
// set contact friction dent
void SetContactFrictionDent( const float dent, const float start, const float end );
// get the current contact friction scale
float GetContactFrictionScale( void ) const;
// enable or disable collision detection
void SetCollision( const bool enable ) { enableCollision = enable; }
// enable or disable self collision
void SetSelfCollision( const bool enable ) { selfCollision = enable; }
// enable or disable coming to a dead stop
void SetComeToRest( bool enable ) { comeToRest = enable; }
// call when structure of articulated figure changes
void SetChanged( void ) { changedAF = true; }
// RAVEN BEGIN
// rjohnson: fast AF eval to skip some things that are not needed for specific circumstances
// enable or disable fast evaluation
void SetFastEval( const bool enable ) { fastEval = enable; }
// RAVEN END
// enable/disable activation by impact
void EnableImpact( void );
void DisableImpact( void );
// lock of unlock the world constraints
void LockWorldConstraints( const bool lock ) { worldConstraintsLocked = lock; }
// set force pushable
void SetForcePushable( const bool enable ) { forcePushable = enable; }
// update the clip model positions
void UpdateClipModels( void );
public: // common physics interface
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
//MCG: added SetImpulseThreshold
void SetImpulseThreshold( float newIT ) { impulseThreshold = newIT; };
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void AddForce( const int id, const idVec3 &point, const idVec3 &force );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
void Activate( void );
void PutToRest( void );
bool IsPushable( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated = true );
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
private:
// articulated figure
idList<idAFTree *> trees; // tree structures
idList<idAFBody *> bodies; // all bodies
idList<idAFConstraint *>constraints; // all frame independent constraints
idList<idAFConstraint *>primaryConstraints; // list with primary constraints
idList<idAFConstraint *>auxiliaryConstraints; // list with auxiliary constraints
idList<idAFConstraint *>frameConstraints; // constraints that only live one frame
idList<idAFConstraint_Contact *>contactConstraints; // contact constraints
idList<int> contactBodies; // body id for each contact
idList<AFCollision_t> collisions; // collisions
bool changedAF; // true when the articulated figure just changed
// properties
float linearFriction; // default translational friction
float angularFriction; // default rotational friction
float contactFriction; // default friction with contact surfaces
float bouncyness; // default bouncyness
float totalMass; // total mass of articulated figure
float forceTotalMass; // force this total mass
idVec2 suspendVelocity; // simulation may not be suspended if a body has more velocity
idVec2 suspendAcceleration; // simulation may not be suspended if a body has more acceleration
float noMoveTime; // suspend simulation if hardly any movement for this many seconds
float noMoveTranslation; // maximum translation considered no movement
float noMoveRotation; // maximum rotation considered no movement
float minMoveTime; // if > 0 the simulation is never suspended before running this many seconds
float maxMoveTime; // if > 0 the simulation is always suspeded after running this many seconds
float impulseThreshold; // threshold below which impulses are ignored to avoid continuous activation
float timeScale; // the time is scaled with this value for slow motion effects
float timeScaleRampStart; // start of time scale change
float timeScaleRampEnd; // end of time scale change
float jointFrictionScale; // joint friction scale
float jointFrictionDent; // joint friction dives from 1 to this value and goes up again
float jointFrictionDentStart; // start time of joint friction dent
float jointFrictionDentEnd; // end time of joint friction dent
float jointFrictionDentScale; // dent scale
float contactFrictionScale; // contact friction scale
float contactFrictionDent; // contact friction dives from 1 to this value and goes up again
float contactFrictionDentStart; // start time of contact friction dent
float contactFrictionDentEnd; // end time of contact friction dent
float contactFrictionDentScale; // dent scale
bool enableCollision; // if true collision detection is enabled
bool selfCollision; // if true the self collision is allowed
bool comeToRest; // if true the figure can come to rest
bool linearTime; // if true use the linear time algorithm
bool noImpact; // if true do not activate when another object collides
bool worldConstraintsLocked; // if true world constraints cannot be moved
bool forcePushable; // if true can be pushed even when bound to a master
// RAVEN BEGIN
// rjohnson: fast AF eval to skip some things that are not needed for specific circumstances
bool fastEval; // if true the fast eval is on
// RAVEN END
// physics state
AFPState_t current;
AFPState_t saved;
idAFBody * masterBody; // master body
idLCP * lcp; // linear complementarity problem solver
private:
void BuildTrees( void );
bool IsClosedLoop( const idAFBody *body1, const idAFBody *body2 ) const;
void PrimaryFactor( void );
void EvaluateBodies( float timeStep );
void EvaluateConstraints( float timeStep );
void AddFrameConstraints( void );
void RemoveFrameConstraints( void );
void ApplyFriction( float timeStep, float endTimeMSec );
void PrimaryForces( float timeStep );
void AuxiliaryForces( float timeStep );
void VerifyContactConstraints( void );
void SetupContactConstraints( void );
void ApplyContactForces( void );
void Evolve( float timeStep );
idEntity * SetupCollisionForBody( idAFBody *body ) const;
bool CollisionImpulse( float timeStep, idAFBody *body, trace_t &collision );
bool ApplyCollisions( float timeStep );
void CheckForCollisions( float timeStep );
void ClearExternalForce( void );
void AddGravity( void );
void SwapStates( void );
bool TestIfAtRest( float timeStep );
void Rest( void );
void AddPushVelocity( const idVec6 &pushVelocity );
void DebugDraw( void );
};
#endif /* !__PHYSICS_AF_H__ */
+373
View File
@@ -0,0 +1,373 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idPhysics_Base, idPhysics_Actor )
END_CLASS
/*
================
idPhysics_Actor::idPhysics_Actor
================
*/
idPhysics_Actor::idPhysics_Actor( void ) {
clipModel = NULL;
SetClipModelAxis();
mass = 100.0f;
invMass = 1.0f / mass;
masterEntity = NULL;
masterYaw = 0.0f;
masterDeltaYaw = 0.0f;
groundEntityPtr = NULL;
}
/*
================
idPhysics_Actor::~idPhysics_Actor
================
*/
idPhysics_Actor::~idPhysics_Actor( void ) {
if ( clipModel ) {
delete clipModel;
clipModel = NULL;
}
}
/*
================
idPhysics_Actor::Save
================
*/
void idPhysics_Actor::Save( idSaveGame *savefile ) const {
savefile->WriteClipModel( clipModel );
savefile->WriteMat3( clipModelAxis );
savefile->WriteFloat( mass );
savefile->WriteFloat( invMass );
savefile->WriteObject( masterEntity );
savefile->WriteFloat( masterYaw );
savefile->WriteFloat( masterDeltaYaw );
groundEntityPtr.Save( savefile );
}
/*
================
idPhysics_Actor::Restore
================
*/
void idPhysics_Actor::Restore( idRestoreGame *savefile ) {
savefile->ReadClipModel( clipModel );
savefile->ReadMat3( clipModelAxis );
savefile->ReadFloat( mass );
savefile->ReadFloat( invMass );
savefile->ReadObject( reinterpret_cast<idClass *&>( masterEntity ) );
savefile->ReadFloat( masterYaw );
savefile->ReadFloat( masterDeltaYaw );
groundEntityPtr.Restore( savefile );
}
/*
================
idPhysics_Actor::SetClipModelAxis
================
*/
void idPhysics_Actor::SetClipModelAxis( void ) {
// align clip model to gravity direction
if ( ( gravityNormal[2] == -1.0f ) || ( gravityNormal == vec3_zero ) ) {
clipModelAxis.Identity();
}
else {
clipModelAxis[2] = -gravityNormal;
clipModelAxis[2].NormalVectors( clipModelAxis[0], clipModelAxis[1] );
clipModelAxis[1] = -clipModelAxis[1];
}
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, clipModel->GetOrigin(), clipModelAxis );
// RAVEN END
}
}
/*
================
idPhysics_Actor::GetGravityAxis
================
*/
const idMat3 &idPhysics_Actor::GetGravityAxis( void ) const {
return clipModelAxis;
}
/*
================
idPhysics_Actor::GetMasterDeltaYaw
================
*/
float idPhysics_Actor::GetMasterDeltaYaw( void ) const {
return masterDeltaYaw;
}
/*
================
idPhysics_Actor::GetGroundEntity
================
*/
idEntity *idPhysics_Actor::GetGroundEntity( void ) const {
return groundEntityPtr.GetEntity();
}
/*
================
idPhysics_Actor::SetClipModel
================
*/
void idPhysics_Actor::SetClipModel( idClipModel *model, const float density, int id, bool freeOld ) {
assert( self );
assert( model ); // a clip model is required
assert( model->IsTraceModel() ); // and it should be a trace model
assert( density > 0.0f ); // density should be valid
if ( clipModel && clipModel != model && freeOld ) {
delete clipModel;
}
clipModel = model;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, clipModel->GetOrigin(), clipModelAxis );
// RAVEN END
}
/*
================
idPhysics_Actor::GetClipModel
================
*/
idClipModel *idPhysics_Actor::GetClipModel( int id ) const {
return clipModel;
}
/*
================
idPhysics_Actor::GetNumClipModels
================
*/
int idPhysics_Actor::GetNumClipModels( void ) const {
return 1;
}
/*
================
idPhysics_Actor::SetMass
================
*/
void idPhysics_Actor::SetMass( float _mass, int id ) {
assert( _mass > 0.0f );
mass = _mass;
invMass = 1.0f / _mass;
}
/*
================
idPhysics_Actor::GetMass
================
*/
float idPhysics_Actor::GetMass( int id ) const {
return mass;
}
/*
================
idPhysics_Actor::SetContents
================
*/
void idPhysics_Actor::SetContents( int contents, int id ) {
clipModel->SetContents( contents );
}
/*
================
idPhysics_Actor::GetContents
================
*/
int idPhysics_Actor::GetContents( int id ) const {
return clipModel->GetContents();
}
/*
================
idPhysics_Actor::GetBounds
================
*/
const idBounds &idPhysics_Actor::GetBounds( int id ) const {
return clipModel->GetBounds();
}
/*
================
idPhysics_Actor::GetAbsBounds
================
*/
const idBounds &idPhysics_Actor::GetAbsBounds( int id ) const {
return clipModel->GetAbsBounds();
}
/*
================
idPhysics_Actor::IsPushable
================
*/
bool idPhysics_Actor::IsPushable( void ) const {
return ( masterEntity == NULL );
}
/*
================
idPhysics_Actor::GetOrigin
================
*/
const idVec3 &idPhysics_Actor::GetOrigin( int id ) const {
return clipModel->GetOrigin();
}
/*
================
idPhysics_Player::GetAxis
================
*/
const idMat3 &idPhysics_Actor::GetAxis( int id ) const {
return clipModel->GetAxis();
}
/*
================
idPhysics_Actor::SetGravity
================
*/
void idPhysics_Actor::SetGravity( const idVec3 &newGravity ) {
if ( newGravity != gravityVector ) {
idPhysics_Base::SetGravity( newGravity );
SetClipModelAxis();
}
}
/*
================
idPhysics_Actor::ClipTranslation
================
*/
void idPhysics_Actor::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.TranslationModel( self, results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation,
clipModel, clipModel->GetAxis(), clipMask,
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
}
else {
gameLocal.Translation( self, results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation,
clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
}
}
/*
================
idPhysics_Actor::ClipRotation
================
*/
void idPhysics_Actor::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.RotationModel( self, results, clipModel->GetOrigin(), rotation,
clipModel, clipModel->GetAxis(), clipMask,
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
}
else {
gameLocal.Rotation( self, results, clipModel->GetOrigin(), rotation,
clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
}
}
/*
================
idPhysics_Actor::ClipContents
================
*/
int idPhysics_Actor::ClipContents( const idClipModel *model ) const {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple clip models
return gameLocal.ContentsModel( self, clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1,
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
}
else {
return gameLocal.Contents( self, clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL );
// RAVEN END
}
}
/*
================
idPhysics_Actor::DisableClip
================
*/
void idPhysics_Actor::DisableClip( void ) {
clipModel->Disable();
}
/*
================
idPhysics_Actor::EnableClip
================
*/
void idPhysics_Actor::EnableClip( void ) {
clipModel->Enable();
}
/*
================
idPhysics_Actor::UnlinkClip
================
*/
void idPhysics_Actor::UnlinkClip( void ) {
clipModel->Unlink();
}
/*
================
idPhysics_Actor::LinkClip
================
*/
void idPhysics_Actor::LinkClip( void ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, clipModel->GetOrigin(), clipModel->GetAxis() );
// RAVEN END
}
/*
================
idPhysics_Actor::EvaluateContacts
================
*/
bool idPhysics_Actor::EvaluateContacts( void ) {
// get all the ground contacts
ClearContacts();
AddGroundContacts( clipModel );
AddContactEntitiesForContacts();
return ( contacts.Num() != 0 );
}
+89
View File
@@ -0,0 +1,89 @@
#ifndef __PHYSICS_ACTOR_H__
#define __PHYSICS_ACTOR_H__
/*
===================================================================================
Actor physics base class
An actor typically uses one collision model which is aligned with the gravity
direction. The collision model is usually a simple box with the origin at the
bottom center.
===================================================================================
*/
class idPhysics_Actor : public idPhysics_Base {
public:
CLASS_PROTOTYPE( idPhysics_Actor );
idPhysics_Actor( void );
~idPhysics_Actor( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// get delta yaw of master
float GetMasterDeltaYaw( void ) const;
// returns the ground entity
idEntity * GetGroundEntity( void ) const;
// align the clip model with the gravity direction
void SetClipModelAxis( void );
public: // common physics interface
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool IsPushable( void ) const;
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetGravity( const idVec3 &newGravity );
// RAVEN BEGIN
// abahr: made virtual
virtual const idMat3& GetGravityAxis( void ) const;
// RAVEN END
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
protected:
idClipModel * clipModel; // clip model used for collision detection
idMat3 clipModelAxis; // axis of clip model aligned with gravity direction
// derived properties
float mass;
float invMass;
// master
idEntity * masterEntity;
float masterYaw;
float masterDeltaYaw;
// results of last evaluate
idEntityPtr<idEntity> groundEntityPtr;
};
#endif /* !__PHYSICS_ACTOR_H__ */
+872
View File
@@ -0,0 +1,872 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idPhysics, idPhysics_Base )
END_CLASS
/*
================
idPhysics_Base::idPhysics_Base
================
*/
idPhysics_Base::idPhysics_Base( void ) {
self = NULL;
clipMask = 0;
SetGravity( gameLocal.GetGravity() );
ClearContacts();
}
/*
================
idPhysics_Base::~idPhysics_Base
================
*/
idPhysics_Base::~idPhysics_Base( void ) {
if ( self && self->GetPhysics() == this ) {
self->SetPhysics( NULL );
}
idForce::DeletePhysics( this );
ClearContacts();
}
/*
================
idPhysics_Base::Save
================
*/
void idPhysics_Base::Save( idSaveGame *savefile ) const {
int i;
savefile->WriteObject( self );
savefile->WriteInt( clipMask );
savefile->WriteVec3( gravityVector );
savefile->WriteVec3( gravityNormal );
savefile->WriteInt( contacts.Num() );
for ( i = 0; i < contacts.Num(); i++ ) {
savefile->WriteContactInfo( contacts[i] );
}
savefile->WriteInt( contactEntities.Num() );
for ( i = 0; i < contactEntities.Num(); i++ ) {
contactEntities[i].Save( savefile );
}
}
/*
================
idPhysics_Base::Restore
================
*/
void idPhysics_Base::Restore( idRestoreGame *savefile ) {
int i, num;
savefile->ReadObject( reinterpret_cast<idClass *&>( self ) );
savefile->ReadInt( clipMask );
savefile->ReadVec3( gravityVector );
savefile->ReadVec3( gravityNormal );
savefile->ReadInt( num );
contacts.SetNum( num );
for ( i = 0; i < contacts.Num(); i++ ) {
savefile->ReadContactInfo( contacts[i] );
}
savefile->ReadInt( num );
contactEntities.SetNum( num );
for ( i = 0; i < contactEntities.Num(); i++ ) {
contactEntities[i].Restore( savefile );
}
}
/*
================
idPhysics_Base::SetSelf
================
*/
void idPhysics_Base::SetSelf( idEntity *e ) {
assert( e );
self = e;
}
/*
================
idPhysics_Base::SetClipModel
================
*/
void idPhysics_Base::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) {
}
/*
================
idPhysics_Base::GetClipModel
================
*/
idClipModel *idPhysics_Base::GetClipModel( int id ) const {
return NULL;
}
/*
================
idPhysics_Base::GetNumClipModels
================
*/
int idPhysics_Base::GetNumClipModels( void ) const {
return 0;
}
/*
================
idPhysics_Base::SetMass
================
*/
void idPhysics_Base::SetMass( float mass, int id ) {
}
/*
================
idPhysics_Base::GetMass
================
*/
float idPhysics_Base::GetMass( int id ) const {
return 0.0f;
}
// RAVEN BEGIN
// bdube: Added center mass call
/*
================
idPhysics_Base::GetCenterMass
default center of mass is origin
================
*/
idVec3 idPhysics_Base::GetCenterMass ( int id ) const {
return GetOrigin();
}
// RAVEN END
/*
================
idPhysics_Base::SetContents
================
*/
void idPhysics_Base::SetContents( int contents, int id ) {
}
/*
================
idPhysics_Base::SetClipMask
================
*/
int idPhysics_Base::GetContents( int id ) const {
return 0;
}
/*
================
idPhysics_Base::SetClipMask
================
*/
void idPhysics_Base::SetClipMask( int mask, int id ) {
clipMask = mask;
}
/*
================
idPhysics_Base::GetClipMask
================
*/
int idPhysics_Base::GetClipMask( int id ) const {
return clipMask;
}
/*
================
idPhysics_Base::GetBounds
================
*/
const idBounds &idPhysics_Base::GetBounds( int id ) const {
return bounds_zero;
}
/*
================
idPhysics_Base::GetAbsBounds
================
*/
const idBounds &idPhysics_Base::GetAbsBounds( int id ) const {
return bounds_zero;
}
/*
================
idPhysics_Base::Evaluate
================
*/
bool idPhysics_Base::Evaluate( int timeStepMSec, int endTimeMSec ) {
return false;
}
/*
================
idPhysics_Base::UpdateTime
================
*/
void idPhysics_Base::UpdateTime( int endTimeMSec ) {
}
/*
================
idPhysics_Base::GetTime
================
*/
int idPhysics_Base::GetTime( void ) const {
return 0;
}
/*
================
idPhysics_Base::GetImpactInfo
================
*/
void idPhysics_Base::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
memset( info, 0, sizeof( *info ) );
}
/*
================
idPhysics_Base::ApplyImpulse
================
*/
void idPhysics_Base::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
}
/*
================
idPhysics_Base::AddForce
================
*/
void idPhysics_Base::AddForce( const int id, const idVec3 &point, const idVec3 &force ) {
}
/*
================
idPhysics_Base::Activate
================
*/
void idPhysics_Base::Activate( void ) {
}
/*
================
idPhysics_Base::PutToRest
================
*/
void idPhysics_Base::PutToRest( void ) {
}
/*
================
idPhysics_Base::IsAtRest
================
*/
bool idPhysics_Base::IsAtRest( void ) const {
return true;
}
/*
================
idPhysics_Base::GetRestStartTime
================
*/
int idPhysics_Base::GetRestStartTime( void ) const {
return 0;
}
/*
================
idPhysics_Base::IsPushable
================
*/
bool idPhysics_Base::IsPushable( void ) const {
return true;
}
// RAVEN BEGIN
// bdube: water interraction
bool idPhysics_Base::IsInWater ( void ) const {
return false;
}
// RAVEN END
/*
================
idPhysics_Base::SaveState
================
*/
void idPhysics_Base::SaveState( void ) {
}
/*
================
idPhysics_Base::RestoreState
================
*/
void idPhysics_Base::RestoreState( void ) {
}
/*
================
idPhysics_Base::SetOrigin
================
*/
void idPhysics_Base::SetOrigin( const idVec3 &newOrigin, int id ) {
}
/*
================
idPhysics_Base::SetAxis
================
*/
void idPhysics_Base::SetAxis( const idMat3 &newAxis, int id ) {
}
/*
================
idPhysics_Base::Translate
================
*/
void idPhysics_Base::Translate( const idVec3 &translation, int id ) {
}
/*
================
idPhysics_Base::Rotate
================
*/
void idPhysics_Base::Rotate( const idRotation &rotation, int id ) {
}
/*
================
idPhysics_Base::GetOrigin
================
*/
const idVec3 &idPhysics_Base::GetOrigin( int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Base::GetAxis
================
*/
const idMat3 &idPhysics_Base::GetAxis( int id ) const {
return mat3_identity;
}
/*
================
idPhysics_Base::SetLinearVelocity
================
*/
void idPhysics_Base::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
}
/*
================
idPhysics_Base::SetAngularVelocity
================
*/
void idPhysics_Base::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) {
}
/*
================
idPhysics_Base::GetLinearVelocity
================
*/
const idVec3 &idPhysics_Base::GetLinearVelocity( int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Base::GetAngularVelocity
================
*/
const idVec3 &idPhysics_Base::GetAngularVelocity( int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Base::SetGravity
================
*/
void idPhysics_Base::SetGravity( const idVec3 &newGravity ) {
gravityVector = newGravity;
gravityNormal = newGravity;
gravityNormal.Normalize();
}
/*
================
idPhysics_Base::GetGravity
================
*/
const idVec3 &idPhysics_Base::GetGravity( void ) const {
return gravityVector;
}
/*
================
idPhysics_Base::GetGravityNormal
================
*/
const idVec3 &idPhysics_Base::GetGravityNormal( void ) const {
return gravityNormal;
}
/*
================
idPhysics_Base::ClipTranslation
================
*/
void idPhysics_Base::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
memset( &results, 0, sizeof( trace_t ) );
}
/*
================
idPhysics_Base::ClipRotation
================
*/
void idPhysics_Base::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
memset( &results, 0, sizeof( trace_t ) );
}
/*
================
idPhysics_Base::ClipContents
================
*/
int idPhysics_Base::ClipContents( const idClipModel *model ) const {
return 0;
}
/*
================
idPhysics_Base::DisableClip
================
*/
void idPhysics_Base::DisableClip( void ) {
}
/*
================
idPhysics_Base::EnableClip
================
*/
void idPhysics_Base::EnableClip( void ) {
}
/*
================
idPhysics_Base::UnlinkClip
================
*/
void idPhysics_Base::UnlinkClip( void ) {
}
/*
================
idPhysics_Base::LinkClip
================
*/
void idPhysics_Base::LinkClip( void ) {
}
/*
================
idPhysics_Base::EvaluateContacts
================
*/
bool idPhysics_Base::EvaluateContacts( void ) {
return false;
}
/*
================
idPhysics_Base::GetNumContacts
================
*/
int idPhysics_Base::GetNumContacts( void ) const {
return contacts.Num();
}
/*
================
idPhysics_Base::GetContact
================
*/
const contactInfo_t &idPhysics_Base::GetContact( int num ) const {
return contacts[num];
}
/*
================
idPhysics_Base::ClearContacts
================
*/
void idPhysics_Base::ClearContacts( void ) {
int i;
idEntity *ent;
for ( i = 0; i < contacts.Num(); i++ ) {
ent = gameLocal.entities[ contacts[i].entityNum ];
if ( ent ) {
ent->RemoveContactEntity( self );
}
}
contacts.SetNum( 0, false );
}
/*
================
idPhysics_Base::AddContactEntity
================
*/
void idPhysics_Base::AddContactEntity( idEntity *e ) {
int i;
idEntity *ent;
bool found = false;
for ( i = 0; i < contactEntities.Num(); i++ ) {
ent = contactEntities[i].GetEntity();
if ( ent == NULL ) {
contactEntities.RemoveIndex( i-- );
}
if ( ent == e ) {
found = true;
}
}
if ( !found ) {
contactEntities.Alloc() = e;
}
}
/*
================
idPhysics_Base::RemoveContactEntity
================
*/
void idPhysics_Base::RemoveContactEntity( idEntity *e ) {
int i;
idEntity *ent;
for ( i = 0; i < contactEntities.Num(); i++ ) {
ent = contactEntities[i].GetEntity();
if ( !ent ) {
contactEntities.RemoveIndex( i-- );
continue;
}
if ( ent == e ) {
contactEntities.RemoveIndex( i-- );
return;
}
}
}
// RAVEN BEGIN
// abahr:
/*
================
idPhysics_Base::GetContactNormal
================
*/
const idVec3 idPhysics_Base::GetContactNormal() const {
idVec3 normal( vec3_zero );
for( int ix = 0; ix < GetNumContacts(); ++ix ) {
normal += GetContact( ix ).normal;
}
return normal.ToNormal();
}
/*
================
idPhysics_Base::GetContactNormal
================
*/
const idVec3 idPhysics_Base::GetGroundContactNormal() const {
idVec3 normal( vec3_zero );
for( int ix = 0; ix < GetNumContacts(); ++ix ) {
if ( GetContact(ix).normal * -gravityNormal > 0.0f ) {
normal += GetContact( ix ).normal;
}
}
return normal.ToNormal();
}
// RAVEN END
/*
================
idPhysics_Base::HasGroundContacts
================
*/
bool idPhysics_Base::HasGroundContacts( void ) const {
int i;
for ( i = 0; i < contacts.Num(); i++ ) {
if ( contacts[i].normal * -gravityNormal > 0.0f ) {
return true;
}
}
return false;
}
/*
================
idPhysics_Base::IsGroundEntity
================
*/
bool idPhysics_Base::IsGroundEntity( int entityNum ) const {
int i;
for ( i = 0; i < contacts.Num(); i++ ) {
if ( contacts[i].entityNum == entityNum && ( contacts[i].normal * -gravityNormal > 0.0f ) ) {
return true;
}
}
return false;
}
/*
================
idPhysics_Base::IsGroundClipModel
================
*/
bool idPhysics_Base::IsGroundClipModel( int entityNum, int id ) const {
int i;
for ( i = 0; i < contacts.Num(); i++ ) {
if ( contacts[i].entityNum == entityNum && contacts[i].id == id && ( contacts[i].normal * -gravityNormal > 0.0f ) ) {
return true;
}
}
return false;
}
/*
================
idPhysics_Base::SetPushed
================
*/
void idPhysics_Base::SetPushed( int deltaTime ) {
}
/*
================
idPhysics_Base::GetPushedLinearVelocity
================
*/
const idVec3 &idPhysics_Base::GetPushedLinearVelocity( const int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Base::GetPushedAngularVelocity
================
*/
const idVec3 &idPhysics_Base::GetPushedAngularVelocity( const int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Base::SetMaster
================
*/
void idPhysics_Base::SetMaster( idEntity *master, const bool orientated ) {
}
/*
================
idPhysics_Base::GetBlockingInfo
================
*/
const trace_t *idPhysics_Base::GetBlockingInfo( void ) const {
return NULL;
}
/*
================
idPhysics_Base::GetBlockingEntity
================
*/
idEntity *idPhysics_Base::GetBlockingEntity( void ) const {
return NULL;
}
/*
================
idPhysics_Base::GetLinearEndTime
================
*/
int idPhysics_Base::GetLinearEndTime( void ) const {
return 0;
}
/*
================
idPhysics_Base::GetAngularEndTime
================
*/
int idPhysics_Base::GetAngularEndTime( void ) const {
return 0;
}
/*
================
idPhysics_Base::AddGroundContacts
================
*/
void idPhysics_Base::AddGroundContacts( const idClipModel *clipModel ) {
idVec6 dir;
int index, num;
index = contacts.Num();
contacts.SetNum( index + 10, false );
dir.SubVec3(0) = gravityNormal;
dir.SubVec3(1) = vec3_origin;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
num = gameLocal.Contacts( self, &contacts[index], 10, clipModel->GetOrigin(),
dir, CONTACT_EPSILON, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
contacts.SetNum( index + num, false );
}
/*
================
idPhysics_Base::AddContactEntitiesForContacts
================
*/
void idPhysics_Base::AddContactEntitiesForContacts( void ) {
int i;
idEntity *ent;
for ( i = 0; i < contacts.Num(); i++ ) {
ent = gameLocal.entities[ contacts[i].entityNum ];
if ( ent && ent != self ) {
ent->AddContactEntity( self );
}
}
}
/*
================
idPhysics_Base::ActivateContactEntities
================
*/
void idPhysics_Base::ActivateContactEntities( void ) {
int i;
idEntity *ent;
for ( i = 0; i < contactEntities.Num(); i++ ) {
ent = contactEntities[i].GetEntity();
if ( ent ) {
ent->ActivatePhysics( self );
} else {
contactEntities.RemoveIndex( i-- );
}
}
}
/*
================
idPhysics_Base::IsOutsideWorld
================
*/
bool idPhysics_Base::IsOutsideWorld( void ) const {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
if ( !gameLocal.GetWorldBounds( self ).Expand( 128.0f ).IntersectsBounds( GetAbsBounds() ) ) {
// RAVEN END
return true;
}
return false;
}
/*
================
idPhysics_Base::DrawVelocity
================
*/
void idPhysics_Base::DrawVelocity( int id, float linearScale, float angularScale ) const {
idVec3 dir, org, vec, start, end;
idMat3 axis;
float length, a;
dir = GetLinearVelocity( id );
dir *= linearScale;
if ( dir.LengthSqr() > Square( 0.1f ) ) {
dir.Truncate( 10.0f );
org = GetOrigin( id );
gameRenderWorld->DebugArrow( colorRed, org, org + dir, 1 );
}
dir = GetAngularVelocity( id );
length = dir.Normalize();
length *= angularScale;
if ( length > 0.1f ) {
if ( length < 60.0f ) {
length = 60.0f;
}
else if ( length > 360.0f ) {
length = 360.0f;
}
axis = GetAxis( id );
vec = axis[2];
if ( idMath::Fabs( dir * vec ) > 0.99f ) {
vec = axis[0];
}
vec -= vec * dir * vec;
vec.Normalize();
vec *= 4.0f;
start = org + vec;
for ( a = 20.0f; a < length; a += 20.0f ) {
end = org + idRotation( vec3_origin, dir, -a ).ToMat3() * vec;
gameRenderWorld->DebugLine( colorBlue, start, end, 1 );
start = end;
}
end = org + idRotation( vec3_origin, dir, -length ).ToMat3() * vec;
gameRenderWorld->DebugArrow( colorBlue, start, end, 1 );
}
}
/*
================
idPhysics_Base::WriteToSnapshot
================
*/
void idPhysics_Base::WriteToSnapshot( idBitMsgDelta &msg ) const {
}
/*
================
idPhysics_Base::ReadFromSnapshot
================
*/
void idPhysics_Base::ReadFromSnapshot( const idBitMsgDelta &msg ) {
}
+160
View File
@@ -0,0 +1,160 @@
#ifndef __PHYSICS_BASE_H__
#define __PHYSICS_BASE_H__
/*
===============================================================================
Physics base for a moving object using one or more collision models.
===============================================================================
*/
// RAVEN BEGIN
// jnewquist: Changed from #define to typedef to fix compiler issues
typedef idEntityPtr<idEntity> contactEntity_t;
// RAVEN END
class idPhysics_Base : public idPhysics {
public:
CLASS_PROTOTYPE( idPhysics_Base );
idPhysics_Base( void );
~idPhysics_Base( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public: // common physics interface
void SetSelf( idEntity *e );
//RAVEN BEGIN
// abahr: for gravity
virtual idEntity* GetSelf() const { return self; }
// RAVEN END
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
// RAVEN BEGIN
// bdube: added center mass
idVec3 GetCenterMass ( int id = -1 ) const;
// RAVEN END
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
void SetClipMask( int mask, int id = -1 );
int GetClipMask( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void AddForce( const int id, const idVec3 &point, const idVec3 &force );
void Activate( void );
void PutToRest( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
// RAVEN BEGIN
// bdube: water interraction
bool IsInWater ( void ) const;
// RAVEN END
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void SetGravity( const idVec3 &newGravity );
const idVec3 & GetGravity( void ) const;
const idVec3 & GetGravityNormal( void ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
int GetNumContacts( void ) const;
const contactInfo_t & GetContact( int num ) const;
void ClearContacts( void );
void AddContactEntity( idEntity *e );
void RemoveContactEntity( idEntity *e );
// RAVEN BEGIN
// abahr: helper function used in projectiles
virtual const idVec3 GetContactNormal() const;
virtual const idVec3 GetGroundContactNormal() const;
// RAVEN END
bool HasGroundContacts( void ) const;
bool IsGroundEntity( int entityNum ) const;
bool IsGroundClipModel( int entityNum, int id ) const;
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated = true );
const trace_t * GetBlockingInfo( void ) const;
idEntity * GetBlockingEntity( void ) const;
int GetLinearEndTime( void ) const;
int GetAngularEndTime( void ) const;
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
protected:
idEntity * self; // entity using this physics object
int clipMask; // contents the physics object collides with
idVec3 gravityVector; // direction and magnitude of gravity
idVec3 gravityNormal; // normalized direction of gravity
idList<contactInfo_t> contacts; // contacts with other physics objects
idList<contactEntity_t> contactEntities; // entities touching this physics object
protected:
// add ground contacts for the clip model
void AddGroundContacts( const idClipModel *clipModel );
// add contact entity links to contact entities
void AddContactEntitiesForContacts( void );
// active all contact entities
void ActivateContactEntities( void );
// returns true if the whole physics object is outside the world bounds
bool IsOutsideWorld( void ) const;
// draw linear and angular velocity
void DrawVelocity( int id, float linearScale, float angularScale ) const;
};
#endif /* !__PHYSICS_BASE_H__ */
+838
View File
@@ -0,0 +1,838 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idPhysics_Actor, idPhysics_Monster )
END_CLASS
const float OVERCLIP = 1.001f;
/*
=====================
idPhysics_Monster::CheckGround
=====================
*/
void idPhysics_Monster::CheckGround( monsterPState_t &state ) {
trace_t groundTrace;
idVec3 down;
if ( gravityNormal == vec3_zero ) {
state.onGround = false;
groundEntityPtr = NULL;
return;
}
down = state.origin + gravityNormal * CONTACT_EPSILON;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( self, groundTrace, state.origin, down, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
if ( groundTrace.fraction == 1.0f ) {
state.onGround = false;
groundEntityPtr = NULL;
return;
}
groundEntityPtr = gameLocal.entities[ groundTrace.c.entityNum ];
if ( ( groundTrace.c.normal * -gravityNormal ) < minFloorCosine ) {
state.onGround = false;
return;
}
state.onGround = true;
// let the entity know about the collision
self->Collide( groundTrace, state.velocity );
// apply impact to a non world floor entity
if ( groundTrace.c.entityNum != ENTITYNUM_WORLD && groundEntityPtr.GetEntity() ) {
impactInfo_t info;
groundEntityPtr.GetEntity()->GetImpactInfo( self, groundTrace.c.id, groundTrace.c.point, &info );
if ( info.invMass != 0.0f ) {
groundEntityPtr.GetEntity()->ApplyImpulse( self, 0, groundTrace.c.point, state.velocity / ( info.invMass * 10.0f ) );
}
}
}
/*
=====================
idPhysics_Monster::SlideMove
=====================
*/
monsterMoveResult_t idPhysics_Monster::SlideMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) {
int i;
trace_t tr;
idVec3 move;
blockingEntity = NULL;
move = delta;
for( i = 0; i < 3; i++ ) {
// RAVEN BEGIN
// ddynerman: multiple collision worlds
gameLocal.Translation( self, tr, start, start + move, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
start = tr.endpos;
if ( tr.fraction == 1.0f ) {
if ( i > 0 ) {
return MM_SLIDING;
}
return MM_OK;
}
if ( tr.c.entityNum != ENTITYNUM_NONE ) {
blockingEntity = gameLocal.entities[ tr.c.entityNum ];
}
// clip the movement delta and velocity
move.ProjectOntoPlane( tr.c.normal, OVERCLIP );
velocity.ProjectOntoPlane( tr.c.normal, OVERCLIP );
}
return MM_BLOCKED;
}
/*
=====================
idPhysics_Monster::StepMove
move start into the delta direction
the velocity is clipped conform any collisions
=====================
*/
monsterMoveResult_t idPhysics_Monster::StepMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta ) {
trace_t tr;
idVec3 up, down, noStepPos, noStepVel, stepPos, stepVel;
monsterMoveResult_t result1, result2;
float stepdist;
float nostepdist;
if ( delta == vec3_origin ) {
return MM_OK;
}
// try to move without stepping up
noStepPos = start;
noStepVel = velocity;
result1 = SlideMove( noStepPos, noStepVel, delta );
if ( result1 == MM_OK ) {
velocity = noStepVel;
// RAVEN BEGIN
// bdube: dont step when there is no gravity
if ( gravityNormal == vec3_zero || forceDeltaMove ) {
// RAVEN END
start = noStepPos;
return MM_OK;
}
// try to step down so that we walk down slopes and stairs at a normal rate
down = noStepPos + gravityNormal * maxStepHeight;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( self, tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
if ( tr.fraction < 1.0f ) {
start = tr.endpos;
return MM_STEPPED;
} else {
start = noStepPos;
return MM_OK;
}
}
// RAVEN BEGIN
// jnewquist: Use accessor for static class type
if ( blockingEntity && blockingEntity->IsType( idActor::GetClassType() ) ) {
// RAVEN END
// try to step down in case walking into an actor while going down steps
down = noStepPos + gravityNormal * maxStepHeight;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( self, tr, noStepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
start = tr.endpos;
velocity = noStepVel;
return MM_BLOCKED;
}
if ( gravityNormal == vec3_zero ) {
return result1;
}
// try to step up
up = start - gravityNormal * maxStepHeight;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( self, tr, start, up, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
if ( tr.fraction == 0.0f ) {
start = noStepPos;
velocity = noStepVel;
return result1;
}
// try to move at the stepped up position
stepPos = tr.endpos;
stepVel = velocity;
result2 = SlideMove( stepPos, stepVel, delta );
if ( result2 == MM_BLOCKED ) {
start = noStepPos;
velocity = noStepVel;
return result1;
}
// step down again
down = stepPos + gravityNormal * maxStepHeight;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.Translation( self, tr, stepPos, down, clipModel, clipModel->GetAxis(), clipMask, self );
// RAVEN END
stepPos = tr.endpos;
// if the move is further without stepping up, or the slope is too steap, don't step up
nostepdist = ( noStepPos - start ).LengthSqr();
stepdist = ( stepPos - start ).LengthSqr();
if ( ( nostepdist >= stepdist ) || ( ( tr.c.normal * -gravityNormal ) < minFloorCosine ) ) {
start = noStepPos;
velocity = noStepVel;
return MM_SLIDING;
}
start = stepPos;
velocity = stepVel;
return MM_STEPPED;
}
/*
================
idPhysics_Monster::Activate
================
*/
void idPhysics_Monster::Activate( void ) {
current.atRest = -1;
self->BecomeActive( TH_PHYSICS );
}
/*
================
idPhysics_Monster::Rest
================
*/
void idPhysics_Monster::Rest( void ) {
current.atRest = gameLocal.time;
current.velocity.Zero();
self->BecomeInactive( TH_PHYSICS );
}
/*
================
idPhysics_Monster::PutToRest
================
*/
void idPhysics_Monster::PutToRest( void ) {
Rest();
}
/*
================
idPhysics_Monster::idPhysics_Monster
================
*/
idPhysics_Monster::idPhysics_Monster( void ) {
memset( &current, 0, sizeof( current ) );
current.atRest = -1;
saved = current;
delta.Zero();
maxStepHeight = 18.0f;
minFloorCosine = 0.7f;
moveResult = MM_OK;
forceDeltaMove = false;
fly = false;
useVelocityMove = false;
noImpact = false;
blockingEntity = NULL;
}
/*
================
idPhysics_Monster_SavePState
================
*/
void idPhysics_Monster_SavePState( idSaveGame *savefile, const monsterPState_t &state ) {
savefile->WriteInt( state.atRest );
savefile->WriteBool( state.onGround );
savefile->WriteVec3( state.origin );
savefile->WriteVec3( state.velocity );
savefile->WriteVec3( state.localOrigin );
savefile->WriteVec3( state.pushVelocity );
savefile->WriteVec3( state.lastPushVelocity ); // cnicholson: Added unsaved var
}
/*
================
idPhysics_Monster_RestorePState
================
*/
void idPhysics_Monster_RestorePState( idRestoreGame *savefile, monsterPState_t &state ) {
savefile->ReadInt( state.atRest );
savefile->ReadBool( state.onGround );
savefile->ReadVec3( state.origin );
savefile->ReadVec3( state.velocity );
savefile->ReadVec3( state.localOrigin );
savefile->ReadVec3( state.pushVelocity );
savefile->ReadVec3( state.lastPushVelocity ); // cnicholson: Added unrestored var
}
/*
================
idPhysics_Monster::Save
================
*/
void idPhysics_Monster::Save( idSaveGame *savefile ) const {
idPhysics_Monster_SavePState( savefile, current );
idPhysics_Monster_SavePState( savefile, saved );
savefile->WriteFloat( maxStepHeight );
savefile->WriteFloat( minFloorCosine );
savefile->WriteVec3( delta );
savefile->WriteBool( forceDeltaMove );
savefile->WriteBool( fly );
savefile->WriteBool( useVelocityMove );
savefile->WriteBool( noImpact );
savefile->WriteInt( (int)moveResult );
savefile->WriteObject( blockingEntity );
}
/*
================
idPhysics_Monster::Restore
================
*/
void idPhysics_Monster::Restore( idRestoreGame *savefile ) {
idPhysics_Monster_RestorePState( savefile, current );
idPhysics_Monster_RestorePState( savefile, saved );
savefile->ReadFloat( maxStepHeight );
savefile->ReadFloat( minFloorCosine );
savefile->ReadVec3( delta );
savefile->ReadBool( forceDeltaMove );
savefile->ReadBool( fly );
savefile->ReadBool( useVelocityMove );
savefile->ReadBool( noImpact );
savefile->ReadInt( (int &)moveResult );
savefile->ReadObject( reinterpret_cast<idClass *&>( blockingEntity ) );
}
/*
================
idPhysics_Monster::SetDelta
================
*/
void idPhysics_Monster::SetDelta( const idVec3 &d ) {
delta = d;
if ( delta != vec3_origin ) {
Activate();
}
}
/*
================
idPhysics_Monster::SetMaxStepHeight
================
*/
void idPhysics_Monster::SetMaxStepHeight( const float newMaxStepHeight ) {
maxStepHeight = newMaxStepHeight;
}
/*
================
idPhysics_Monster::GetMaxStepHeight
================
*/
float idPhysics_Monster::GetMaxStepHeight( void ) const {
return maxStepHeight;
}
/*
================
idPhysics_Monster::OnGround
================
*/
bool idPhysics_Monster::OnGround( void ) const {
return current.onGround;
}
/*
================
idPhysics_Monster::GetSlideMoveEntity
================
*/
idEntity *idPhysics_Monster::GetSlideMoveEntity( void ) const {
return blockingEntity;
}
/*
================
idPhysics_Monster::GetMoveResult
================
*/
monsterMoveResult_t idPhysics_Monster::GetMoveResult( void ) const {
return moveResult;
}
/*
================
idPhysics_Monster::ForceDeltaMove
================
*/
void idPhysics_Monster::ForceDeltaMove( bool force ) {
forceDeltaMove = force;
}
/*
================
idPhysics_Monster::UseFlyMove
================
*/
void idPhysics_Monster::UseFlyMove( bool force ) {
fly = force;
}
/*
================
idPhysics_Monster::UseVelocityMove
================
*/
void idPhysics_Monster::UseVelocityMove( bool force ) {
useVelocityMove = force;
}
/*
================
idPhysics_Monster::EnableImpact
================
*/
void idPhysics_Monster::EnableImpact( void ) {
noImpact = false;
}
/*
================
idPhysics_Monster::DisableImpact
================
*/
void idPhysics_Monster::DisableImpact( void ) {
noImpact = true;
}
/*
================
idPhysics_Monster::Evaluate
================
*/
bool idPhysics_Monster::Evaluate( int timeStepMSec, int endTimeMSec ) {
idVec3 masterOrigin, oldOrigin;
idMat3 masterAxis;
float timeStep;
timeStep = MS2SEC( timeStepMSec );
moveResult = MM_OK;
blockingEntity = NULL;
oldOrigin = current.origin;
// if bound to a master
if ( masterEntity ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.origin = masterOrigin + current.localOrigin * masterAxis;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, clipModel->GetAxis() );
// RAVEN END
current.velocity = ( current.origin - oldOrigin ) / timeStep;
masterDeltaYaw = masterYaw;
masterYaw = masterAxis[0].ToYaw();
masterDeltaYaw = masterYaw - masterDeltaYaw;
return true;
}
// if the monster is at rest
if ( current.atRest >= 0 ) {
return true;
}
ActivateContactEntities();
// move the monster velocity into the frame of a pusher
current.velocity -= current.pushVelocity;
clipModel->Unlink();
// check if on the ground
idPhysics_Monster::CheckGround( current );
// if not on the ground or moving upwards
float upspeed;
if ( gravityNormal != vec3_zero ) {
upspeed = -( current.velocity * gravityNormal );
} else {
upspeed = current.velocity.z;
}
if ( fly || ( !forceDeltaMove && ( !current.onGround || upspeed > 1.0f ) ) ) {
if ( upspeed < 0.0f ) {
moveResult = MM_FALLING;
}
else {
current.onGround = false;
moveResult = MM_OK;
}
delta = current.velocity * timeStep;
if ( delta != vec3_origin ) {
moveResult = idPhysics_Monster::SlideMove( current.origin, current.velocity, delta );
delta.Zero();
}
if ( !fly ) {
current.velocity += gravityVector * timeStep;
}
} else {
if ( useVelocityMove ) {
delta = current.velocity * timeStep;
} else {
current.velocity = delta / timeStep;
}
current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal;
if ( delta == vec3_origin ) {
Rest();
} else {
// try moving into the desired direction
// RAVEN BEGIN
// jshepard: flying creatures, even if not using fly move, shouldn't use step move
if( self->IsType( idAI::GetClassType() ) && ((idAI*)self)->move.moveType == MOVETYPE_FLY ) {
moveResult = idPhysics_Monster::SlideMove( current.origin, current.velocity, delta );
} else {
moveResult = idPhysics_Monster::StepMove( current.origin, current.velocity, delta );
}
delta.Zero();
// RAVEN END
current.velocity -= ( current.velocity * gravityNormal ) * gravityNormal;
}
}
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, clipModel->GetAxis() );
// RAVEN END
// get all the ground contacts
EvaluateContacts();
// move the monster velocity back into the world frame
current.velocity += current.pushVelocity;
current.lastPushVelocity = current.pushVelocity;
current.pushVelocity.Zero();
if ( IsOutsideWorld() ) {
gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
Rest();
}
// RAVEN BEGIN
// bdube: determine if we moved this frame
return true;
// RAVEN END
}
/*
================
idPhysics_Monster::UpdateTime
================
*/
void idPhysics_Monster::UpdateTime( int endTimeMSec ) {
}
/*
================
idPhysics_Monster::GetTime
================
*/
int idPhysics_Monster::GetTime( void ) const {
return gameLocal.time;
}
/*
================
idPhysics_Monster::GetImpactInfo
================
*/
void idPhysics_Monster::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
info->invMass = invMass;
info->invInertiaTensor.Zero();
info->position.Zero();
info->velocity = current.velocity;
}
/*
================
idPhysics_Monster::ApplyImpulse
================
*/
void idPhysics_Monster::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
if ( noImpact ) {
return;
}
current.velocity += impulse * invMass;
Activate();
}
/*
================
idPhysics_Monster::IsAtRest
================
*/
bool idPhysics_Monster::IsAtRest( void ) const {
return current.atRest >= 0;
}
/*
================
idPhysics_Monster::GetRestStartTime
================
*/
int idPhysics_Monster::GetRestStartTime( void ) const {
return current.atRest;
}
/*
================
idPhysics_Monster::SaveState
================
*/
void idPhysics_Monster::SaveState( void ) {
saved = current;
}
/*
================
idPhysics_Monster::RestoreState
================
*/
void idPhysics_Monster::RestoreState( void ) {
current = saved;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, clipModel->GetAxis() );
// RAVEN END
EvaluateContacts();
}
/*
================
idPhysics_Player::SetOrigin
================
*/
void idPhysics_Monster::SetOrigin( const idVec3 &newOrigin, int id ) {
idVec3 masterOrigin;
idMat3 masterAxis;
current.localOrigin = newOrigin;
if ( masterEntity ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.origin = masterOrigin + newOrigin * masterAxis;
}
else {
current.origin = newOrigin;
}
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, newOrigin, clipModel->GetAxis() );
// RAVEN END
Activate();
}
/*
================
idPhysics_Player::SetAxis
================
*/
void idPhysics_Monster::SetAxis( const idMat3 &newAxis, int id ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, clipModel->GetOrigin(), newAxis );
// RAVEN END
Activate();
}
/*
================
idPhysics_Monster::Translate
================
*/
void idPhysics_Monster::Translate( const idVec3 &translation, int id ) {
current.localOrigin += translation;
current.origin += translation;
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, clipModel->GetAxis() );
// RAVEN END
Activate();
}
/*
================
idPhysics_Monster::Rotate
================
*/
void idPhysics_Monster::Rotate( const idRotation &rotation, int id ) {
idVec3 masterOrigin;
idMat3 masterAxis;
current.origin *= rotation;
if ( masterEntity ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
}
else {
current.localOrigin = current.origin;
}
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, clipModel->GetAxis() * rotation.ToMat3() );
// RAVEN END
Activate();
}
/*
================
idPhysics_Monster::SetLinearVelocity
================
*/
void idPhysics_Monster::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
current.velocity = newLinearVelocity;
Activate();
}
/*
================
idPhysics_Monster::GetLinearVelocity
================
*/
const idVec3 &idPhysics_Monster::GetLinearVelocity( int id ) const {
return current.velocity;
}
/*
================
idPhysics_Monster::SetPushed
================
*/
void idPhysics_Monster::SetPushed( int deltaTime ) {
// velocity with which the monster is pushed
current.pushVelocity += ( current.origin - saved.origin ) / ( deltaTime * idMath::M_MS2SEC );
}
/*
================
idPhysics_Monster::GetPushedLinearVelocity
================
*/
const idVec3 &idPhysics_Monster::GetPushedLinearVelocity( const int id ) const {
return current.lastPushVelocity;
}
/*
================
idPhysics_Monster::SetMaster
the binding is never orientated
================
*/
void idPhysics_Monster::SetMaster( idEntity *master, const bool orientated ) {
idVec3 masterOrigin;
idMat3 masterAxis;
if ( master ) {
if ( !masterEntity ) {
// transform from world space to master space
self->GetMasterPosition( masterOrigin, masterAxis );
current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
masterEntity = master;
masterYaw = masterAxis[0].ToYaw();
}
ClearContacts();
}
else {
if ( masterEntity ) {
masterEntity = NULL;
Activate();
}
}
}
const float MONSTER_VELOCITY_MAX = 4000;
const int MONSTER_VELOCITY_TOTAL_BITS = 16;
const int MONSTER_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( MONSTER_VELOCITY_MAX ) ) + 1;
const int MONSTER_VELOCITY_MANTISSA_BITS = MONSTER_VELOCITY_TOTAL_BITS - 1 - MONSTER_VELOCITY_EXPONENT_BITS;
/*
================
idPhysics_Monster::WriteToSnapshot
================
*/
void idPhysics_Monster::WriteToSnapshot( idBitMsgDelta &msg ) const {
msg.WriteFloat( current.origin[0] );
msg.WriteFloat( current.origin[1] );
msg.WriteFloat( current.origin[2] );
msg.WriteFloat( current.velocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteFloat( current.velocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteFloat( current.velocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] );
msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] );
msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] );
msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
msg.WriteLong( current.atRest );
msg.WriteBits( current.onGround, 1 );
}
/*
================
idPhysics_Monster::ReadFromSnapshot
================
*/
void idPhysics_Monster::ReadFromSnapshot( const idBitMsgDelta &msg ) {
current.origin[0] = msg.ReadFloat();
current.origin[1] = msg.ReadFloat();
current.origin[2] = msg.ReadFloat();
current.velocity[0] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.velocity[1] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.velocity[2] = msg.ReadFloat( MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] );
current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] );
current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] );
current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, MONSTER_VELOCITY_EXPONENT_BITS, MONSTER_VELOCITY_MANTISSA_BITS );
current.atRest = msg.ReadLong();
current.onGround = msg.ReadBits( 1 ) != 0;
}
+129
View File
@@ -0,0 +1,129 @@
#ifndef __PHYSICS_MONSTER_H__
#define __PHYSICS_MONSTER_H__
/*
===================================================================================
Monster physics
Simulates the motion of a monster through the environment. The monster motion
is typically driven by animations.
===================================================================================
*/
typedef enum {
MM_OK,
MM_SLIDING,
MM_BLOCKED,
MM_STEPPED,
MM_FALLING
} monsterMoveResult_t;
typedef struct monsterPState_s {
int atRest;
bool onGround;
idVec3 origin;
idVec3 velocity;
idVec3 localOrigin;
idVec3 pushVelocity;
// RAVEN BEGIN
// bdube: added
idVec3 lastPushVelocity;
// RAVEN END
} monsterPState_t;
class idPhysics_Monster : public idPhysics_Actor {
public:
CLASS_PROTOTYPE( idPhysics_Monster );
idPhysics_Monster( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// maximum step up the monster can take, default 18 units
void SetMaxStepHeight( const float newMaxStepHeight );
float GetMaxStepHeight( void ) const;
// minimum cosine of floor angle to be able to stand on the floor
void SetMinFloorCosine( const float newMinFloorCosine );
// set delta for next move
void SetDelta( const idVec3 &d );
// returns true if monster is standing on the ground
bool OnGround( void ) const;
// returns the movement result
monsterMoveResult_t GetMoveResult( void ) const;
// overrides any velocity for pure delta movement
void ForceDeltaMove( bool force );
// whether velocity should be affected by gravity
void UseFlyMove( bool force );
// don't use delta movement
void UseVelocityMove( bool force );
// get entity blocking the move
idEntity * GetSlideMoveEntity( void ) const;
// enable/disable activation by impact
void EnableImpact( void );
void DisableImpact( void );
public: // common physics interface
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void Activate( void );
void PutToRest( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated = true );
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
private:
// monster physics state
monsterPState_t current;
monsterPState_t saved;
// properties
float maxStepHeight; // maximum step height
float minFloorCosine; // minimum cosine of floor angle
idVec3 delta; // delta for next move
bool forceDeltaMove;
bool fly;
bool useVelocityMove;
bool noImpact; // if true do not activate when another object collides
// results of last evaluate
monsterMoveResult_t moveResult;
idEntity * blockingEntity;
private:
void CheckGround( monsterPState_t &state );
monsterMoveResult_t SlideMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta );
monsterMoveResult_t StepMove( idVec3 &start, idVec3 &velocity, const idVec3 &delta );
void Rest( void );
};
#endif /* !__PHYSICS_MONSTER_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,163 @@
#ifndef __PHYSICS_PARAMETRIC_H__
#define __PHYSICS_PARAMETRIC_H__
/*
===================================================================================
Parametric physics
Used for predefined or scripted motion. The motion of an object is completely
parametrized. By adjusting the parameters an object is forced to follow a
predefined path. The parametric physics is typically used for doors, bridges,
rotating fans etc.
===================================================================================
*/
typedef struct parametricPState_s {
int time; // physics time
int atRest; // set when simulation is suspended
idVec3 origin; // world origin
idAngles angles; // world angles
idMat3 axis; // world axis
idVec3 localOrigin; // local origin
idAngles localAngles; // local angles
idExtrapolate<idVec3> linearExtrapolation; // extrapolation based description of the position over time
idExtrapolate<idAngles> angularExtrapolation; // extrapolation based description of the orientation over time
idInterpolateAccelDecelLinear<idVec3> linearInterpolation; // interpolation based description of the position over time
idInterpolateAccelDecelLinear<idAngles> angularInterpolation; // interpolation based description of the orientation over time
idCurve_Spline<idVec3> * spline; // spline based description of the position over time
idInterpolateAccelDecelLinear<float> splineInterpolate; // position along the spline over time
bool useSplineAngles; // set the orientation using the spline
} parametricPState_t;
class idPhysics_Parametric : public idPhysics_Base {
public:
CLASS_PROTOTYPE( idPhysics_Parametric );
idPhysics_Parametric( void );
~idPhysics_Parametric( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void SetPusher( int flags );
bool IsPusher( void ) const;
void SetLinearExtrapolation( extrapolation_t type, int time, int duration, const idVec3 &base, const idVec3 &speed, const idVec3 &baseSpeed );
void SetAngularExtrapolation( extrapolation_t type, int time, int duration, const idAngles &base, const idAngles &speed, const idAngles &baseSpeed );
extrapolation_t GetLinearExtrapolationType( void ) const;
extrapolation_t GetAngularExtrapolationType( void ) const;
void SetLinearInterpolation( int time, int accelTime, int decelTime, int duration, const idVec3 &startPos, const idVec3 &endPos );
void SetAngularInterpolation( int time, int accelTime, int decelTime, int duration, const idAngles &startAng, const idAngles &endAng );
void SetSpline( idCurve_Spline<idVec3> *spline, int accelTime, int decelTime, bool useSplineAngles );
idCurve_Spline<idVec3> *GetSpline( void ) const;
int GetSplineAcceleration( void ) const;
int GetSplineDeceleration( void ) const;
bool UsingSplineAngles( void ) const;
void GetLocalOrigin( idVec3 &curOrigin ) const;
void GetLocalAngles( idAngles &curAngles ) const;
void GetAngles( idAngles &curAngles ) const;
// RAVEN BEGIN
// abahr: a method for hiding gimblelock
void SetAxisOffset( const idMat3& offset ) { axisOffset = offset; useAxisOffset = true; }
const idMat3& GetAxisOffset() const { return axisOffset; }
idMat3& GetAxisOffset() { return axisOffset; }
bool UseAxisOffset() const { return useAxisOffset; }
// RAVEN END
public: // common physics interface
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void Activate( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
void SetMaster( idEntity *master, const bool orientated = true );
const trace_t * GetBlockingInfo( void ) const;
idEntity * GetBlockingEntity( void ) const;
int GetLinearEndTime( void ) const;
int GetAngularEndTime( void ) const;
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
private:
// parametric physics state
parametricPState_t current;
parametricPState_t saved;
// pusher
bool isPusher;
idClipModel * clipModel;
int pushFlags;
// results of last evaluate
trace_t pushResults;
bool isBlocked;
// master
bool hasMaster;
bool isOrientated;
// RAVEN BEGIN
// abahr: a method for hiding gimblelock
bool useAxisOffset;
idMat3 axisOffset;
// RAVEN END
private:
bool TestIfAtRest( void ) const;
void Rest( void );
};
#endif /* !__PHYSICS_PARAMETRIC_H__ */
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
#ifndef __PHYSICS_PARTICLE_H__
#define __PHYSICS_PARTICLE_H__
/*
===================================================================================
Particle Physics
Employs an impulse based dynamic simulation which is not very accurate but
relatively fast and still reliable due to the continuous collision detection.
===================================================================================
*/
typedef struct particlePState_s {
int atRest; // set when simulation is suspended
idVec3 localOrigin; // origin relative to master
idMat3 localAxis; // axis relative to master
idVec3 pushVelocity; // push velocity
idVec3 origin;
idVec3 velocity;
bool onGround;
bool inWater;
} particlePState_t;
class rvPhysics_Particle : public idPhysics_Base {
public:
CLASS_PROTOTYPE( rvPhysics_Particle );
rvPhysics_Particle( void );
~rvPhysics_Particle( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// initialisation
void SetFriction( const float linear, const float angular, const float contact );
void SetBouncyness( const float b, bool allowBounce );
// put to rest untill something collides with this physics object
void PutToRest( void );
// same as above but drop to the floor first
void DropToFloor( void );
// returns true if touching the ground
bool IsOnGround ( void ) const;
bool IsInWater ( void ) const;
public: // common physics interface
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
bool CanBounce ( void ) const;
bool EvaluateContacts( void );
void Activate( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated );
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
idEntityPtr<idEntity> extraPassEntity;
private:
// state of the particle
particlePState_t current;
particlePState_t saved;
// particle properties
float linearFriction; // translational friction
float angularFriction; // rotational friction
float contactFriction; // friction with contact surfaces
float bouncyness; // bouncyness
bool allowBounce; // Allowed to bounce at all?
idClipModel * clipModel; // clip model used for collision detection
bool dropToFloor; // true if dropping to the floor and putting to rest
bool testSolid; // true if testing for inside solid during a drop
// master
bool hasMaster;
bool isOrientated;
private:
void DropToFloorAndRest ( void );
bool SlideMove ( idVec3& start, idVec3& velocity, const idVec3& delta );
void CheckGround ( void );
void ApplyFriction ( float timeStep );
void DebugDraw ( void );
};
ID_INLINE bool rvPhysics_Particle::IsOnGround ( void ) const {
return current.onGround;
}
ID_INLINE bool rvPhysics_Particle::IsInWater ( void ) const {
return current.inWater;
}
ID_INLINE bool rvPhysics_Particle::CanBounce ( void ) const {
return allowBounce;
}
#endif /* !__PHYSICS_PARTICLE_H__ */
File diff suppressed because it is too large Load Diff
+198
View File
@@ -0,0 +1,198 @@
#ifndef __PHYSICS_PLAYER_H__
#define __PHYSICS_PLAYER_H__
/*
===================================================================================
Player physics
Simulates the motion of a player through the environment. Input from the
player is used to allow a certain degree of control over the motion.
===================================================================================
*/
// movementType
typedef enum {
PM_NORMAL, // normal physics
PM_DEAD, // no acceleration or turning, but free falling
PM_SPECTATOR, // flying without gravity but with collision detection
PM_FREEZE, // stuck in place without control
PM_NOCLIP // flying without collision detection nor gravity
} pmtype_t;
typedef enum {
WATERLEVEL_NONE,
WATERLEVEL_FEET,
WATERLEVEL_WAIST,
WATERLEVEL_HEAD
} waterLevel_t;
#define MAXTOUCH 32
typedef struct playerPState_s {
idVec3 origin;
idVec3 velocity;
idVec3 localOrigin;
idVec3 pushVelocity;
// RAVEN BEGIN
// bdube: added
idVec3 lastPushVelocity;
// RAVEN END
float stepUp;
int movementType;
int movementFlags;
int movementTime;
// RAVEN BEGIN
// bdube: crouch slide
int crouchSlideTime;
// RAVEN END
} playerPState_t;
class idPhysics_Player : public idPhysics_Actor {
public:
CLASS_PROTOTYPE( idPhysics_Player );
idPhysics_Player( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// initialisation
void SetSpeed( const float newWalkSpeed, const float newCrouchSpeed );
void SetMaxStepHeight( const float newMaxStepHeight );
float GetMaxStepHeight( void ) const;
void SetMaxJumpHeight( const float newMaxJumpHeight );
void SetMovementType( const pmtype_t type );
void SetPlayerInput( const usercmd_t &cmd, const idAngles &newViewAngles );
void SetKnockBack( const int knockBackTime );
void SetDebugLevel( bool set );
// feed back from last physics frame
waterLevel_t GetWaterLevel( void ) const;
int GetWaterType( void ) const;
bool HasJumped( void ) const;
bool HasSteppedUp( void ) const;
float GetStepUp( void ) const;
bool IsCrouching( void ) const;
bool OnLadder( void ) const;
const idVec3 & PlayerGetOrigin( void ) const; // != GetOrigin
public: // common physics interface
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
void ClearPushedVelocity( void );
void SetMaster( idEntity *master, const bool orientated = true );
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
// RAVEN BEGIN
// kfuller: Added
bool IsNoclip( void ) const;
bool IsDead( void ) const;
// RAVEN END
void SetClipModelNoLink( idClipModel *clip );
private:
// player physics state
playerPState_t current;
playerPState_t saved;
// properties
float walkSpeed;
float crouchSpeed;
float maxStepHeight;
float maxJumpHeight;
int debugLevel; // if set, diagnostic output will be printed
// player input
usercmd_t command;
idAngles viewAngles;
// run-time variables
int framemsec;
float frametime;
float playerSpeed;
idVec3 viewForward;
idVec3 viewRight;
// walk movement
bool walking;
bool groundPlane;
trace_t groundTrace;
const idMaterial * groundMaterial;
// ladder movement
bool ladder;
idVec3 ladderNormal;
// results of last evaluate
waterLevel_t waterLevel;
int waterType;
private:
float CmdScale( const usercmd_t &cmd ) const;
void Accelerate( const idVec3 &wishdir, const float wishspeed, const float accel );
bool SlideMove( bool gravity, bool stepUp, bool stepDown, bool push );
void Friction( void );
void WaterJumpMove( void );
void WaterMove( void );
void FlyMove( void );
void AirMove( void );
void WalkMove( void );
void DeadMove( void );
void NoclipMove( void );
void SpectatorMove( void );
void LadderMove( void );
void CorrectAllSolid( trace_t &trace, int contents );
// RAVEN BEGIN
// MrE: check stuck
void CheckGround( bool checkStuck );
// RAVEN END
void CheckDuck( void );
void CheckLadder( void );
bool CheckJump( void );
bool CheckWaterJump( void );
void SetWaterLevel( void );
void DropTimers( void );
void MovePlayer( int msec );
float Pm_Accelerate( void );
float Pm_AirAccelerate( void );
};
ID_INLINE bool idPhysics_Player::IsNoclip( void ) const {
return current.movementType == PM_NOCLIP;
}
ID_INLINE bool idPhysics_Player::IsDead( void ) const {
return current.movementType == PM_DEAD;
}
#endif /* !__PHYSICS_PLAYER_H__ */
File diff suppressed because it is too large Load Diff
+172
View File
@@ -0,0 +1,172 @@
#ifndef __PHYSICS_RIGIDBODY_H__
#define __PHYSICS_RIGIDBODY_H__
/*
===================================================================================
Rigid body physics
Employs an impulse based dynamic simulation which is not very accurate but
relatively fast and still reliable due to the continuous collision detection.
===================================================================================
*/
typedef struct rididBodyIState_s {
idVec3 position; // position of trace model
idMat3 orientation; // orientation of trace model
idVec3 linearMomentum; // translational momentum relative to center of mass
idVec3 angularMomentum; // rotational momentum relative to center of mass
} rigidBodyIState_t;
typedef struct rigidBodyPState_s {
int atRest; // set when simulation is suspended
float lastTimeStep; // length of last time step
idVec3 localOrigin; // origin relative to master
idMat3 localAxis; // axis relative to master
idVec6 pushVelocity; // push velocity
idVec3 externalForce; // external force relative to center of mass
idVec3 externalTorque; // external torque relative to center of mass
rigidBodyIState_t i; // state used for integration
} rigidBodyPState_t;
class idPhysics_RigidBody : public idPhysics_Base {
public:
CLASS_PROTOTYPE( idPhysics_RigidBody );
idPhysics_RigidBody( void );
~idPhysics_RigidBody( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// initialisation
void SetFriction( const float linear, const float angular, const float contact );
void SetBouncyness( const float b );
// same as above but drop to the floor first
void DropToFloor( void );
// no contact determination and contact friction
void NoContact( void );
// enable/disable activation by impact
void EnableImpact( void );
void DisableImpact( void );
public: // common physics interface
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
// RAVEN BEGIN
// bdube: means of getting center of mass
idVec3 GetCenterMass ( int id = -1 ) const;
// RAVEN END
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void AddForce( const int id, const idVec3 &point, const idVec3 &force );
void Activate( void );
void PutToRest( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated );
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
protected:
// state of the rigid body
rigidBodyPState_t current;
rigidBodyPState_t saved;
private:
// rigid body properties
float linearFriction; // translational friction
float angularFriction; // rotational friction
float contactFriction; // friction with contact surfaces
float bouncyness; // bouncyness
idClipModel * clipModel; // clip model used for collision detection
// derived properties
float mass; // mass of body
float inverseMass; // 1 / mass
idVec3 centerOfMass; // center of mass of trace model
idMat3 inertiaTensor; // mass distribution
idMat3 inverseInertiaTensor; // inverse inertia tensor
idODE * integrator; // integrator
bool dropToFloor; // true if dropping to the floor and putting to rest
bool testSolid; // true if testing for solid when dropping to the floor
bool noImpact; // if true do not activate when another object collides
bool noContact; // if true do not determine contacts and no contact friction
// master
bool hasMaster;
bool isOrientated;
private:
friend void RigidBodyDerivatives( const float t, const void *clientData, const float *state, float *derivatives );
void Integrate( const float deltaTime, rigidBodyPState_t &next );
bool CheckForCollisions( const float deltaTime, rigidBodyPState_t &next, trace_t &collision );
bool CollisionImpulse( const trace_t &collision, idVec3 &impulse );
void ContactFriction( float deltaTime );
void DropToFloorAndRest( void );
bool TestIfAtRest( void ) const;
void Rest( void );
void DebugDraw( void );
};
#endif /* !__PHYSICS_RIGIDBODY_H__ */
+882
View File
@@ -0,0 +1,882 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idPhysics, idPhysics_Static )
END_CLASS
/*
================
idPhysics_Static::idPhysics_Static
================
*/
idPhysics_Static::idPhysics_Static( void ) {
self = NULL;
clipModel = NULL;
current.origin.Zero();
current.axis.Identity();
current.localOrigin.Zero();
current.localAxis.Identity();
hasMaster = false;
isOrientated = false;
}
/*
================
idPhysics_Static::~idPhysics_Static
================
*/
idPhysics_Static::~idPhysics_Static( void ) {
if ( self && self->GetPhysics() == this ) {
self->SetPhysics( NULL );
}
idForce::DeletePhysics( this );
if ( clipModel ) {
delete clipModel;
}
}
/*
================
idPhysics_Static::Save
================
*/
void idPhysics_Static::Save( idSaveGame *savefile ) const {
savefile->WriteObject( self );
savefile->WriteVec3( current.origin );
savefile->WriteMat3( current.axis );
savefile->WriteVec3( current.localOrigin );
savefile->WriteMat3( current.localAxis );
savefile->WriteClipModel( clipModel );
savefile->WriteBool( hasMaster );
savefile->WriteBool( isOrientated );
}
/*
================
idPhysics_Static::Restore
================
*/
void idPhysics_Static::Restore( idRestoreGame *savefile ) {
savefile->ReadObject( reinterpret_cast<idClass *&>( self ) );
savefile->ReadVec3( current.origin );
savefile->ReadMat3( current.axis );
savefile->ReadVec3( current.localOrigin );
savefile->ReadMat3( current.localAxis );
savefile->ReadClipModel( clipModel );
savefile->ReadBool( hasMaster );
savefile->ReadBool( isOrientated );
}
/*
================
idPhysics_Static::SetSelf
================
*/
void idPhysics_Static::SetSelf( idEntity *e ) {
assert( e );
self = e;
}
/*
================
idPhysics_Static::SetClipModel
================
*/
void idPhysics_Static::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) {
assert( self );
if ( clipModel && clipModel != model && freeOld ) {
delete clipModel;
}
clipModel = model;
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::GetClipModel
================
*/
idClipModel *idPhysics_Static::GetClipModel( int id ) const {
if ( clipModel ) {
return clipModel;
}
// RAVEN BEGIN
// ddynerman: multiple clip worlds
return idClip::DefaultClipModel();
// RAVEN END
}
/*
================
idPhysics_Static::GetNumClipModels
================
*/
int idPhysics_Static::GetNumClipModels( void ) const {
return ( clipModel != NULL );
}
/*
================
idPhysics_Static::SetMass
================
*/
void idPhysics_Static::SetMass( float mass, int id ) {
}
/*
================
idPhysics_Static::GetMass
================
*/
float idPhysics_Static::GetMass( int id ) const {
return 0.0f;
}
// RAVEN BEGIN
// bdube: Added center mass call
/*
================
idPhysics_Static::GetCenterMass
default center of mass is origin
================
*/
idVec3 idPhysics_Static::GetCenterMass ( int id ) const {
return GetOrigin();
}
// RAVEN END
/*
================
idPhysics_Static::SetContents
================
*/
void idPhysics_Static::SetContents( int contents, int id ) {
if ( clipModel ) {
clipModel->SetContents( contents );
}
}
/*
================
idPhysics_Static::GetContents
================
*/
int idPhysics_Static::GetContents( int id ) const {
if ( clipModel ) {
return clipModel->GetContents();
}
return 0;
}
/*
================
idPhysics_Static::SetClipMask
================
*/
void idPhysics_Static::SetClipMask( int mask, int id ) {
}
/*
================
idPhysics_Static::GetClipMask
================
*/
int idPhysics_Static::GetClipMask( int id ) const {
return 0;
}
/*
================
idPhysics_Static::GetBounds
================
*/
const idBounds &idPhysics_Static::GetBounds( int id ) const {
if ( clipModel ) {
return clipModel->GetBounds();
}
return bounds_zero;
}
/*
================
idPhysics_Static::GetAbsBounds
================
*/
const idBounds &idPhysics_Static::GetAbsBounds( int id ) const {
static idBounds absBounds;
if ( clipModel ) {
return clipModel->GetAbsBounds();
}
absBounds[0] = absBounds[1] = current.origin;
return absBounds;
}
/*
================
idPhysics_Static::Evaluate
================
*/
bool idPhysics_Static::Evaluate( int timeStepMSec, int endTimeMSec ) {
// RAVEN BEGIN
// bdube: draw bbox
if ( hasMaster ) {
idVec3 masterOrigin;
idVec3 oldOrigin;
idMat3 masterAxis;
idMat3 oldAxis;
// RAVEN END
oldOrigin = current.origin;
oldAxis = current.axis;
self->GetMasterPosition( masterOrigin, masterAxis );
current.origin = masterOrigin + current.localOrigin * masterAxis;
if ( isOrientated ) {
current.axis = current.localAxis * masterAxis;
} else {
current.axis = current.localAxis;
}
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
return ( current.origin != oldOrigin || current.axis != oldAxis );
}
return false;
}
/*
================
idPhysics_Static::UpdateTime
================
*/
void idPhysics_Static::UpdateTime( int endTimeMSec ) {
}
/*
================
idPhysics_Static::GetTime
================
*/
int idPhysics_Static::GetTime( void ) const {
return 0;
}
/*
================
idPhysics_Static::GetImpactInfo
================
*/
void idPhysics_Static::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
memset( info, 0, sizeof( *info ) );
}
/*
================
idPhysics_Static::ApplyImpulse
================
*/
void idPhysics_Static::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
}
/*
================
idPhysics_Static::AddForce
================
*/
void idPhysics_Static::AddForce( const int id, const idVec3 &point, const idVec3 &force ) {
}
/*
================
idPhysics_Static::Activate
================
*/
void idPhysics_Static::Activate( void ) {
}
/*
================
idPhysics_Static::PutToRest
================
*/
void idPhysics_Static::PutToRest( void ) {
}
/*
================
idPhysics_Static::IsAtRest
================
*/
bool idPhysics_Static::IsAtRest( void ) const {
return true;
}
/*
================
idPhysics_Static::GetRestStartTime
================
*/
int idPhysics_Static::GetRestStartTime( void ) const {
return 0;
}
/*
================
idPhysics_Static::IsPushable
================
*/
bool idPhysics_Static::IsPushable( void ) const {
return false;
}
// RAVEN BEGIN
// bdube: water interraction
/*
================
idPhysics_Static::IsInWater
================
*/
bool idPhysics_Static::IsInWater ( void ) const {
return false;
}
// RAVEN END
/*
================
idPhysics_Static::SaveState
================
*/
void idPhysics_Static::SaveState( void ) {
}
/*
================
idPhysics_Static::RestoreState
================
*/
void idPhysics_Static::RestoreState( void ) {
}
/*
================
idPhysics_Static::SetOrigin
================
*/
void idPhysics_Static::SetOrigin( const idVec3 &newOrigin, int id ) {
idVec3 masterOrigin;
idMat3 masterAxis;
current.localOrigin = newOrigin;
if ( hasMaster ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.origin = masterOrigin + newOrigin * masterAxis;
} else {
current.origin = newOrigin;
}
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::SetAxis
================
*/
void idPhysics_Static::SetAxis( const idMat3 &newAxis, int id ) {
idVec3 masterOrigin;
idMat3 masterAxis;
current.localAxis = newAxis;
if ( hasMaster && isOrientated ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.axis = newAxis * masterAxis;
} else {
current.axis = newAxis;
}
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::Translate
================
*/
void idPhysics_Static::Translate( const idVec3 &translation, int id ) {
current.localOrigin += translation;
current.origin += translation;
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::Rotate
================
*/
void idPhysics_Static::Rotate( const idRotation &rotation, int id ) {
idVec3 masterOrigin;
idMat3 masterAxis;
current.origin *= rotation;
current.axis *= rotation.ToMat3();
if ( hasMaster ) {
self->GetMasterPosition( masterOrigin, masterAxis );
current.localAxis *= rotation.ToMat3();
current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
} else {
current.localAxis = current.axis;
current.localOrigin = current.origin;
}
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::GetOrigin
================
*/
const idVec3 &idPhysics_Static::GetOrigin( int id ) const {
return current.origin;
}
/*
================
idPhysics_Static::GetAxis
================
*/
const idMat3 &idPhysics_Static::GetAxis( int id ) const {
return current.axis;
}
/*
================
idPhysics_Static::SetLinearVelocity
================
*/
void idPhysics_Static::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
}
/*
================
idPhysics_Static::SetAngularVelocity
================
*/
void idPhysics_Static::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) {
}
/*
================
idPhysics_Static::GetLinearVelocity
================
*/
const idVec3 &idPhysics_Static::GetLinearVelocity( int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Static::GetAngularVelocity
================
*/
const idVec3 &idPhysics_Static::GetAngularVelocity( int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Static::SetGravity
================
*/
void idPhysics_Static::SetGravity( const idVec3 &newGravity ) {
}
/*
================
idPhysics_Static::GetGravity
================
*/
const idVec3 &idPhysics_Static::GetGravity( void ) const {
static idVec3 gravity( 0, 0, -g_gravity.GetFloat() );
if( gameLocal.isMultiplayer ) {
gravity = idVec3( 0, 0, -g_mp_gravity.GetFloat() );
}
return gravity;
}
/*
================
idPhysics_Static::GetGravityNormal
================
*/
const idVec3 &idPhysics_Static::GetGravityNormal( void ) const {
static idVec3 gravity( 0, 0, -1 );
return gravity;
}
/*
================
idPhysics_Static::ClipTranslation
================
*/
void idPhysics_Static::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.TranslationModel( self, results, current.origin, current.origin + translation,
clipModel, current.axis, MASK_SOLID, model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
} else {
gameLocal.Translation( self, results, current.origin, current.origin + translation,
clipModel, current.axis, MASK_SOLID, self );
// RAVEN END
}
}
/*
================
idPhysics_Static::ClipRotation
================
*/
void idPhysics_Static::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
gameLocal.RotationModel( self, results, current.origin, rotation,
clipModel, current.axis, MASK_SOLID, model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
} else {
gameLocal.Rotation( self, results, current.origin, rotation, clipModel, current.axis, MASK_SOLID, self );
}
// RAVEN END
}
/*
================
idPhysics_Static::ClipContents
================
*/
int idPhysics_Static::ClipContents( const idClipModel *model ) const {
if ( clipModel ) {
if ( model ) {
// RAVEN BEGIN
// ddynerman: multiple collision worlds
return gameLocal.ContentsModel( self, clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1,
model->GetCollisionModel(), model->GetOrigin(), model->GetAxis() );
} else {
return gameLocal.Contents( self, clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL );
// RAVEN END
}
}
return 0;
}
/*
================
idPhysics_Static::DisableClip
================
*/
void idPhysics_Static::DisableClip( void ) {
if ( clipModel ) {
clipModel->Disable();
}
}
/*
================
idPhysics_Static::EnableClip
================
*/
void idPhysics_Static::EnableClip( void ) {
if ( clipModel ) {
clipModel->Enable();
}
}
/*
================
idPhysics_Static::UnlinkClip
================
*/
void idPhysics_Static::UnlinkClip( void ) {
if ( clipModel ) {
clipModel->Unlink();
}
}
/*
================
idPhysics_Static::LinkClip
================
*/
void idPhysics_Static::LinkClip( void ) {
if ( clipModel ) {
// RAVEN BEGIN
// ddynerman: multiple clip worlds
clipModel->Link( self, 0, current.origin, current.axis );
// RAVEN END
}
}
/*
================
idPhysics_Static::EvaluateContacts
================
*/
bool idPhysics_Static::EvaluateContacts( void ) {
return false;
}
/*
================
idPhysics_Static::GetNumContacts
================
*/
int idPhysics_Static::GetNumContacts( void ) const {
return 0;
}
/*
================
idPhysics_Static::GetContact
================
*/
const contactInfo_t &idPhysics_Static::GetContact( int num ) const {
static contactInfo_t info;
memset( &info, 0, sizeof( info ) );
return info;
}
/*
================
idPhysics_Static::ClearContacts
================
*/
void idPhysics_Static::ClearContacts( void ) {
}
/*
================
idPhysics_Static::AddContactEntity
================
*/
void idPhysics_Static::AddContactEntity( idEntity *e ) {
}
/*
================
idPhysics_Static::RemoveContactEntity
================
*/
void idPhysics_Static::RemoveContactEntity( idEntity *e ) {
}
/*
================
idPhysics_Static::HasGroundContacts
================
*/
bool idPhysics_Static::HasGroundContacts( void ) const {
return false;
}
/*
================
idPhysics_Static::IsGroundEntity
================
*/
bool idPhysics_Static::IsGroundEntity( int entityNum ) const {
return false;
}
/*
================
idPhysics_Static::IsGroundClipModel
================
*/
bool idPhysics_Static::IsGroundClipModel( int entityNum, int id ) const {
return false;
}
/*
================
idPhysics_Static::SetPushed
================
*/
void idPhysics_Static::SetPushed( int deltaTime ) {
}
/*
================
idPhysics_Static::GetPushedLinearVelocity
================
*/
const idVec3 &idPhysics_Static::GetPushedLinearVelocity( const int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Static::GetPushedAngularVelocity
================
*/
const idVec3 &idPhysics_Static::GetPushedAngularVelocity( const int id ) const {
return vec3_origin;
}
/*
================
idPhysics_Static::SetMaster
================
*/
void idPhysics_Static::SetMaster( idEntity *master, const bool orientated ) {
idVec3 masterOrigin;
idMat3 masterAxis;
if ( master ) {
if ( !hasMaster ) {
// transform from world space to master space
self->GetMasterPosition( masterOrigin, masterAxis );
current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose();
if ( orientated ) {
current.localAxis = current.axis * masterAxis.Transpose();
} else {
current.localAxis = current.axis;
}
hasMaster = true;
isOrientated = orientated;
}
} else {
if ( hasMaster ) {
hasMaster = false;
}
}
}
/*
================
idPhysics_Static::GetBlockingInfo
================
*/
const trace_t *idPhysics_Static::GetBlockingInfo( void ) const {
return NULL;
}
/*
================
idPhysics_Static::GetBlockingEntity
================
*/
idEntity *idPhysics_Static::GetBlockingEntity( void ) const {
return NULL;
}
/*
================
idPhysics_Static::GetLinearEndTime
================
*/
int idPhysics_Static::GetLinearEndTime( void ) const {
return 0;
}
/*
================
idPhysics_Static::GetAngularEndTime
================
*/
int idPhysics_Static::GetAngularEndTime( void ) const {
return 0;
}
/*
================
idPhysics_Static::WriteToSnapshot
================
*/
void idPhysics_Static::WriteToSnapshot( idBitMsgDelta &msg ) const {
idCQuat quat, localQuat;
quat = current.axis.ToCQuat();
localQuat = current.localAxis.ToCQuat();
msg.WriteFloat( current.origin[0] );
msg.WriteFloat( current.origin[1] );
msg.WriteFloat( current.origin[2] );
msg.WriteFloat( quat.x );
msg.WriteFloat( quat.y );
msg.WriteFloat( quat.z );
msg.WriteDeltaFloat( current.origin[0], current.localOrigin[0] );
msg.WriteDeltaFloat( current.origin[1], current.localOrigin[1] );
msg.WriteDeltaFloat( current.origin[2], current.localOrigin[2] );
msg.WriteDeltaFloat( quat.x, localQuat.x );
msg.WriteDeltaFloat( quat.y, localQuat.y );
msg.WriteDeltaFloat( quat.z, localQuat.z );
}
/*
================
idPhysics_Base::ReadFromSnapshot
================
*/
void idPhysics_Static::ReadFromSnapshot( const idBitMsgDelta &msg ) {
idCQuat quat, localQuat;
current.origin[0] = msg.ReadFloat();
current.origin[1] = msg.ReadFloat();
current.origin[2] = msg.ReadFloat();
quat.x = msg.ReadFloat();
quat.y = msg.ReadFloat();
quat.z = msg.ReadFloat();
current.localOrigin[0] = msg.ReadDeltaFloat( current.origin[0] );
current.localOrigin[1] = msg.ReadDeltaFloat( current.origin[1] );
current.localOrigin[2] = msg.ReadDeltaFloat( current.origin[2] );
localQuat.x = msg.ReadDeltaFloat( quat.x );
localQuat.y = msg.ReadDeltaFloat( quat.y );
localQuat.z = msg.ReadDeltaFloat( quat.z );
current.axis = quat.ToMat3();
current.localAxis = localQuat.ToMat3();
}
+155
View File
@@ -0,0 +1,155 @@
#ifndef __PHYSICS_STATIC_H__
#define __PHYSICS_STATIC_H__
/*
===============================================================================
Physics for a non moving object using at most one collision model.
===============================================================================
*/
// RAVEN BEGIN
// rjohnson: converted this from a struct to a class
class idStaticPState {
public:
idVec3 origin;
idMat3 axis;
idVec3 localOrigin;
idMat3 localAxis;
idStaticPState( void ) { }
};
// RAVEN END
class idPhysics_Static : public idPhysics {
public:
CLASS_PROTOTYPE( idPhysics_Static );
idPhysics_Static( void );
~idPhysics_Static( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public: // common physics interface
void SetSelf( idEntity *e );
//RAVEN BEGIN
// abahr: for gravity
virtual idEntity* GetSelf() const { return self; }
// RAVEN END
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
// RAVEN BEGIN
// bdube: means of getting center of mass
idVec3 GetCenterMass( int id = -1 ) const;
// RAVEN END
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
void SetClipMask( int mask, int id = -1 );
int GetClipMask( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void AddForce( const int id, const idVec3 &point, const idVec3 &force );
void Activate( void );
void PutToRest( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
// RAVEN BEGIN
// bdube: water interraction
bool IsInWater ( void ) const;
// RAVEN END
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void SetGravity( const idVec3 &newGravity );
const idVec3 & GetGravity( void ) const;
const idVec3 & GetGravityNormal( void ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
int GetNumContacts( void ) const;
const contactInfo_t & GetContact( int num ) const;
void ClearContacts( void );
void AddContactEntity( idEntity *e );
void RemoveContactEntity( idEntity *e );
bool HasGroundContacts( void ) const;
bool IsGroundEntity( int entityNum ) const;
bool IsGroundClipModel( int entityNum, int id ) const;
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated = true );
const trace_t * GetBlockingInfo( void ) const;
idEntity * GetBlockingEntity( void ) const;
int GetLinearEndTime( void ) const;
int GetAngularEndTime( void ) const;
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
protected:
idEntity * self; // entity using this physics object
// RAVEN BEGIN
// rjohnson: converted this from a struct to a class
idStaticPState current; // physics state
// RAVEN END
idClipModel * clipModel; // collision model
// master
bool hasMaster;
bool isOrientated;
};
#endif /* !__PHYSICS_STATIC_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,143 @@
#ifndef __PHYSICS_STATICMULTI_H__
#define __PHYSICS_STATICMULTI_H__
/*
===============================================================================
Physics for a non moving object using no or multiple collision models.
===============================================================================
*/
class idPhysics_StaticMulti : public idPhysics {
public:
CLASS_PROTOTYPE( idPhysics_StaticMulti );
idPhysics_StaticMulti( void );
~idPhysics_StaticMulti( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
void RemoveIndex( int id = 0, bool freeClipModel = true );
public: // common physics interface
void SetSelf( idEntity *e );
//RAVEN BEGIN
// abahr: for gravity
virtual idEntity* GetSelf() const { return self; }
// RAVEN END
void SetClipModel( idClipModel *model, float density, int id = 0, bool freeOld = true );
idClipModel * GetClipModel( int id = 0 ) const;
int GetNumClipModels( void ) const;
void SetMass( float mass, int id = -1 );
float GetMass( int id = -1 ) const;
// RAVEN BEGIN
// bdube: means of getting center of mass
idVec3 GetCenterMass( int id = -1 ) const;
// RAVEN END
void SetContents( int contents, int id = -1 );
int GetContents( int id = -1 ) const;
void SetClipMask( int mask, int id = -1 );
int GetClipMask( int id = -1 ) const;
const idBounds & GetBounds( int id = -1 ) const;
const idBounds & GetAbsBounds( int id = -1 ) const;
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
int GetTime( void ) const;
void GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const;
void ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse );
void AddForce( const int id, const idVec3 &point, const idVec3 &force );
void Activate( void );
void PutToRest( void );
bool IsAtRest( void ) const;
int GetRestStartTime( void ) const;
bool IsPushable( void ) const;
// RAVEN BEGIN
// bdube: water interraction
bool IsInWater ( void ) const;
// RAVEN END
void SaveState( void );
void RestoreState( void );
void SetOrigin( const idVec3 &newOrigin, int id = -1 );
void SetAxis( const idMat3 &newAxis, int id = -1 );
void Translate( const idVec3 &translation, int id = -1 );
void Rotate( const idRotation &rotation, int id = -1 );
const idVec3 & GetOrigin( int id = 0 ) const;
const idMat3 & GetAxis( int id = 0 ) const;
void SetLinearVelocity( const idVec3 &newLinearVelocity, int id = 0 );
void SetAngularVelocity( const idVec3 &newAngularVelocity, int id = 0 );
const idVec3 & GetLinearVelocity( int id = 0 ) const;
const idVec3 & GetAngularVelocity( int id = 0 ) const;
void SetGravity( const idVec3 &newGravity );
const idVec3 & GetGravity( void ) const;
const idVec3 & GetGravityNormal( void ) const;
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
void DisableClip( void );
void EnableClip( void );
void UnlinkClip( void );
void LinkClip( void );
bool EvaluateContacts( void );
int GetNumContacts( void ) const;
const contactInfo_t & GetContact( int num ) const;
void ClearContacts( void );
void AddContactEntity( idEntity *e );
void RemoveContactEntity( idEntity *e );
bool HasGroundContacts( void ) const;
bool IsGroundEntity( int entityNum ) const;
bool IsGroundClipModel( int entityNum, int id ) const;
void SetPushed( int deltaTime );
const idVec3 & GetPushedLinearVelocity( const int id = 0 ) const;
const idVec3 & GetPushedAngularVelocity( const int id = 0 ) const;
void SetMaster( idEntity *master, const bool orientated = true );
const trace_t * GetBlockingInfo( void ) const;
idEntity * GetBlockingEntity( void ) const;
int GetLinearEndTime( void ) const;
int GetAngularEndTime( void ) const;
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
protected:
idEntity * self; // entity using this physics object
// RAVEN BEGIN
// rjohnson: converted this from a struct to a class
idList<idStaticPState> current; // physics state
// RAVEN END
idList<idClipModel *> clipModels; // collision model
// master
bool hasMaster;
bool isOrientated;
};
#endif /* !__PHYSICS_STATICMULTI_H__ */
@@ -0,0 +1,37 @@
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idPhysics_RigidBody, rvPhysics_VehicleMonster )
END_CLASS
/*
================
rvPhysics_VehicleMonster::Evaluate
Evaluate the impulse based rigid body physics.
When a collision occurs an impulse is applied at the moment of impact but
the remaining time after the collision is ignored.
================
*/
bool rvPhysics_VehicleMonster::Evaluate( int timeStepMSec, int endTimeMSec ) {
if ( idPhysics_RigidBody::Evaluate( timeStepMSec, endTimeMSec ) ) {
idAngles euler = current.i.orientation.ToAngles();
euler.pitch = 0.0f;
euler.roll = 0.0f;
current.i.orientation = euler.ToMat3();
return true;
}
return false;
}
void rvPhysics_VehicleMonster::SetGravity ( const idVec3 & v ) {
gravityVector = v;
gravityNormal = gameLocal.GetGravity( );
gravityNormal.Normalize();
}
@@ -0,0 +1,25 @@
#ifndef __PHYSICS_VEHICLE_MONSTER_H__
#define __PHYSICS_VEHICLE_MONSTER_H__
/*
===================================================================================
Vehicle Monster Physics
Employs an impulse based dynamic simulation which is not very accurate but
relatively fast and still reliable due to the continuous collision detection.
Extents particle physics with the ability to apply impulses.
===================================================================================
*/
class rvPhysics_VehicleMonster : public idPhysics_RigidBody {
public:
CLASS_PROTOTYPE( rvPhysics_VehicleMonster );
bool Evaluate ( int timeStepMSec, int endTimeMSec );
void SetGravity ( const idVec3 & v );
};
#endif /* !__PHYSICS_VEHICLE_MONSTER_H__ */
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
#ifndef __PUSH_H__
#define __PUSH_H__
/*
===============================================================================
Allows physics objects to be pushed geometrically.
===============================================================================
*/
#define PUSHFL_ONLYMOVEABLE 1 // only push moveable entities
#define PUSHFL_NOGROUNDENTITIES 2 // don't push entities the clip model rests upon
#define PUSHFL_CLIP 4 // also clip against all non-moveable entities
#define PUSHFL_CRUSH 8 // kill blocking entities
#define PUSHFL_APPLYIMPULSE 16 // apply impulse to pushed entities
//#define NEW_PUSH
class idPush {
public:
// Try to push other entities by moving the given entity.
// If results.fraction < 1.0 the move was blocked by results.c.entityNum
// Returns total mass of all pushed entities.
float ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags,
const idVec3 &newOrigin, const idVec3 &move );
float ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
const idMat3 &newAxis, const idRotation &rotation );
float ClipPush( trace_t &results, idEntity *pusher, const int flags,
const idVec3 &oldOrigin, const idMat3 &oldAxis,
idVec3 &newOrigin, idMat3 &newAxis );
// initialize saving the positions of entities being pushed
void InitSavingPushedEntityPositions( void );
// move all pushed entities back to their previous position
void RestorePushedEntityPositions( void );
// returns the number of pushed entities
int GetNumPushedEntities( void ) const { return numPushed; }
// get the ith pushed entity
idEntity * GetPushedEntity( int i ) const { assert( i >= 0 && i < numPushed ); return pushed[i].ent; }
private:
struct pushed_s {
idEntity * ent; // pushed entity
idAngles deltaViewAngles; // actor delta view angles
} pushed[MAX_GENTITIES]; // pushed entities
int numPushed; // number of pushed entities
struct pushedGroup_s {
idEntity * ent;
float fraction;
bool groundContact;
bool test;
} pushedGroup[MAX_GENTITIES];
int pushedGroupSize;
private:
void SaveEntityPosition( idEntity *ent );
bool RotateEntityToAxial( idEntity *ent, idVec3 rotationPoint );
#ifdef NEW_PUSH
bool CanPushEntity( idEntity *ent, idEntity *pusher, idEntity *initialPusher, const int flags );
void AddEntityToPushedGroup( idEntity *ent, float fraction, bool groundContact );
bool IsFullyPushed( idEntity *ent );
bool ClipTranslationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idVec3 &translation );
int GetPushableEntitiesForTranslation( idEntity *pusher, idEntity *initialPusher, const int flags,
const idVec3 &translation, idEntity *entityList[], int maxEntities );
bool ClipRotationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idRotation &rotation );
int GetPushableEntitiesForRotation( idEntity *pusher, idEntity *initialPusher, const int flags,
const idRotation &rotation, idEntity *entityList[], int maxEntities );
#else
void ClipEntityRotation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel,
idClipModel *skip, const idRotation &rotation );
void ClipEntityTranslation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel,
idClipModel *skip, const idVec3 &translation );
int TryTranslatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags,
const idVec3 &newOrigin, const idVec3 &move );
int TryRotatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags,
const idMat3 &newAxis, const idRotation &rotation );
int DiscardEntities( idEntity *entityList[], int numEntities, int flags, idEntity *pusher );
#endif
};
#endif /* !__PUSH_H__ */