dhewm3-sdk/d3xp/physics/Physics_AF.h
dhewg afebd7e1e5 Untangle the epic precompiled.h mess
Don't include the lazy precompiled.h everywhere, only what's
required for the compilation unit.
platform.h needs to be included instead to provide all essential
defines and types.
All includes use the relative path to the neo or the game
specific root.
Move all idlib related includes from idlib/Lib.h to precompiled.h.
precompiled.h still exists for the MFC stuff in tools/.
Add some missing header guards.
2018-08-20 01:46:28 +02:00

1051 lines
44 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __PHYSICS_AF_H__
#define __PHYSICS_AF_H__
#include "idlib/math/Lcp.h"
#include "physics/Physics_Base.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 idAFConstraint_Suspension;
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,
CONSTRAINT_SUSPENSION
} 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 );
};
// vehicle suspension
class idAFConstraint_Suspension : public idAFConstraint {
public:
idAFConstraint_Suspension( void );
void Setup( const char *name, idAFBody *body, const idVec3 &origin, const idMat3 &axis, idClipModel *clipModel );
void SetSuspension( const float up, const float down, const float k, const float d, const float f );
void SetSteerAngle( const float degrees ) { steerAngle = degrees; }
void EnableMotor( const bool enable ) { motorEnabled = enable; }
void SetMotorForce( const float force ) { motorForce = force; }
void SetMotorVelocity( const float vel ) { motorVelocity = vel; }
void SetEpsilon( const float e ) { epsilon = e; }
const idVec3 GetWheelOrigin( void ) const;
virtual void DebugDraw( void );
virtual void Translate( const idVec3 &translation );
virtual void Rotate( const idRotation &rotation );
protected:
idVec3 localOrigin; // position of suspension relative to body1
idMat3 localAxis; // orientation of suspension relative to body1
float suspensionUp; // suspension up movement
float suspensionDown; // suspension down movement
float suspensionKCompress; // spring compress constant
float suspensionDamping; // spring damping
float steerAngle; // desired steer angle in degrees
float friction; // friction
bool motorEnabled; // whether the motor is enabled or not
float motorForce; // motor force
float motorVelocity; // desired velocity
idClipModel * wheelModel; // wheel model
idVec3 wheelOffset; // wheel position relative to body1
trace_t trace; // contact point with the ground
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; }
// 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;
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
// 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__ */