2017-04-18 11:12:17 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program 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 2
of the License , or ( at your option ) any later version .
This program 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 this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
//if we're not building as an fte-specific plugin, we must be being built as part of the fte engine itself.
//(no, we don't want to act as a plugin for ezquake...)
# ifndef FTEPLUGIN
# define FTEENGINE
# define FTEPLUGIN
# define pCvar_Register Cvar_Get
# define pCvar_GetFloat(x) Cvar_FindVar(x)->value
# define pSys_Error Sys_Error
# define Plug_Init Plug_Bullet_Init
# pragma comment(lib,".. / .. / plugins / bullet / libs / bullet_dbg.lib")
# endif
# include "../plugin.h"
# include "../engine.h"
# include "pr_common.h"
# include "com_mesh.h"
# ifndef FTEENGINE
# define BZ_Malloc malloc
# define BZ_Free free
# define Z_Free BZ_Free
static vec3_t vec3_origin ;
static int VectorCompare ( const vec3_t v1 , const vec3_t v2 )
{
int i ;
for ( i = 0 ; i < 3 ; i + + )
if ( v1 [ i ] ! = v2 [ i ] )
return 0 ;
return 1 ;
}
# endif
static rbeplugfuncs_t * rbefuncs ;
//============================================================================
// physics engine support
//============================================================================
# define DEG2RAD(d) (d * M_PI * (1 / 180.0f))
# define RAD2DEG(d) ((d*180) / M_PI)
# include <btBulletDynamicsCommon.h>
static void World_Bullet_RunCmd ( world_t * world , rbecommandqueue_t * cmd ) ;
2017-12-09 21:22:46 +00:00
static cvar_t * physics_bullet_enable ;
static cvar_t * physics_bullet_maxiterationsperframe ;
static cvar_t * physics_bullet_framerate ;
static cvar_t * pr_meshpitch ;
2017-04-18 11:12:17 +00:00
void World_Bullet_Init ( void )
{
2017-12-09 21:22:46 +00:00
physics_bullet_enable = pCvar_GetNVFDG ( " physics_bullet_enable " , " 1 " , 0 , " " , " Bullet " ) ;
physics_bullet_maxiterationsperframe = pCvar_GetNVFDG ( " physics_bullet_maxiterationsperframe " , " 10 " , 0 , " FIXME: should be 1 when CCD is working properly. " , " Bullet " ) ;
physics_bullet_framerate = pCvar_GetNVFDG ( " physics_bullet_framerate " , " 60 " , 0 , " " , " Bullet " ) ;
pr_meshpitch = pCvar_GetNVFDG ( " r_meshpitch " , " -1 " , 0 , " " , " Bullet " ) ;
2017-04-18 11:12:17 +00:00
}
void World_Bullet_Shutdown ( void )
{
}
typedef struct bulletcontext_s
{
rigidbodyengine_t funcs ;
qboolean hasextraobjs ;
// void *ode_space;
// void *ode_contactgroup;
// number of constraint solver iterations to use (for dWorldStepFast)
// int ode_iterations;
// actual step (server frametime / ode_iterations)
// vec_t ode_step;
// max velocity for a 1-unit radius object at current step to prevent
// missed collisions
// vec_t ode_movelimit;
rbecommandqueue_t * cmdqueuehead ;
rbecommandqueue_t * cmdqueuetail ;
world_t * gworld ;
btBroadphaseInterface * broadphase ;
btDefaultCollisionConfiguration * collisionconfig ;
btCollisionDispatcher * collisiondispatcher ;
btSequentialImpulseConstraintSolver * solver ;
btDiscreteDynamicsWorld * dworld ;
btOverlapFilterCallback * ownerfilter ;
} bulletcontext_t ;
class QCFilterCallback : public btOverlapFilterCallback
{
// return true when pairs need collision
virtual bool needBroadphaseCollision ( btBroadphaseProxy * proxy0 , btBroadphaseProxy * proxy1 ) const
{
//dimensions don't collide
bool collides = ( proxy0 - > m_collisionFilterGroup & proxy1 - > m_collisionFilterMask ) ! = 0 ;
collides = collides & & ( proxy1 - > m_collisionFilterGroup & proxy0 - > m_collisionFilterMask ) ;
//owners don't collide (unless one is world, obviouslyish)
if ( collides )
{
btRigidBody * b1 = ( btRigidBody * ) proxy0 - > m_clientObject ;
btRigidBody * b2 = ( btRigidBody * ) proxy1 - > m_clientObject ;
//don't let two qc-controlled entities collide in Bullet, that's the job of quake.
if ( b1 - > isStaticOrKinematicObject ( ) & & b2 - > isStaticOrKinematicObject ( ) )
return false ;
wedict_t * e1 = ( wedict_t * ) b1 - > getUserPointer ( ) ;
wedict_t * e2 = ( wedict_t * ) b2 - > getUserPointer ( ) ;
if ( ( e1 - > v - > solid = = SOLID_TRIGGER & & e2 - > v - > solid ! = SOLID_BSP ) | |
( e2 - > v - > solid = = SOLID_TRIGGER & & e1 - > v - > solid ! = SOLID_BSP ) )
return false ; //triggers only collide with bsp objects.
if ( e1 - > entnum & & e2 - > entnum )
collides = e1 - > v - > owner ! = e2 - > entnum & & e2 - > v - > owner ! = e1 - > entnum ;
}
return collides ;
}
} ;
static void QDECL World_Bullet_End ( world_t * world )
{
struct bulletcontext_s * ctx = ( struct bulletcontext_s * ) world - > rbe ;
world - > rbe = NULL ;
delete ctx - > dworld ;
delete ctx - > solver ;
delete ctx - > collisionconfig ;
delete ctx - > collisiondispatcher ;
delete ctx - > broadphase ;
delete ctx - > ownerfilter ;
Z_Free ( ctx ) ;
}
static void QDECL World_Bullet_RemoveJointFromEntity ( world_t * world , wedict_t * ed )
{
ed - > ode . ode_joint_type = 0 ;
// if(ed->ode.ode_joint)
// dJointDestroy((dJointID)ed->ode.ode_joint);
ed - > ode . ode_joint = NULL ;
}
static void QDECL World_Bullet_RemoveFromEntity ( world_t * world , wedict_t * ed )
{
struct bulletcontext_s * ctx = ( struct bulletcontext_s * ) world - > rbe ;
btRigidBody * body ;
btCollisionShape * geom ;
if ( ! ed - > ode . ode_physics )
return ;
// entity is not physics controlled, free any physics data
ed - > ode . ode_physics = qfalse ;
body = ( btRigidBody * ) ed - > ode . ode_body ;
ed - > ode . ode_body = NULL ;
if ( body )
ctx - > dworld - > removeRigidBody ( body ) ;
geom = ( btCollisionShape * ) ed - > ode . ode_geom ;
ed - > ode . ode_geom = NULL ;
if ( ed - > ode . ode_geom )
delete geom ;
//FIXME: joints
rbefuncs - > ReleaseCollisionMesh ( ed ) ;
if ( ed - > ode . ode_massbuf )
BZ_Free ( ed - > ode . ode_massbuf ) ;
ed - > ode . ode_massbuf = NULL ;
}
static void World_Bullet_Frame_BodyToEntity ( world_t * world , wedict_t * ed )
{
return ;
#if 0
model_t * model ;
const float * avel ;
const float * o ;
const float * r ; // for some reason dBodyGetRotation returns a [3][4] matrix
const float * vel ;
btRigidBody * body = ( btRigidBody * ) ed - > ode . ode_body ;
int movetype ;
float bodymatrix [ 16 ] ;
float entitymatrix [ 16 ] ;
vec3_t angles ;
vec3_t avelocity ;
vec3_t forward , left , up ;
vec3_t origin ;
vec3_t spinvelocity ;
vec3_t velocity ;
if ( ! body )
return ;
movetype = ( int ) ed - > v - > movetype ;
if ( movetype ! = MOVETYPE_PHYSICS )
{
switch ( ( int ) ed - > xv - > jointtype )
{
// TODO feed back data from physics
case JOINTTYPE_POINT :
break ;
case JOINTTYPE_HINGE :
break ;
case JOINTTYPE_SLIDER :
break ;
case JOINTTYPE_UNIVERSAL :
break ;
case JOINTTYPE_HINGE2 :
break ;
case JOINTTYPE_FIXED :
break ;
}
return ;
}
// store the physics engine data into the entity
btTransform trans ;
body - > getMotionState ( ) - > getWorldTransform ( trans ) ;
// o = dBodyGetPosition(body);
// r = dBodyGetRotation(body);
// vel = dBodyGetLinearVel(body);
// avel = dBodyGetAngularVel(body);
// VectorCopy(o, origin);
// forward[0] = r[0];
// forward[1] = r[4];
// forward[2] = r[8];
// left[0] = r[1];
// left[1] = r[5];
// left[2] = r[9];
// up[0] = r[2];
// up[1] = r[6];
// up[2] = r[10];
vel = body - > getLinearVelocity ( ) ;
avel = body - > getAngularVelocity ( ) ;
VectorCopy ( vel , velocity ) ;
VectorCopy ( avel , spinvelocity ) ;
trans . getBasis ( ) . getOpenGLSubMatrix ( bodymatrix ) ;
foo Matrix4x4_RM_FromVectors ( bodymatrix , forward , left , up , origin ) ;
foo Matrix4_Multiply ( ed - > ode . ode_offsetimatrix , bodymatrix , entitymatrix ) ;
foo Matrix3x4_RM_ToVectors ( entitymatrix , forward , left , up , origin ) ;
VectorAngles ( forward , up , angles ) ;
angles [ 0 ] * = - 1 ;
avelocity [ PITCH ] = RAD2DEG ( spinvelocity [ PITCH ] ) ;
avelocity [ YAW ] = RAD2DEG ( spinvelocity [ ROLL ] ) ;
avelocity [ ROLL ] = RAD2DEG ( spinvelocity [ YAW ] ) ;
if ( ed - > v - > modelindex )
{
model = world - > Get_CModel ( world , ed - > v - > modelindex ) ;
if ( ! model | | model - > type = = mod_alias )
{
angles [ PITCH ] * = - 1 ;
avelocity [ PITCH ] * = - 1 ;
}
}
VectorCopy ( origin , ed - > v - > origin ) ;
VectorCopy ( velocity , ed - > v - > velocity ) ;
//VectorCopy(forward, ed->xv->axis_forward);
//VectorCopy(left, ed->xv->axis_left);
//VectorCopy(up, ed->xv->axis_up);
//VectorCopy(spinvelocity, ed->xv->spinvelocity);
VectorCopy ( angles , ed - > v - > angles ) ;
VectorCopy ( avelocity , ed - > v - > avelocity ) ;
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy ( origin , ed - > ode . ode_origin ) ;
VectorCopy ( velocity , ed - > ode . ode_velocity ) ;
VectorCopy ( angles , ed - > ode . ode_angles ) ;
VectorCopy ( avelocity , ed - > ode . ode_avelocity ) ;
// ed->ode.ode_gravity = (qboolean)dBodyGetGravityMode(body);
World_LinkEdict ( world , ed , true ) ;
# endif
}
2017-12-09 21:22:46 +00:00
static bool NegativeMeshPitch ( world_t * world , wedict_t * ent )
{
if ( ent - > v - > modelindex )
{
model_t * model = world - > Get_CModel ( world , ent - > v - > modelindex ) ;
if ( model & & ( model - > type = = mod_alias | | model - > type = = mod_halflife ) )
return pr_meshpitch - > value < 0 ;
return false ;
}
return false ;
}
static btTransform transformFromQuake ( world_t * world , wedict_t * ent )
{
vec3_t forward , left , up ;
if ( NegativeMeshPitch ( world , ent ) )
{
vec3_t iangles = { - ent - > v - > angles [ 0 ] , ent - > v - > angles [ 1 ] , ent - > v - > angles [ 2 ] } ;
rbefuncs - > AngleVectors ( iangles , forward , left , up ) ;
}
else
rbefuncs - > AngleVectors ( ent - > v - > angles , forward , left , up ) ;
VectorNegate ( left , left ) ;
return btTransform ( btMatrix3x3 ( forward [ 0 ] , forward [ 1 ] , forward [ 2 ] , left [ 0 ] , left [ 1 ] , left [ 2 ] , up [ 0 ] , up [ 1 ] , up [ 2 ] ) , btVector3 ( ent - > v - > origin [ 0 ] , ent - > v - > origin [ 1 ] , ent - > v - > origin [ 2 ] ) ) ;
}
2017-04-18 11:12:17 +00:00
static void World_Bullet_Frame_JointFromEntity ( world_t * world , wedict_t * ed )
{
2017-12-09 21:22:46 +00:00
bulletcontext_t * rbe = ( bulletcontext_t * ) world - > rbe ;
btTypedConstraint * j = NULL ;
btRigidBody * b1 = NULL ;
btRigidBody * b2 = NULL ;
2017-04-18 11:12:17 +00:00
int movetype = 0 ;
int jointtype = 0 ;
int enemy = 0 , aiment = 0 ;
2017-12-09 21:22:46 +00:00
wedict_t * e1 , * e2 ;
// vec_t CFM, ERP, FMax;
vec_t Stop , Vel ;
vec3_t forward ;
2017-04-18 11:12:17 +00:00
movetype = ( int ) ed - > v - > movetype ;
jointtype = ( int ) ed - > xv - > jointtype ;
enemy = ed - > v - > enemy ;
aiment = ed - > v - > aiment ;
2017-12-09 21:22:46 +00:00
btVector3 origin ( ed - > v - > origin [ 0 ] , ed - > v - > origin [ 1 ] , ed - > v - > origin [ 2 ] ) ;
btVector3 velocity ( ed - > v - > velocity [ 0 ] , ed - > v - > velocity [ 1 ] , ed - > v - > velocity [ 2 ] ) ;
btVector3 movedir ( ed - > v - > movedir [ 0 ] , ed - > v - > movedir [ 1 ] , ed - > v - > movedir [ 2 ] ) ;
2017-04-18 11:12:17 +00:00
if ( movetype = = MOVETYPE_PHYSICS )
jointtype = 0 ; // can't have both
2017-12-09 21:22:46 +00:00
e1 = ( wedict_t * ) PROG_TO_EDICT ( world - > progs , enemy ) ;
b1 = ( btRigidBody * ) e1 - > ode . ode_body ;
if ( ED_ISFREE ( e1 ) | | ! b1 )
2017-04-18 11:12:17 +00:00
enemy = 0 ;
2017-12-09 21:22:46 +00:00
e2 = ( wedict_t * ) PROG_TO_EDICT ( world - > progs , aiment ) ;
b2 = ( btRigidBody * ) e2 - > ode . ode_body ;
if ( ED_ISFREE ( e2 ) | | ! b2 )
2017-04-18 11:12:17 +00:00
aiment = 0 ;
// see http://www.ode.org/old_list_archives/2006-January/017614.html
// we want to set ERP? make it fps independent and work like a spring constant
// note: if movedir[2] is 0, it becomes ERP = 1, CFM = 1.0 / (H * K)
if ( movedir [ 0 ] > 0 & & movedir [ 1 ] > 0 )
{
float K = movedir [ 0 ] ;
float D = movedir [ 1 ] ;
float R = 2.0 * D * sqrt ( K ) ; // we assume D is premultiplied by sqrt(sprungMass)
2017-12-09 21:22:46 +00:00
// CFM = 1.0 / (rbe->ode_step * K + R); // always > 0
// ERP = rbe->ode_step * K * CFM;
2017-04-18 11:12:17 +00:00
Vel = 0 ;
2017-12-09 21:22:46 +00:00
// FMax = 0;
2017-04-18 11:12:17 +00:00
Stop = movedir [ 2 ] ;
}
else if ( movedir [ 1 ] < 0 )
{
2017-12-09 21:22:46 +00:00
// CFM = 0;
// ERP = 0;
2017-04-18 11:12:17 +00:00
Vel = movedir [ 0 ] ;
2017-12-09 21:22:46 +00:00
// FMax = -movedir[1]; // TODO do we need to multiply with world.physics.ode_step?
Stop = movedir [ 2 ] > 0 ? movedir [ 2 ] : BT_INFINITY ;
2017-04-18 11:12:17 +00:00
}
else // movedir[0] > 0, movedir[1] == 0 or movedir[0] < 0, movedir[1] >= 0
{
2017-12-09 21:22:46 +00:00
// CFM = 0;
// ERP = 0;
2017-04-18 11:12:17 +00:00
Vel = 0 ;
2017-12-09 21:22:46 +00:00
// FMax = 0;
Stop = BT_INFINITY ;
2017-04-18 11:12:17 +00:00
}
2017-12-09 21:22:46 +00:00
if ( jointtype = = ed - > ode . ode_joint_type & & VectorCompare ( origin , ed - > ode . ode_joint_origin ) & & VectorCompare ( velocity , ed - > ode . ode_joint_velocity ) & & VectorCompare ( ed - > v - > angles , ed - > ode . ode_joint_angles ) & & enemy = = ed - > ode . ode_joint_enemy & & aiment = = ed - > ode . ode_joint_aiment & & VectorCompare ( movedir , ed - > ode . ode_joint_movedir ) )
2017-04-18 11:12:17 +00:00
return ; // nothing to do
2017-12-09 21:22:46 +00:00
2017-04-18 11:12:17 +00:00
if ( ed - > ode . ode_joint )
{
2017-12-09 21:22:46 +00:00
j = ( btTypedConstraint * ) ed - > ode . ode_joint ;
rbe - > dworld - > removeConstraint ( j ) ;
ed - > ode . ode_joint = NULL ;
delete j ;
2017-04-18 11:12:17 +00:00
}
2017-12-09 21:22:46 +00:00
if ( ! jointtype )
return ;
btVector3 b1org ( 0 , 0 , 0 ) , b2org ( 0 , 0 , 0 ) ;
if ( enemy )
b1org . setValue ( e1 - > v - > origin [ 0 ] , e1 - > v - > origin [ 1 ] , e1 - > v - > origin [ 2 ] ) ;
if ( aiment )
b2org . setValue ( e2 - > v - > origin [ 0 ] , e2 - > v - > origin [ 1 ] , e2 - > v - > origin [ 2 ] ) ;
2017-04-18 11:12:17 +00:00
ed - > ode . ode_joint_type = jointtype ;
ed - > ode . ode_joint_enemy = enemy ;
ed - > ode . ode_joint_aiment = aiment ;
VectorCopy ( origin , ed - > ode . ode_joint_origin ) ;
VectorCopy ( velocity , ed - > ode . ode_joint_velocity ) ;
2017-12-09 21:22:46 +00:00
VectorCopy ( ed - > v - > angles , ed - > ode . ode_joint_angles ) ;
2017-04-18 11:12:17 +00:00
VectorCopy ( movedir , ed - > ode . ode_joint_movedir ) ;
2017-12-09 21:22:46 +00:00
rbefuncs - > AngleVectors ( ed - > v - > angles , forward , NULL , NULL ) ;
//Con_Printf("making new joint %i\n", (int) (ed - prog->edicts));
switch ( jointtype )
2017-04-18 11:12:17 +00:00
{
2017-12-09 21:22:46 +00:00
case JOINTTYPE_POINT :
j = new btPoint2PointConstraint ( * b1 , * b2 , btVector3 ( b1org - origin ) , btVector3 ( b2org - origin ) ) ;
break ;
/* case JOINTTYPE_HINGE:
btHingeConstraint * h = new btHingeConstraint ( * b1 , * b2 , btVector3 ( b1org - origin ) , btVector3 ( b2org - origin ) , aa , ab , ref ) ;
j = h ;
if ( h )
2017-04-18 11:12:17 +00:00
{
2017-12-09 21:22:46 +00:00
h - > setLimit ( - Stop , Stop , softness , bias , relaxation ) ;
h - > setAxis ( btVector3 ( forward [ 0 ] , forward [ 1 ] , forward [ 2 ] ) ) ;
// h->dJointSetHingeParam(j, dParamFMax, FMax);
// h->dJointSetHingeParam(j, dParamHiStop, Stop);
// h->dJointSetHingeParam(j, dParamLoStop, -Stop);
// h->dJointSetHingeParam(j, dParamStopCFM, CFM);
// h->dJointSetHingeParam(j, dParamStopERP, ERP);
// h->setMotorTarget(vel);
}
break ; */
case JOINTTYPE_SLIDER :
{
btTransform jointtransform = transformFromQuake ( world , ed ) ;
btTransform b1transform = transformFromQuake ( world , e1 ) . inverseTimes ( jointtransform ) ;
btTransform b2transform = transformFromQuake ( world , e2 ) . inverseTimes ( jointtransform ) ;
btSliderConstraint * s = new btSliderConstraint ( * b1 , * b2 , b1transform , b2transform , false ) ;
j = s ;
if ( s )
{
// s->dJointSetSliderAxis(j, forward[0], forward[1], forward[2]);
// s->dJointSetSliderParam(j, dParamFMax, FMax);
s - > setLowerLinLimit ( - Stop ) ;
s - > setUpperLinLimit ( Stop ) ;
s - > setLowerAngLimit ( 0 ) ;
s - > setUpperAngLimit ( 0 ) ;
// s->dJointSetSliderParam(j, dParamHiStop, Stop);
// s->dJointSetSliderParam(j, dParamLoStop, -Stop);
// s->dJointSetSliderParam(j, dParamStopCFM, CFM);
// s->dJointSetSliderParam(j, dParamStopERP, ERP);
// s->setTargetLinMotorVelocity(vel);
// s->setPoweredLinMotor(true);
}
2017-04-18 11:12:17 +00:00
}
2017-12-09 21:22:46 +00:00
break ;
/* case JOINTTYPE_UNIVERSAL:
btGeneric6DofConstraint
j = dJointCreateUniversal ( rbe - > ode_world , 0 ) ;
if ( j )
{
dJointSetUniversalAnchor ( j , origin [ 0 ] , origin [ 1 ] , origin [ 2 ] ) ;
dJointSetUniversalAxis1 ( j , forward [ 0 ] , forward [ 1 ] , forward [ 2 ] ) ;
dJointSetUniversalAxis2 ( j , up [ 0 ] , up [ 1 ] , up [ 2 ] ) ;
dJointSetUniversalParam ( j , dParamFMax , FMax ) ;
dJointSetUniversalParam ( j , dParamHiStop , Stop ) ;
dJointSetUniversalParam ( j , dParamLoStop , - Stop ) ;
dJointSetUniversalParam ( j , dParamStopCFM , CFM ) ;
dJointSetUniversalParam ( j , dParamStopERP , ERP ) ;
dJointSetUniversalParam ( j , dParamVel , Vel ) ;
dJointSetUniversalParam ( j , dParamFMax2 , FMax ) ;
dJointSetUniversalParam ( j , dParamHiStop2 , Stop ) ;
dJointSetUniversalParam ( j , dParamLoStop2 , - Stop ) ;
dJointSetUniversalParam ( j , dParamStopCFM2 , CFM ) ;
dJointSetUniversalParam ( j , dParamStopERP2 , ERP ) ;
dJointSetUniversalParam ( j , dParamVel2 , Vel ) ;
}
break ; */
/* case JOINTTYPE_HINGE2:
j = dJointCreateHinge2 ( rbe - > ode_world , 0 ) ;
if ( j )
{
dJointSetHinge2Anchor ( j , origin [ 0 ] , origin [ 1 ] , origin [ 2 ] ) ;
dJointSetHinge2Axis1 ( j , forward [ 0 ] , forward [ 1 ] , forward [ 2 ] ) ;
dJointSetHinge2Axis2 ( j , velocity [ 0 ] , velocity [ 1 ] , velocity [ 2 ] ) ;
dJointSetHinge2Param ( j , dParamFMax , FMax ) ;
dJointSetHinge2Param ( j , dParamHiStop , Stop ) ;
dJointSetHinge2Param ( j , dParamLoStop , - Stop ) ;
dJointSetHinge2Param ( j , dParamStopCFM , CFM ) ;
dJointSetHinge2Param ( j , dParamStopERP , ERP ) ;
dJointSetHinge2Param ( j , dParamVel , Vel ) ;
dJointSetHinge2Param ( j , dParamFMax2 , FMax ) ;
dJointSetHinge2Param ( j , dParamHiStop2 , Stop ) ;
dJointSetHinge2Param ( j , dParamLoStop2 , - Stop ) ;
dJointSetHinge2Param ( j , dParamStopCFM2 , CFM ) ;
dJointSetHinge2Param ( j , dParamStopERP2 , ERP ) ;
dJointSetHinge2Param ( j , dParamVel2 , Vel ) ;
}
break ; */
case JOINTTYPE_FIXED :
{
btTransform jointtransform = transformFromQuake ( world , ed ) ;
btTransform b1transform = transformFromQuake ( world , e1 ) . inverseTimes ( jointtransform ) ;
btTransform b2transform = transformFromQuake ( world , e2 ) . inverseTimes ( jointtransform ) ;
2017-04-18 11:12:17 +00:00
2017-12-09 21:22:46 +00:00
j = new btFixedConstraint ( * b1 , * b2 , b1transform , b2transform ) ;
}
break ;
case 0 :
default :
j = NULL ;
break ;
}
ed - > ode . ode_joint = ( void * ) j ;
if ( j )
{
j - > setUserConstraintPtr ( ( void * ) ed ) ;
rbe - > dworld - > addConstraint ( j , false ) ;
2017-04-18 11:12:17 +00:00
}
}
static qboolean QDECL World_Bullet_RagMatrixToBody ( rbebody_t * bodyptr , float * mat )
{
btRigidBody * body ;
/*
dVector3 r [ 3 ] ;
r [ 0 ] [ 0 ] = mat [ 0 ] ;
r [ 0 ] [ 1 ] = mat [ 1 ] ;
r [ 0 ] [ 2 ] = mat [ 2 ] ;
r [ 1 ] [ 0 ] = mat [ 4 ] ;
r [ 1 ] [ 1 ] = mat [ 5 ] ;
r [ 1 ] [ 2 ] = mat [ 6 ] ;
r [ 2 ] [ 0 ] = mat [ 8 ] ;
r [ 2 ] [ 1 ] = mat [ 9 ] ;
r [ 2 ] [ 2 ] = mat [ 10 ] ;
dBodySetPosition ( bodyptr - > ode_body , mat [ 3 ] , mat [ 7 ] , mat [ 11 ] ) ;
dBodySetRotation ( bodyptr - > ode_body , r [ 0 ] ) ;
dBodySetLinearVel ( bodyptr - > ode_body , 0 , 0 , 0 ) ;
dBodySetAngularVel ( bodyptr - > ode_body , 0 , 0 , 0 ) ;
*/
return qtrue ;
}
static qboolean QDECL World_Bullet_RagCreateBody ( world_t * world , rbebody_t * bodyptr , rbebodyinfo_t * bodyinfo , float * mat , wedict_t * ent )
{
/*
dMass mass ;
float radius ;
if ( ! world - > ode . ode_space )
return false ;
world - > ode . hasodeents = true ; //I don't like this, but we need the world etc to be solid.
world - > ode . hasextraobjs = true ;
switch ( bodyinfo - > geomshape )
{
case GEOMTYPE_CAPSULE :
radius = ( bodyinfo - > dimensions [ 0 ] + bodyinfo - > dimensions [ 1 ] ) * 0.5 ;
bodyptr - > ode_geom = ( void * ) dCreateCapsule ( world - > ode . ode_space , radius , bodyinfo - > dimensions [ 2 ] ) ;
dMassSetCapsuleTotal ( & mass , bodyinfo - > mass , 3 , radius , bodyinfo - > dimensions [ 2 ] ) ;
//aligned along the geom's local z axis
break ;
case GEOMTYPE_SPHERE :
//radius
radius = ( bodyinfo - > dimensions [ 0 ] + bodyinfo - > dimensions [ 1 ] + bodyinfo - > dimensions [ 2 ] ) / 3 ;
bodyptr - > ode_geom = dCreateSphere ( world - > ode . ode_space , radius ) ;
dMassSetSphereTotal ( & mass , bodyinfo - > mass , radius ) ;
//aligned along the geom's local z axis
break ;
case GEOMTYPE_CYLINDER :
//radius, length
radius = ( bodyinfo - > dimensions [ 0 ] + bodyinfo - > dimensions [ 1 ] ) * 0.5 ;
bodyptr - > ode_geom = dCreateCylinder ( world - > ode . ode_space , radius , bodyinfo - > dimensions [ 2 ] ) ;
dMassSetCylinderTotal ( & mass , bodyinfo - > mass , 3 , radius , bodyinfo - > dimensions [ 2 ] ) ;
//alignment is irreleevnt, thouse I suppose it might be scaled wierdly.
break ;
default :
case GEOMTYPE_BOX :
//diameter
bodyptr - > ode_geom = dCreateBox ( world - > ode . ode_space , bodyinfo - > dimensions [ 0 ] , bodyinfo - > dimensions [ 1 ] , bodyinfo - > dimensions [ 2 ] ) ;
dMassSetBoxTotal ( & mass , bodyinfo - > mass , bodyinfo - > dimensions [ 0 ] , bodyinfo - > dimensions [ 1 ] , bodyinfo - > dimensions [ 2 ] ) ;
//monkey
break ;
}
bodyptr - > ode_body = dBodyCreate ( world - > ode . ode_world ) ;
dBodySetMass ( bodyptr - > ode_body , & mass ) ;
dGeomSetBody ( bodyptr - > ode_geom , bodyptr - > ode_body ) ;
dGeomSetData ( bodyptr - > ode_geom , ( void * ) ent ) ;
*/
return World_Bullet_RagMatrixToBody ( bodyptr , mat ) ;
}
static void QDECL World_Bullet_RagMatrixFromJoint ( rbejoint_t * joint , rbejointinfo_t * info , float * mat )
{
/*
dVector3 dr3 ;
switch ( info - > type )
{
case JOINTTYPE_POINT :
dJointGetBallAnchor ( joint - > ode_joint , dr3 ) ;
mat [ 3 ] = dr3 [ 0 ] ;
mat [ 7 ] = dr3 [ 1 ] ;
mat [ 11 ] = dr3 [ 2 ] ;
VectorClear ( mat + 4 ) ;
VectorClear ( mat + 8 ) ;
break ;
case JOINTTYPE_HINGE :
dJointGetHingeAnchor ( joint - > ode_joint , dr3 ) ;
mat [ 3 ] = dr3 [ 0 ] ;
mat [ 7 ] = dr3 [ 1 ] ;
mat [ 11 ] = dr3 [ 2 ] ;
dJointGetHingeAxis ( joint - > ode_joint , dr3 ) ;
VectorCopy ( dr3 , mat + 4 ) ;
VectorClear ( mat + 8 ) ;
CrossProduct ( mat + 4 , mat + 8 , mat + 0 ) ;
return ;
break ;
case JOINTTYPE_HINGE2 :
dJointGetHinge2Anchor ( joint - > ode_joint , dr3 ) ;
mat [ 3 ] = dr3 [ 0 ] ;
mat [ 7 ] = dr3 [ 1 ] ;
mat [ 11 ] = dr3 [ 2 ] ;
dJointGetHinge2Axis1 ( joint - > ode_joint , dr3 ) ;
VectorCopy ( dr3 , mat + 4 ) ;
dJointGetHinge2Axis2 ( joint - > ode_joint , dr3 ) ;
VectorCopy ( dr3 , mat + 8 ) ;
break ;
case JOINTTYPE_SLIDER :
//no anchor point...
//get the two bodies and average their origin for a somewhat usable representation of an anchor.
{
const dReal * p1 , * p2 ;
dReal n [ 3 ] ;
dBodyID b1 = dJointGetBody ( joint - > ode_joint , 0 ) , b2 = dJointGetBody ( joint - > ode_joint , 1 ) ;
if ( b1 )
p1 = dBodyGetPosition ( b1 ) ;
else
{
p1 = n ;
VectorClear ( n ) ;
}
if ( b2 )
p2 = dBodyGetPosition ( b2 ) ;
else
p2 = p1 ;
dJointGetSliderAxis ( joint - > ode_joint , dr3 + 0 ) ;
VectorInterpolate ( p1 , 0.5 , p2 , dr3 ) ;
mat [ 3 ] = dr3 [ 0 ] ;
mat [ 7 ] = dr3 [ 1 ] ;
mat [ 11 ] = dr3 [ 2 ] ;
VectorClear ( mat + 4 ) ;
VectorClear ( mat + 8 ) ;
}
break ;
case JOINTTYPE_UNIVERSAL :
dJointGetUniversalAnchor ( joint - > ode_joint , dr3 ) ;
mat [ 3 ] = dr3 [ 0 ] ;
mat [ 7 ] = dr3 [ 1 ] ;
mat [ 11 ] = dr3 [ 2 ] ;
dJointGetUniversalAxis1 ( joint - > ode_joint , dr3 ) ;
VectorCopy ( dr3 , mat + 4 ) ;
dJointGetUniversalAxis2 ( joint - > ode_joint , dr3 ) ;
VectorCopy ( dr3 , mat + 8 ) ;
CrossProduct ( mat + 4 , mat + 8 , mat + 0 ) ;
return ;
break ;
}
2017-12-09 21:22:46 +00:00
rbefuncs - > AngleVectors ( vec3_origin , mat + 0 , mat + 4 , mat + 8 ) ;
VectorNegate ( ( mat + 4 ) , ( mat + 4 ) ) ;
2017-04-18 11:12:17 +00:00
*/
}
static void QDECL World_Bullet_RagMatrixFromBody ( world_t * world , rbebody_t * bodyptr , float * mat )
{
/*
const dReal * o = dBodyGetPosition ( bodyptr - > ode_body ) ;
const dReal * r = dBodyGetRotation ( bodyptr - > ode_body ) ;
mat [ 0 ] = r [ 0 ] ;
mat [ 1 ] = r [ 1 ] ;
mat [ 2 ] = r [ 2 ] ;
mat [ 3 ] = o [ 0 ] ;
mat [ 4 ] = r [ 4 ] ;
mat [ 5 ] = r [ 5 ] ;
mat [ 6 ] = r [ 6 ] ;
mat [ 7 ] = o [ 1 ] ;
mat [ 8 ] = r [ 8 ] ;
mat [ 9 ] = r [ 9 ] ;
mat [ 10 ] = r [ 10 ] ;
mat [ 11 ] = o [ 2 ] ;
*/
}
static void QDECL World_Bullet_RagEnableJoint ( rbejoint_t * joint , qboolean enabled )
{
/*
if ( enabled )
dJointEnable ( joint - > ode_joint ) ;
else
dJointDisable ( joint - > ode_joint ) ;
*/
}
static void QDECL World_Bullet_RagCreateJoint ( world_t * world , rbejoint_t * joint , rbejointinfo_t * info , rbebody_t * body1 , rbebody_t * body2 , vec3_t aaa2 [ 3 ] )
{
/*
switch ( info - > type )
{
case JOINTTYPE_POINT :
joint - > ode_joint = dJointCreateBall ( world - > ode . ode_world , 0 ) ;
break ;
case JOINTTYPE_HINGE :
joint - > ode_joint = dJointCreateHinge ( world - > ode . ode_world , 0 ) ;
break ;
case JOINTTYPE_SLIDER :
joint - > ode_joint = dJointCreateSlider ( world - > ode . ode_world , 0 ) ;
break ;
case JOINTTYPE_UNIVERSAL :
joint - > ode_joint = dJointCreateUniversal ( world - > ode . ode_world , 0 ) ;
break ;
case JOINTTYPE_HINGE2 :
joint - > ode_joint = dJointCreateHinge2 ( world - > ode . ode_world , 0 ) ;
break ;
case JOINTTYPE_FIXED :
joint - > ode_joint = dJointCreateFixed ( world - > ode . ode_world , 0 ) ;
break ;
default :
joint - > ode_joint = NULL ;
break ;
}
if ( joint - > ode_joint )
{
//Con_Printf("made new joint %i\n", (int) (ed - prog->edicts));
// dJointSetData(joint->ode_joint, NULL);
dJointAttach ( joint - > ode_joint , body1 ? body1 - > ode_body : NULL , body2 ? body2 - > ode_body : NULL ) ;
switch ( info - > type )
{
case JOINTTYPE_POINT :
dJointSetBallAnchor ( joint - > ode_joint , aaa2 [ 0 ] [ 0 ] , aaa2 [ 0 ] [ 1 ] , aaa2 [ 0 ] [ 2 ] ) ;
break ;
case JOINTTYPE_HINGE :
dJointSetHingeAnchor ( joint - > ode_joint , aaa2 [ 0 ] [ 0 ] , aaa2 [ 0 ] [ 1 ] , aaa2 [ 0 ] [ 2 ] ) ;
dJointSetHingeAxis ( joint - > ode_joint , aaa2 [ 1 ] [ 0 ] , aaa2 [ 1 ] [ 1 ] , aaa2 [ 1 ] [ 2 ] ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamFMax , info - > FMax ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamHiStop , info - > HiStop ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamLoStop , info - > LoStop ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamStopCFM , info - > CFM ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamStopERP , info - > ERP ) ;
dJointSetHingeParam ( joint - > ode_joint , dParamVel , info - > Vel ) ;
break ;
case JOINTTYPE_SLIDER :
dJointSetSliderAxis ( joint - > ode_joint , aaa2 [ 1 ] [ 0 ] , aaa2 [ 1 ] [ 1 ] , aaa2 [ 1 ] [ 2 ] ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamFMax , info - > FMax ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamHiStop , info - > HiStop ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamLoStop , info - > LoStop ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamStopCFM , info - > CFM ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamStopERP , info - > ERP ) ;
dJointSetSliderParam ( joint - > ode_joint , dParamVel , info - > Vel ) ;
break ;
case JOINTTYPE_UNIVERSAL :
dJointSetUniversalAnchor ( joint - > ode_joint , aaa2 [ 0 ] [ 0 ] , aaa2 [ 0 ] [ 1 ] , aaa2 [ 0 ] [ 2 ] ) ;
dJointSetUniversalAxis1 ( joint - > ode_joint , aaa2 [ 1 ] [ 0 ] , aaa2 [ 1 ] [ 1 ] , aaa2 [ 1 ] [ 2 ] ) ;
dJointSetUniversalAxis2 ( joint - > ode_joint , aaa2 [ 2 ] [ 0 ] , aaa2 [ 2 ] [ 1 ] , aaa2 [ 2 ] [ 2 ] ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamFMax , info - > FMax ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamHiStop , info - > HiStop ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamLoStop , info - > LoStop ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamStopCFM , info - > CFM ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamStopERP , info - > ERP ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamVel , info - > Vel ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamFMax2 , info - > FMax2 ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamHiStop2 , info - > HiStop2 ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamLoStop2 , info - > LoStop2 ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamStopCFM2 , info - > CFM2 ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamStopERP2 , info - > ERP2 ) ;
dJointSetUniversalParam ( joint - > ode_joint , dParamVel2 , info - > Vel2 ) ;
break ;
case JOINTTYPE_HINGE2 :
dJointSetHinge2Anchor ( joint - > ode_joint , aaa2 [ 0 ] [ 0 ] , aaa2 [ 0 ] [ 1 ] , aaa2 [ 0 ] [ 2 ] ) ;
dJointSetHinge2Axis1 ( joint - > ode_joint , aaa2 [ 1 ] [ 0 ] , aaa2 [ 1 ] [ 1 ] , aaa2 [ 1 ] [ 2 ] ) ;
dJointSetHinge2Axis2 ( joint - > ode_joint , aaa2 [ 2 ] [ 0 ] , aaa2 [ 2 ] [ 1 ] , aaa2 [ 2 ] [ 2 ] ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamFMax , info - > FMax ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamHiStop , info - > HiStop ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamLoStop , info - > LoStop ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamStopCFM , info - > CFM ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamStopERP , info - > ERP ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamVel , info - > Vel ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamFMax2 , info - > FMax2 ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamHiStop2 , info - > HiStop2 ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamLoStop2 , info - > LoStop2 ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamStopCFM2 , info - > CFM2 ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamStopERP2 , info - > ERP2 ) ;
dJointSetHinge2Param ( joint - > ode_joint , dParamVel2 , info - > Vel2 ) ;
break ;
case JOINTTYPE_FIXED :
dJointSetFixed ( joint - > ode_joint ) ;
break ;
}
}
*/
}
static void QDECL World_Bullet_RagDestroyBody ( world_t * world , rbebody_t * bodyptr )
{
/*
if ( bodyptr - > ode_geom )
dGeomDestroy ( bodyptr - > ode_geom ) ;
bodyptr - > ode_geom = NULL ;
if ( bodyptr - > ode_body )
dBodyDestroy ( bodyptr - > ode_body ) ;
bodyptr - > ode_body = NULL ;
*/
}
static void QDECL World_Bullet_RagDestroyJoint ( world_t * world , rbejoint_t * joint )
{
/*
if ( joint - > ode_joint )
dJointDestroy ( joint - > ode_joint ) ;
joint - > ode_joint = NULL ;
*/
}
//bullet gives us a handy way to get/set motion states. we can cheesily update entity fields this way.
class QCMotionState : public btMotionState
{
wedict_t * edict ;
qboolean dirty ;
btTransform trans ;
world_t * world ;
public :
void ReloadMotionState ( void )
{
vec3_t offset ;
vec3_t axis [ 3 ] ;
btVector3 org ;
rbefuncs - > AngleVectors ( edict - > v - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
VectorNegate ( axis [ 1 ] , axis [ 1 ] ) ;
VectorAvg ( edict - > ode . ode_mins , edict - > ode . ode_maxs , offset ) ;
VectorMA ( edict - > v - > origin , offset [ 0 ] * 1 , axis [ 0 ] , org ) ;
VectorMA ( org , offset [ 1 ] * 1 , axis [ 1 ] , org ) ;
VectorMA ( org , offset [ 2 ] * 1 , axis [ 2 ] , org ) ;
trans . setBasis ( btMatrix3x3 ( axis [ 0 ] [ 0 ] , axis [ 1 ] [ 0 ] , axis [ 2 ] [ 0 ] ,
axis [ 0 ] [ 1 ] , axis [ 1 ] [ 1 ] , axis [ 2 ] [ 1 ] ,
axis [ 0 ] [ 2 ] , axis [ 1 ] [ 2 ] , axis [ 2 ] [ 2 ] ) ) ;
trans . setOrigin ( org ) ;
}
QCMotionState ( wedict_t * ed , world_t * w )
{
dirty = qtrue ;
edict = ed ;
world = w ;
ReloadMotionState ( ) ;
}
virtual ~ QCMotionState ( )
{
}
virtual void getWorldTransform ( btTransform & worldTrans ) const
{
worldTrans = trans ;
}
virtual void setWorldTransform ( const btTransform & worldTrans )
{
vec3_t fwd , left , up , offset ;
trans = worldTrans ;
btVector3 pos = worldTrans . getOrigin ( ) ;
VectorCopy ( worldTrans . getBasis ( ) . getColumn ( 0 ) , fwd ) ;
VectorCopy ( worldTrans . getBasis ( ) . getColumn ( 1 ) , left ) ;
VectorCopy ( worldTrans . getBasis ( ) . getColumn ( 2 ) , up ) ;
VectorAvg ( edict - > ode . ode_mins , edict - > ode . ode_maxs , offset ) ;
VectorMA ( pos , offset [ 0 ] * - 1 , fwd , pos ) ;
VectorMA ( pos , offset [ 1 ] * - 1 , left , pos ) ;
VectorMA ( pos , offset [ 2 ] * - 1 , up , edict - > v - > origin ) ;
2017-12-09 21:22:46 +00:00
rbefuncs - > VectorAngles ( fwd , up , edict - > v - > angles , ( qboolean ) NegativeMeshPitch ( world , edict ) ) ;
2017-04-18 11:12:17 +00:00
2017-12-09 21:22:46 +00:00
const btVector3 & vel = ( ( btRigidBody * ) edict - > ode . ode_body ) - > getLinearVelocity ( ) ;
VectorCopy ( vel . m_floats , edict - > v - > velocity ) ;
2017-04-18 11:12:17 +00:00
//so it doesn't get rebuilt
VectorCopy ( edict - > v - > origin , edict - > ode . ode_origin ) ;
VectorCopy ( edict - > v - > angles , edict - > ode . ode_angles ) ;
2017-12-09 21:22:46 +00:00
VectorCopy ( edict - > v - > velocity , edict - > ode . ode_velocity ) ;
2017-04-18 11:12:17 +00:00
// World_LinkEdict(world, edict, false);
// if(mSceneNode == nullptr)
// return; // silently return before we set a node
// btQuaternion rot = worldTrans.getRotation();
// mSceneNode ->setOrientation(rot.w(), rot.x(), rot.y(), rot.z());
// btVector3 pos = worldTrans.getOrigin();
// mSceneNode ->setPosition(pos.x(), pos.y(), pos.z());
}
} ;
static void World_Bullet_Frame_BodyFromEntity ( world_t * world , wedict_t * ed )
{
bulletcontext_t * ctx = ( bulletcontext_t * ) world - > rbe ;
btRigidBody * body = NULL ;
btScalar mass ;
float test ;
void * dataID ;
model_t * model ;
int axisindex ;
int modelindex = 0 ;
int movetype = MOVETYPE_NONE ;
int solid = SOLID_NOT ;
int geomtype = GEOMTYPE_SOLID ;
qboolean modified = qfalse ;
vec3_t angles ;
vec3_t avelocity ;
vec3_t entmaxs ;
vec3_t entmins ;
vec3_t forward ;
vec3_t geomcenter ;
vec3_t geomsize ;
vec3_t left ;
vec3_t origin ;
vec3_t spinvelocity ;
vec3_t up ;
vec3_t velocity ;
vec_t f ;
vec_t length ;
vec_t massval = 1.0f ;
// vec_t movelimit;
vec_t radius ;
vec_t scale ;
vec_t spinlimit ;
qboolean gravity ;
geomtype = ( int ) ed - > xv - > geomtype ;
solid = ( int ) ed - > v - > solid ;
movetype = ( int ) ed - > v - > movetype ;
scale = ed - > xv - > scale ? ed - > xv - > scale : 1 ;
modelindex = 0 ;
model = NULL ;
if ( ! geomtype )
{
switch ( ( int ) ed - > v - > solid )
{
case SOLID_NOT : geomtype = GEOMTYPE_NONE ; break ;
case SOLID_TRIGGER : geomtype = GEOMTYPE_NONE ; break ;
case SOLID_BSP : geomtype = GEOMTYPE_TRIMESH ; break ;
case SOLID_PHYSICS_TRIMESH : geomtype = GEOMTYPE_TRIMESH ; break ;
case SOLID_PHYSICS_BOX : geomtype = GEOMTYPE_BOX ; break ;
case SOLID_PHYSICS_SPHERE : geomtype = GEOMTYPE_SPHERE ; break ;
case SOLID_PHYSICS_CAPSULE : geomtype = GEOMTYPE_CAPSULE ; break ;
case SOLID_PHYSICS_CYLINDER : geomtype = GEOMTYPE_CYLINDER ; break ;
default : geomtype = GEOMTYPE_BOX ; break ;
}
}
switch ( geomtype )
{
case GEOMTYPE_TRIMESH :
modelindex = ( int ) ed - > v - > modelindex ;
model = world - > Get_CModel ( world , modelindex ) ;
if ( ! model | | model - > loadstate ! = MLS_LOADED )
{
model = NULL ;
modelindex = 0 ;
}
if ( model )
{
VectorScale ( model - > mins , scale , entmins ) ;
VectorScale ( model - > maxs , scale , entmaxs ) ;
if ( ed - > xv - > mass )
massval = ed - > xv - > mass ;
}
else
{
modelindex = 0 ;
massval = 1.0f ;
}
massval = 0 ; //bullet does not support trisoup moving through the world.
break ;
case GEOMTYPE_BOX :
case GEOMTYPE_SPHERE :
case GEOMTYPE_CAPSULE :
case GEOMTYPE_CAPSULE_X :
case GEOMTYPE_CAPSULE_Y :
case GEOMTYPE_CAPSULE_Z :
case GEOMTYPE_CYLINDER :
case GEOMTYPE_CYLINDER_X :
case GEOMTYPE_CYLINDER_Y :
case GEOMTYPE_CYLINDER_Z :
VectorCopy ( ed - > v - > mins , entmins ) ;
VectorCopy ( ed - > v - > maxs , entmaxs ) ;
if ( ed - > xv - > mass )
massval = ed - > xv - > mass ;
break ;
default :
// case GEOMTYPE_NONE:
if ( ed - > ode . ode_physics )
World_Bullet_RemoveFromEntity ( world , ed ) ;
return ;
}
VectorSubtract ( entmaxs , entmins , geomsize ) ;
if ( DotProduct ( geomsize , geomsize ) = = 0 )
{
// we don't allow point-size physics objects...
if ( ed - > ode . ode_physics )
World_Bullet_RemoveFromEntity ( world , ed ) ;
return ;
}
// check if we need to create or replace the geom
if ( ! ed - > ode . ode_physics
| | ! VectorCompare ( ed - > ode . ode_mins , entmins )
| | ! VectorCompare ( ed - > ode . ode_maxs , entmaxs )
| | ed - > ode . ode_modelindex ! = modelindex )
{
btCollisionShape * geom ;
modified = qtrue ;
World_Bullet_RemoveFromEntity ( world , ed ) ;
ed - > ode . ode_physics = qtrue ;
VectorCopy ( entmins , ed - > ode . ode_mins ) ;
VectorCopy ( entmaxs , ed - > ode . ode_maxs ) ;
ed - > ode . ode_modelindex = modelindex ;
VectorAvg ( entmins , entmaxs , geomcenter ) ;
ed - > ode . ode_movelimit = min ( geomsize [ 0 ] , min ( geomsize [ 1 ] , geomsize [ 2 ] ) ) ;
/* memset(ed->ode.ode_offsetmatrix, 0, sizeof(ed->ode.ode_offsetmatrix));
ed - > ode . ode_offsetmatrix [ 0 ] = 1 ;
ed - > ode . ode_offsetmatrix [ 5 ] = 1 ;
ed - > ode . ode_offsetmatrix [ 10 ] = 1 ;
ed - > ode . ode_offsetmatrix [ 3 ] = - geomcenter [ 0 ] ;
ed - > ode . ode_offsetmatrix [ 7 ] = - geomcenter [ 1 ] ;
ed - > ode . ode_offsetmatrix [ 11 ] = - geomcenter [ 2 ] ;
*/
ed - > ode . ode_mass = massval ;
switch ( geomtype )
{
case GEOMTYPE_TRIMESH :
// foo Matrix4x4_Identity(ed->ode.ode_offsetmatrix);
geom = NULL ;
if ( ! model )
{
Con_Printf ( " entity %i (classname %s) has no model \n " , NUM_FOR_EDICT ( world - > progs , ( edict_t * ) ed ) , PR_GetString ( world - > progs , ed - > v - > classname ) ) ;
if ( ed - > ode . ode_physics )
World_Bullet_RemoveFromEntity ( world , ed ) ;
return ;
}
if ( ! rbefuncs - > GenerateCollisionMesh ( world , model , ed , geomcenter ) )
{
if ( ed - > ode . ode_physics )
World_Bullet_RemoveFromEntity ( world , ed ) ;
return ;
}
// foo Matrix4x4_RM_CreateTranslate(ed->ode.ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
{
btTriangleIndexVertexArray * tiva = new btTriangleIndexVertexArray ( ) ;
btIndexedMesh mesh ;
mesh . m_vertexType = PHY_FLOAT ;
mesh . m_indexType = PHY_INTEGER ;
mesh . m_numTriangles = ed - > ode . ode_numtriangles ;
mesh . m_numVertices = ed - > ode . ode_numvertices ;
mesh . m_triangleIndexBase = ( const unsigned char * ) ed - > ode . ode_element3i ;
mesh . m_triangleIndexStride = sizeof ( * ed - > ode . ode_element3i ) * 3 ;
mesh . m_vertexBase = ( const unsigned char * ) ed - > ode . ode_vertex3f ;
mesh . m_vertexStride = sizeof ( * ed - > ode . ode_vertex3f ) * 3 ;
tiva - > addIndexedMesh ( mesh ) ;
geom = new btBvhTriangleMeshShape ( tiva , true ) ;
}
break ;
case GEOMTYPE_BOX :
geom = new btBoxShape ( btVector3 ( geomsize [ 0 ] , geomsize [ 1 ] , geomsize [ 2 ] ) * 0.5 ) ;
break ;
case GEOMTYPE_SPHERE :
geom = new btSphereShape ( geomsize [ 0 ] * 0.5f ) ;
break ;
case GEOMTYPE_CAPSULE :
case GEOMTYPE_CAPSULE_X :
case GEOMTYPE_CAPSULE_Y :
case GEOMTYPE_CAPSULE_Z :
if ( geomtype = = GEOMTYPE_CAPSULE )
{
// the qc gives us 3 axis radius, the longest axis is the capsule axis
axisindex = 0 ;
if ( geomsize [ axisindex ] < geomsize [ 1 ] )
axisindex = 1 ;
if ( geomsize [ axisindex ] < geomsize [ 2 ] )
axisindex = 2 ;
}
else
axisindex = geomtype - GEOMTYPE_CAPSULE_X ;
if ( axisindex = = 0 )
radius = min ( geomsize [ 1 ] , geomsize [ 2 ] ) * 0.5f ;
else if ( axisindex = = 1 )
radius = min ( geomsize [ 0 ] , geomsize [ 2 ] ) * 0.5f ;
else
radius = min ( geomsize [ 0 ] , geomsize [ 1 ] ) * 0.5f ;
length = geomsize [ axisindex ] - radius * 2 ;
if ( length < = 0 )
{
radius - = ( 1 - length ) * 0.5 ;
length = 1 ;
}
if ( axisindex = = 0 )
geom = new btCapsuleShapeX ( radius , length ) ;
else if ( axisindex = = 1 )
geom = new btCapsuleShape ( radius , length ) ;
else
geom = new btCapsuleShapeZ ( radius , length ) ;
break ;
case GEOMTYPE_CYLINDER :
case GEOMTYPE_CYLINDER_X :
case GEOMTYPE_CYLINDER_Y :
case GEOMTYPE_CYLINDER_Z :
if ( geomtype = = GEOMTYPE_CYLINDER )
{
// the qc gives us 3 axis radius, the longest axis is the capsule axis
axisindex = 0 ;
if ( geomsize [ axisindex ] < geomsize [ 1 ] )
axisindex = 1 ;
if ( geomsize [ axisindex ] < geomsize [ 2 ] )
axisindex = 2 ;
}
else
axisindex = geomtype - GEOMTYPE_CYLINDER_X ;
if ( axisindex = = 0 )
geom = new btCylinderShapeX ( btVector3 ( geomsize [ 0 ] , geomsize [ 1 ] , geomsize [ 2 ] ) * 0.5 ) ;
else if ( axisindex = = 1 )
geom = new btCylinderShape ( btVector3 ( geomsize [ 0 ] , geomsize [ 1 ] , geomsize [ 2 ] ) * 0.5 ) ;
else
geom = new btCylinderShapeZ ( btVector3 ( geomsize [ 0 ] , geomsize [ 1 ] , geomsize [ 2 ] ) * 0.5 ) ;
break ;
default :
// Con_Printf("World_Bullet_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
if ( ed - > ode . ode_physics )
World_Bullet_RemoveFromEntity ( world , ed ) ;
return ;
}
// Matrix3x4_InvertTo4x4_Simple(ed->ode.ode_offsetmatrix, ed->ode.ode_offsetimatrix);
// ed->ode.ode_massbuf = BZ_Malloc(sizeof(dMass));
// memcpy(ed->ode.ode_massbuf, &mass, sizeof(dMass));
ed - > ode . ode_geom = ( void * ) geom ;
}
//non-moving objects need to be static objects (and thus need 0 mass)
if ( movetype ! = MOVETYPE_PHYSICS & & movetype ! = MOVETYPE_WALK ) //enabling kinematic objects for everything else destroys framerates (!movetype || movetype == MOVETYPE_PUSH)
massval = 0 ;
//if the mass changes, we'll need to create a new body (but not the shape, so invalidate the current one)
if ( ed - > ode . ode_mass ! = massval )
{
ed - > ode . ode_mass = massval ;
body = ( btRigidBody * ) ed - > ode . ode_body ;
if ( body )
ctx - > dworld - > removeRigidBody ( body ) ;
ed - > ode . ode_body = NULL ;
}
// if(ed->ode.ode_geom)
// dGeomSetData(ed->ode.ode_geom, (void*)ed);
if ( movetype = = MOVETYPE_PHYSICS & & ed - > ode . ode_mass )
{
if ( ed - > ode . ode_body = = NULL )
{
// ed->ode.ode_body = (void *)(body = dBodyCreate(world->ode.ode_world));
// dGeomSetBody(ed->ode.ode_geom, body);
// dBodySetData(body, (void*)ed);
// dBodySetMass(body, (dMass *) ed->ode.ode_massbuf);
btVector3 fallInertia ( 0 , 0 , 0 ) ;
( ( btCollisionShape * ) ed - > ode . ode_geom ) - > calculateLocalInertia ( ed - > ode . ode_mass , fallInertia ) ;
btRigidBody : : btRigidBodyConstructionInfo fallRigidBodyCI ( ed - > ode . ode_mass , new QCMotionState ( ed , world ) , ( btCollisionShape * ) ed - > ode . ode_geom , fallInertia ) ;
body = new btRigidBody ( fallRigidBodyCI ) ;
body - > setUserPointer ( ed ) ;
// btTransform trans;
// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix);
// body->setCenterOfMassTransform(trans);
ed - > ode . ode_body = ( void * ) body ;
2017-12-09 21:22:46 +00:00
//motion threshhold should be speed/physicsframerate.
//FIXME: recalculate...
2017-04-18 11:12:17 +00:00
body - > setCcdMotionThreshold ( ( geomsize [ 0 ] + geomsize [ 1 ] + geomsize [ 2 ] ) * ( 4 / 3 ) ) ;
2017-12-09 21:22:46 +00:00
//radius should be the body's radius
2017-04-18 11:12:17 +00:00
body - > setCcdSweptSphereRadius ( ( geomsize [ 0 ] + geomsize [ 1 ] + geomsize [ 2 ] ) * ( 0.5 / 3 ) ) ;
ctx - > dworld - > addRigidBody ( body , ed - > xv - > dimension_solid , ed - > xv - > dimension_hit ) ;
modified = qtrue ;
}
}
else
{
if ( ed - > ode . ode_body = = NULL )
{
btRigidBody : : btRigidBodyConstructionInfo rbci ( ed - > ode . ode_mass , new QCMotionState ( ed , world ) , ( btCollisionShape * ) ed - > ode . ode_geom , btVector3 ( 0 , 0 , 0 ) ) ;
body = new btRigidBody ( rbci ) ;
body - > setUserPointer ( ed ) ;
// btTransform trans;
// trans.setFromOpenGLMatrix(ed->ode.ode_offsetmatrix);
// body->setCenterOfMassTransform(trans);
ed - > ode . ode_body = ( void * ) body ;
if ( ed - > ode . ode_mass )
body - > setCollisionFlags ( body - > getCollisionFlags ( ) | btCollisionObject : : CF_KINEMATIC_OBJECT ) ;
else
body - > setCollisionFlags ( body - > getCollisionFlags ( ) | btCollisionObject : : CF_STATIC_OBJECT ) ;
ctx - > dworld - > addRigidBody ( body , ed - > xv - > dimension_solid , ed - > xv - > dimension_hit ) ;
modified = qtrue ;
}
}
body = ( btRigidBody * ) ed - > ode . ode_body ;
// get current data from entity
gravity = qtrue ;
VectorCopy ( ed - > v - > origin , origin ) ;
VectorCopy ( ed - > v - > velocity , velocity ) ;
VectorCopy ( ed - > v - > angles , angles ) ;
VectorCopy ( ed - > v - > avelocity , avelocity ) ;
if ( ed = = world - > edicts | | ( ed - > xv - > gravity & & ed - > xv - > gravity < = 0.01 ) )
gravity = qfalse ;
// compatibility for legacy entities
// if (!DotProduct(forward,forward) || solid == SOLID_BSP)
{
vec3_t qangles , qavelocity ;
VectorCopy ( angles , qangles ) ;
VectorCopy ( avelocity , qavelocity ) ;
if ( ed - > v - > modelindex )
{
model = world - > Get_CModel ( world , ed - > v - > modelindex ) ;
if ( ! model | | model - > type = = mod_alias )
{
qangles [ PITCH ] * = - 1 ;
qavelocity [ PITCH ] * = - 1 ;
}
}
rbefuncs - > AngleVectors ( qangles , forward , left , up ) ;
VectorNegate ( left , left ) ;
// convert single-axis rotations in avelocity to spinvelocity
// FIXME: untested math - check signs
VectorSet ( spinvelocity , DEG2RAD ( qavelocity [ PITCH ] ) , DEG2RAD ( qavelocity [ ROLL ] ) , DEG2RAD ( qavelocity [ YAW ] ) ) ;
}
// compatibility for legacy entities
switch ( solid )
{
case SOLID_BBOX :
case SOLID_SLIDEBOX :
case SOLID_CORPSE :
VectorSet ( forward , 1 , 0 , 0 ) ;
VectorSet ( left , 0 , 1 , 0 ) ;
VectorSet ( up , 0 , 0 , 1 ) ;
VectorSet ( spinvelocity , 0 , 0 , 0 ) ;
break ;
}
// we must prevent NANs...
test = DotProduct ( origin , origin ) + DotProduct ( forward , forward ) + DotProduct ( left , left ) + DotProduct ( up , up ) + DotProduct ( velocity , velocity ) + DotProduct ( spinvelocity , spinvelocity ) ;
if ( IS_NAN ( test ) )
{
modified = qtrue ;
//Con_Printf("Fixing NAN values on entity %i : .classname = \"%s\" .origin = '%f %f %f' .velocity = '%f %f %f' .axis_forward = '%f %f %f' .axis_left = '%f %f %f' .axis_up = %f %f %f' .spinvelocity = '%f %f %f'\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string), origin[0], origin[1], origin[2], velocity[0], velocity[1], velocity[2], forward[0], forward[1], forward[2], left[0], left[1], left[2], up[0], up[1], up[2], spinvelocity[0], spinvelocity[1], spinvelocity[2]);
Con_Printf ( " Fixing NAN values on entity %i : .classname = \" %s \" .origin = '%f %f %f' .velocity = '%f %f %f' .angles = '%f %f %f' .avelocity = '%f %f %f' \n " , NUM_FOR_EDICT ( world - > progs , ( edict_t * ) ed ) , PR_GetString ( world - > progs , ed - > v - > classname ) , origin [ 0 ] , origin [ 1 ] , origin [ 2 ] , velocity [ 0 ] , velocity [ 1 ] , velocity [ 2 ] , angles [ 0 ] , angles [ 1 ] , angles [ 2 ] , avelocity [ 0 ] , avelocity [ 1 ] , avelocity [ 2 ] ) ;
test = DotProduct ( origin , origin ) ;
if ( IS_NAN ( test ) )
VectorClear ( origin ) ;
test = DotProduct ( forward , forward ) * DotProduct ( left , left ) * DotProduct ( up , up ) ;
if ( IS_NAN ( test ) )
{
VectorSet ( angles , 0 , 0 , 0 ) ;
VectorSet ( forward , 1 , 0 , 0 ) ;
VectorSet ( left , 0 , 1 , 0 ) ;
VectorSet ( up , 0 , 0 , 1 ) ;
}
test = DotProduct ( velocity , velocity ) ;
if ( IS_NAN ( test ) )
VectorClear ( velocity ) ;
test = DotProduct ( spinvelocity , spinvelocity ) ;
if ( IS_NAN ( test ) )
{
VectorClear ( avelocity ) ;
VectorClear ( spinvelocity ) ;
}
}
// check if the qc edited any position data
if (
0 //!VectorCompare(origin, ed->ode.ode_origin)
| | ! VectorCompare ( velocity , ed - > ode . ode_velocity )
//|| !VectorCompare(angles, ed->ode.ode_angles)
| | ! VectorCompare ( avelocity , ed - > ode . ode_avelocity )
| | gravity ! = ed - > ode . ode_gravity )
modified = qtrue ;
// store the qc values into the physics engine
body = ( btRigidBody * ) ed - > ode . ode_body ;
if ( modified & & body )
{
// dVector3 r[3];
float entitymatrix [ 16 ] ;
float bodymatrix [ 16 ] ;
#if 0
Con_Printf ( " entity %i got changed by QC \n " , ( int ) ( ed - prog - > edicts ) ) ;
if ( ! VectorCompare ( origin , ed - > ode . ode_origin ) )
Con_Printf ( " origin: %f %f %f -> %f %f %f \n " , ed - > ode . ode_origin [ 0 ] , ed - > ode . ode_origin [ 1 ] , ed - > ode . ode_origin [ 2 ] , origin [ 0 ] , origin [ 1 ] , origin [ 2 ] ) ;
if ( ! VectorCompare ( velocity , ed - > ode . ode_velocity ) )
Con_Printf ( " velocity: %f %f %f -> %f %f %f \n " , ed - > ode . ode_velocity [ 0 ] , ed - > ode . ode_velocity [ 1 ] , ed - > ode . ode_velocity [ 2 ] , velocity [ 0 ] , velocity [ 1 ] , velocity [ 2 ] ) ;
if ( ! VectorCompare ( angles , ed - > ode . ode_angles ) )
Con_Printf ( " angles: %f %f %f -> %f %f %f \n " , ed - > ode . ode_angles [ 0 ] , ed - > ode . ode_angles [ 1 ] , ed - > ode . ode_angles [ 2 ] , angles [ 0 ] , angles [ 1 ] , angles [ 2 ] ) ;
if ( ! VectorCompare ( avelocity , ed - > ode . ode_avelocity ) )
Con_Printf ( " avelocity: %f %f %f -> %f %f %f \n " , ed - > ode . ode_avelocity [ 0 ] , ed - > ode . ode_avelocity [ 1 ] , ed - > ode . ode_avelocity [ 2 ] , avelocity [ 0 ] , avelocity [ 1 ] , avelocity [ 2 ] ) ;
if ( gravity ! = ed - > ode . ode_gravity )
Con_Printf ( " gravity: %i -> %i \n " , ed - > ide . ode_gravity , gravity ) ;
# endif
// values for BodyFromEntity to check if the qc modified anything later
VectorCopy ( origin , ed - > ode . ode_origin ) ;
VectorCopy ( velocity , ed - > ode . ode_velocity ) ;
VectorCopy ( angles , ed - > ode . ode_angles ) ;
VectorCopy ( avelocity , ed - > ode . ode_avelocity ) ;
ed - > ode . ode_gravity = gravity ;
// foo Matrix4x4_RM_FromVectors(entitymatrix, forward, left, up, origin);
// foo Matrix4_Multiply(ed->ode.ode_offsetmatrix, entitymatrix, bodymatrix);
// foo Matrix3x4_RM_ToVectors(bodymatrix, forward, left, up, origin);
// r[0][0] = forward[0];
// r[1][0] = forward[1];
// r[2][0] = forward[2];
// r[0][1] = left[0];
// r[1][1] = left[1];
// r[2][1] = left[2];
// r[0][2] = up[0];
// r[1][2] = up[1];
// r[2][2] = up[2];
QCMotionState * ms = ( QCMotionState * ) body - > getMotionState ( ) ;
ms - > ReloadMotionState ( ) ;
body - > setMotionState ( ms ) ;
body - > setLinearVelocity ( btVector3 ( velocity [ 0 ] , velocity [ 1 ] , velocity [ 2 ] ) ) ;
body - > setAngularVelocity ( btVector3 ( spinvelocity [ 0 ] , spinvelocity [ 1 ] , spinvelocity [ 2 ] ) ) ;
// body->setGravity(btVector3(ed->xv->gravitydir[0], ed->xv->gravitydir[1], ed->xv->gravitydir[2]) * ed->xv->gravity);
//something changed. make sure it still falls over appropriately
body - > setActivationState ( 1 ) ;
}
/* FIXME: check if we actually need this insanity with bullet (ode sucks).
if ( body )
{
// limit movement speed to prevent missed collisions at high speed
btVector3 ovelocity = body - > getLinearVelocity ( ) ;
btVector3 ospinvelocity = body - > getAngularVelocity ( ) ;
movelimit = ed - > ode . ode_movelimit * world - > ode . ode_movelimit ;
test = DotProduct ( ovelocity , ovelocity ) ;
if ( test > movelimit * movelimit )
{
// scale down linear velocity to the movelimit
// scale down angular velocity the same amount for consistency
f = movelimit / sqrt ( test ) ;
VectorScale ( ovelocity , f , velocity ) ;
VectorScale ( ospinvelocity , f , spinvelocity ) ;
body - > setLinearVelocity ( btVector3 ( velocity [ 0 ] , velocity [ 1 ] , velocity [ 2 ] ) ) ;
body - > setAngularVelocity ( btVector3 ( spinvelocity [ 0 ] , spinvelocity [ 1 ] , spinvelocity [ 2 ] ) ) ;
}
// make sure the angular velocity is not exploding
spinlimit = physics_bullet_spinlimit . value ;
test = DotProduct ( ospinvelocity , ospinvelocity ) ;
if ( test > spinlimit )
{
body - > setAngularVelocity ( btVector3 ( 0 , 0 , 0 ) ) ;
}
}
*/
}
/*
# define MAX_CONTACTS 16
static void VARGS nearCallback ( void * data , dGeomID o1 , dGeomID o2 )
{
world_t * world = ( world_t * ) data ;
dContact contact [ MAX_CONTACTS ] ; // max contacts per collision pair
dBodyID b1 ;
dBodyID b2 ;
dJointID c ;
int i ;
int numcontacts ;
float bouncefactor1 = 0.0f ;
float bouncestop1 = 60.0f / 800.0f ;
float bouncefactor2 = 0.0f ;
float bouncestop2 = 60.0f / 800.0f ;
float erp ;
dVector3 grav ;
wedict_t * ed1 , * ed2 ;
if ( dGeomIsSpace ( o1 ) | | dGeomIsSpace ( o2 ) )
{
// colliding a space with something
dSpaceCollide2 ( o1 , o2 , data , & nearCallback ) ;
// Note we do not want to test intersections within a space,
// only between spaces.
//if (dGeomIsSpace(o1)) dSpaceCollide(o1, data, &nearCallback);
//if (dGeomIsSpace(o2)) dSpaceCollide(o2, data, &nearCallback);
return ;
}
b1 = dGeomGetBody ( o1 ) ;
b2 = dGeomGetBody ( o2 ) ;
// at least one object has to be using MOVETYPE_PHYSICS or we just don't care
if ( ! b1 & & ! b2 )
return ;
// exit without doing anything if the two bodies are connected by a joint
if ( b1 & & b2 & & dAreConnectedExcluding ( b1 , b2 , dJointTypeContact ) )
return ;
ed1 = ( wedict_t * ) dGeomGetData ( o1 ) ;
ed2 = ( wedict_t * ) dGeomGetData ( o2 ) ;
if ( ed1 = = ed2 & & ed1 )
{
//ragdolls don't make contact with the bbox of the doll entity
//the origional entity should probably not be solid anyway.
//these bodies should probably not collide against bboxes of other entities with ragdolls either, but meh.
if ( ed1 - > ode . ode_body = = b1 | | ed2 - > ode . ode_body = = b2 )
return ;
}
if ( ! ed1 | | ed1 - > isfree )
ed1 = world - > edicts ;
if ( ! ed2 | | ed2 - > isfree )
ed2 = world - > edicts ;
// generate contact points between the two non-space geoms
numcontacts = dCollide ( o1 , o2 , MAX_CONTACTS , & ( contact [ 0 ] . geom ) , sizeof ( contact [ 0 ] ) ) ;
if ( numcontacts )
{
if ( ed1 & & ed1 - > v - > touch )
{
world - > Event_Touch ( world , ed1 , ed2 ) ;
}
if ( ed2 & & ed2 - > v - > touch )
{
world - > Event_Touch ( world , ed2 , ed1 ) ;
}
// if either ent killed itself, don't collide
if ( ( ed1 & & ed1 - > isfree ) | | ( ed2 & & ed2 - > isfree ) )
return ;
}
if ( ed1 )
{
if ( ed1 - > xv - > bouncefactor )
bouncefactor1 = ed1 - > xv - > bouncefactor ;
if ( ed1 - > xv - > bouncestop )
bouncestop1 = ed1 - > xv - > bouncestop ;
}
if ( ed2 )
{
if ( ed2 - > xv - > bouncefactor )
bouncefactor2 = ed2 - > xv - > bouncefactor ;
if ( ed2 - > xv - > bouncestop )
bouncestop2 = ed2 - > xv - > bouncestop ;
}
if ( ( ed2 - > entnum & & ed1 - > v - > owner = = ed2 - > entnum ) | | ( ed1 - > entnum & & ed2 - > v - > owner = = ed1 - > entnum ) )
return ;
// merge bounce factors and bounce stop
if ( bouncefactor2 > 0 )
{
if ( bouncefactor1 > 0 )
{
// TODO possibly better logic to merge bounce factor data?
if ( bouncestop2 < bouncestop1 )
bouncestop1 = bouncestop2 ;
if ( bouncefactor2 > bouncefactor1 )
bouncefactor1 = bouncefactor2 ;
}
else
{
bouncestop1 = bouncestop2 ;
bouncefactor1 = bouncefactor2 ;
}
}
dWorldGetGravity ( world - > ode . ode_world , grav ) ;
bouncestop1 * = fabs ( grav [ 2 ] ) ;
erp = ( DotProduct ( ed1 - > v - > velocity , ed1 - > v - > velocity ) > DotProduct ( ed2 - > v - > velocity , ed2 - > v - > velocity ) ) ? ed1 - > xv - > erp : ed2 - > xv - > erp ;
// add these contact points to the simulation
for ( i = 0 ; i < numcontacts ; i + + )
{
contact [ i ] . surface . mode = ( physics_bullet_contact_mu . value ! = - 1 ? dContactApprox1 : 0 ) |
( physics_bullet_contact_erp . value ! = - 1 ? dContactSoftERP : 0 ) |
( physics_bullet_contact_cfm . value ! = - 1 ? dContactSoftCFM : 0 ) |
( bouncefactor1 > 0 ? dContactBounce : 0 ) ;
contact [ i ] . surface . mu = physics_bullet_contact_mu . value ;
if ( ed1 - > xv - > friction )
contact [ i ] . surface . mu * = ed1 - > xv - > friction ;
if ( ed2 - > xv - > friction )
contact [ i ] . surface . mu * = ed2 - > xv - > friction ;
contact [ i ] . surface . mu2 = 0 ;
contact [ i ] . surface . soft_erp = physics_bullet_contact_erp . value + erp ;
contact [ i ] . surface . soft_cfm = physics_bullet_contact_cfm . value ;
contact [ i ] . surface . bounce = bouncefactor1 ;
contact [ i ] . surface . bounce_vel = bouncestop1 ;
c = dJointCreateContact ( world - > ode . ode_world , world - > ode . ode_contactgroup , contact + i ) ;
dJointAttach ( c , b1 , b2 ) ;
}
}
*/
static void QDECL World_Bullet_Frame ( world_t * world , double frametime , double gravity )
{
struct bulletcontext_s * ctx = ( struct bulletcontext_s * ) world - > rbe ;
if ( world - > rbe_hasphysicsents | | ctx - > hasextraobjs )
{
int i ;
wedict_t * ed ;
// world->ode.ode_iterations = bound(1, physics_bullet_iterationsperframe.ival, 1000);
// world->ode.ode_step = frametime / world->ode.ode_iterations;
// world->ode.ode_movelimit = physics_bullet_movelimit.value / world->ode.ode_step;
// copy physics properties from entities to physics engine
for ( i = 0 ; i < world - > num_edicts ; i + + )
{
ed = ( wedict_t * ) EDICT_NUM ( world - > progs , i ) ;
if ( ! ED_ISFREE ( ed ) )
World_Bullet_Frame_BodyFromEntity ( world , ed ) ;
}
// oh, and it must be called after all bodies were created
for ( i = 0 ; i < world - > num_edicts ; i + + )
{
ed = ( wedict_t * ) EDICT_NUM ( world - > progs , i ) ;
if ( ! ED_ISFREE ( ed ) )
World_Bullet_Frame_JointFromEntity ( world , ed ) ;
}
while ( ctx - > cmdqueuehead )
{
rbecommandqueue_t * cmd = ctx - > cmdqueuehead ;
ctx - > cmdqueuehead = cmd - > next ;
if ( ! cmd - > next )
ctx - > cmdqueuetail = NULL ;
World_Bullet_RunCmd ( world , cmd ) ;
Z_Free ( cmd ) ;
}
ctx - > dworld - > setGravity ( btVector3 ( 0 , 0 , - gravity ) ) ;
2017-12-09 21:22:46 +00:00
ctx - > dworld - > stepSimulation ( frametime , max ( 0 , physics_bullet_maxiterationsperframe - > value ) , 1 / bound ( 1 , physics_bullet_framerate - > value , 500 ) ) ;
2017-04-18 11:12:17 +00:00
// set the tolerance for closeness of objects
// dWorldSetContactSurfaceLayer(world->ode.ode_world, max(0, physics_bullet_contactsurfacelayer.value));
// run collisions for the current world state, creating JointGroup
// dSpaceCollide(world->ode.ode_space, (void *)world, nearCallback);
// run physics (move objects, calculate new velocities)
// if (physics_bullet_worldquickstep.ival)
// {
// dWorldSetQuickStepNumIterations(world->ode.ode_world, bound(1, physics_bullet_worldquickstep_iterations.ival, 200));
// dWorldQuickStep(world->ode.ode_world, world->ode.ode_step);
// }
// else
// dWorldStep(world->ode.ode_world, world->ode.ode_step);
// clear the JointGroup now that we're done with it
// dJointGroupEmpty(world->ode.ode_contactgroup);
if ( world - > rbe_hasphysicsents )
{
// copy physics properties from physics engine to entities
for ( i = 1 ; i < world - > num_edicts ; i + + )
{
ed = ( wedict_t * ) EDICT_NUM ( world - > progs , i ) ;
if ( ! ED_ISFREE ( ed ) )
World_Bullet_Frame_BodyToEntity ( world , ed ) ;
}
}
}
}
static void World_Bullet_RunCmd ( world_t * world , rbecommandqueue_t * cmd )
{
btRigidBody * body = ( btRigidBody * ) ( cmd - > edict - > ode . ode_body ) ;
switch ( cmd - > command )
{
case RBECMD_ENABLE :
if ( body )
body - > setActivationState ( 1 ) ;
break ;
case RBECMD_DISABLE :
if ( body )
body - > setActivationState ( 0 ) ;
break ;
case RBECMD_FORCE :
if ( body )
{
body - > setActivationState ( 1 ) ;
body - > applyForce ( btVector3 ( cmd - > v1 [ 0 ] , cmd - > v1 [ 1 ] , cmd - > v1 [ 2 ] ) , btVector3 ( cmd - > v2 [ 0 ] , cmd - > v2 [ 1 ] , cmd - > v2 [ 2 ] ) ) ;
}
break ;
case RBECMD_TORQUE :
if ( cmd - > edict - > ode . ode_body )
{
body - > setActivationState ( 1 ) ;
body - > applyTorque ( btVector3 ( cmd - > v1 [ 0 ] , cmd - > v1 [ 1 ] , cmd - > v1 [ 2 ] ) ) ;
}
break ;
}
}
static void QDECL World_Bullet_PushCommand ( world_t * world , rbecommandqueue_t * val )
{
struct bulletcontext_s * ctx = ( struct bulletcontext_s * ) world - > rbe ;
rbecommandqueue_t * cmd = ( rbecommandqueue_t * ) BZ_Malloc ( sizeof ( * cmd ) ) ;
world - > rbe_hasphysicsents = qtrue ; //just in case.
memcpy ( cmd , val , sizeof ( * cmd ) ) ;
cmd - > next = NULL ;
//add on the end of the queue, so that order is preserved.
if ( ctx - > cmdqueuehead )
{
rbecommandqueue_t * ot = ctx - > cmdqueuetail ;
ot - > next = ctx - > cmdqueuetail = cmd ;
}
else
ctx - > cmdqueuetail = ctx - > cmdqueuehead = cmd ;
}
static void QDECL World_Bullet_TraceEntity ( world_t * world , vec3_t start , vec3_t end , wedict_t * ed )
{
struct bulletcontext_s * ctx = ( struct bulletcontext_s * ) world - > rbe ;
btCollisionShape * shape = ( btCollisionShape * ) ed - > ode . ode_geom ;
class myConvexResultCallback : public btCollisionWorld : : ConvexResultCallback
{
public :
virtual btScalar addSingleResult ( btCollisionWorld : : LocalConvexResult & convexResult , bool normalInWorldSpace )
{
return 0 ;
}
} result ;
btTransform from ( btMatrix3x3 ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 ) , btVector3 ( start [ 0 ] , start [ 1 ] , start [ 2 ] ) ) ;
btTransform to ( btMatrix3x3 ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 ) , btVector3 ( end [ 0 ] , end [ 1 ] , end [ 2 ] ) ) ;
ctx - > dworld - > convexSweepTest ( ( btConvexShape * ) shape , from , to , result , 1 ) ;
}
static void QDECL World_Bullet_Start ( world_t * world )
{
struct bulletcontext_s * ctx ;
if ( world - > rbe )
return ; //no thanks, we already have one. somehow.
2017-12-09 21:22:46 +00:00
if ( ! physics_bullet_enable - > value )
2017-04-18 11:12:17 +00:00
return ;
ctx = ( struct bulletcontext_s * ) BZ_Malloc ( sizeof ( * ctx ) ) ;
memset ( ctx , 0 , sizeof ( * ctx ) ) ;
ctx - > gworld = world ;
ctx - > funcs . End = World_Bullet_End ;
ctx - > funcs . RemoveJointFromEntity = World_Bullet_RemoveJointFromEntity ;
ctx - > funcs . RemoveFromEntity = World_Bullet_RemoveFromEntity ;
ctx - > funcs . RagMatrixToBody = World_Bullet_RagMatrixToBody ;
ctx - > funcs . RagCreateBody = World_Bullet_RagCreateBody ;
ctx - > funcs . RagMatrixFromJoint = World_Bullet_RagMatrixFromJoint ;
ctx - > funcs . RagMatrixFromBody = World_Bullet_RagMatrixFromBody ;
ctx - > funcs . RagEnableJoint = World_Bullet_RagEnableJoint ;
ctx - > funcs . RagCreateJoint = World_Bullet_RagCreateJoint ;
ctx - > funcs . RagDestroyBody = World_Bullet_RagDestroyBody ;
ctx - > funcs . RagDestroyJoint = World_Bullet_RagDestroyJoint ;
ctx - > funcs . RunFrame = World_Bullet_Frame ;
ctx - > funcs . PushCommand = World_Bullet_PushCommand ;
world - > rbe = & ctx - > funcs ;
ctx - > broadphase = new btDbvtBroadphase ( ) ;
ctx - > collisionconfig = new btDefaultCollisionConfiguration ( ) ;
ctx - > collisiondispatcher = new btCollisionDispatcher ( ctx - > collisionconfig ) ;
ctx - > solver = new btSequentialImpulseConstraintSolver ;
ctx - > dworld = new btDiscreteDynamicsWorld ( ctx - > collisiondispatcher , ctx - > broadphase , ctx - > solver , ctx - > collisionconfig ) ;
ctx - > ownerfilter = new QCFilterCallback ( ) ;
ctx - > dworld - > getPairCache ( ) - > setOverlapFilterCallback ( ctx - > ownerfilter ) ;
ctx - > dworld - > setGravity ( btVector3 ( 0 , - 10 , 0 ) ) ;
/*
if ( physics_bullet_world_erp . value > = 0 )
dWorldSetERP ( world - > ode . ode_world , physics_bullet_world_erp . value ) ;
if ( physics_bullet_world_cfm . value > = 0 )
dWorldSetCFM ( world - > ode . ode_world , physics_bullet_world_cfm . value ) ;
if ( physics_bullet_world_damping . ival )
{
dWorldSetLinearDamping ( world - > ode . ode_world , ( physics_bullet_world_damping_linear . value > = 0 ) ? ( physics_bullet_world_damping_linear . value * physics_bullet_world_damping . value ) : 0 ) ;
dWorldSetLinearDampingThreshold ( world - > ode . ode_world , ( physics_bullet_world_damping_linear_threshold . value > = 0 ) ? ( physics_bullet_world_damping_linear_threshold . value * physics_bullet_world_damping . value ) : 0 ) ;
dWorldSetAngularDamping ( world - > ode . ode_world , ( physics_bullet_world_damping_angular . value > = 0 ) ? ( physics_bullet_world_damping_angular . value * physics_bullet_world_damping . value ) : 0 ) ;
dWorldSetAngularDampingThreshold ( world - > ode . ode_world , ( physics_bullet_world_damping_angular_threshold . value > = 0 ) ? ( physics_bullet_world_damping_angular_threshold . value * physics_bullet_world_damping . value ) : 0 ) ;
}
else
{
dWorldSetLinearDamping ( world - > ode . ode_world , 0 ) ;
dWorldSetLinearDampingThreshold ( world - > ode . ode_world , 0 ) ;
dWorldSetAngularDamping ( world - > ode . ode_world , 0 ) ;
dWorldSetAngularDampingThreshold ( world - > ode . ode_world , 0 ) ;
}
if ( physics_bullet_autodisable . ival )
{
dWorldSetAutoDisableSteps ( world - > ode . ode_world , bound ( 1 , physics_bullet_autodisable_steps . ival , 100 ) ) ;
dWorldSetAutoDisableTime ( world - > ode . ode_world , physics_bullet_autodisable_time . value ) ;
dWorldSetAutoDisableAverageSamplesCount ( world - > ode . ode_world , bound ( 1 , physics_bullet_autodisable_threshold_samples . ival , 100 ) ) ;
dWorldSetAutoDisableLinearThreshold ( world - > ode . ode_world , physics_bullet_autodisable_threshold_linear . value ) ;
dWorldSetAutoDisableAngularThreshold ( world - > ode . ode_world , physics_bullet_autodisable_threshold_angular . value ) ;
dWorldSetAutoDisableFlag ( world - > ode . ode_world , true ) ;
}
else
dWorldSetAutoDisableFlag ( world - > ode . ode_world , false ) ;
*/
}
static qintptr_t QDECL World_Bullet_Shutdown ( qintptr_t * args )
{
if ( rbefuncs )
rbefuncs - > UnregisterPhysicsEngine ( " Bullet " ) ;
return 0 ;
}
static bool World_Bullet_DoInit ( void )
{
if ( ! rbefuncs | | ! rbefuncs - > RegisterPhysicsEngine )
{
rbefuncs = NULL ;
Con_Printf ( " Bullet plugin failed: Engine doesn't support physics engine plugins. \n " ) ;
}
else if ( ! rbefuncs - > RegisterPhysicsEngine ( " Bullet " , World_Bullet_Start ) )
Con_Printf ( " Bullet plugin failed: Engine already has a physics plugin active. \n " ) ;
else
{
World_Bullet_Init ( ) ;
return true ;
}
return false ;
}
# define ARGNAMES ,version
static BUILTINR ( rbeplugfuncs_t * , RBE_GetPluginFuncs , ( int version ) ) ;
# undef ARGNAMES
extern " C " qintptr_t Plug_Init ( qintptr_t * args )
{
CHECKBUILTIN ( RBE_GetPluginFuncs ) ;
if ( BUILTINISVALID ( RBE_GetPluginFuncs ) )
{
rbefuncs = pRBE_GetPluginFuncs ( sizeof ( rbeplugfuncs_t ) ) ;
if ( rbefuncs & & rbefuncs - > version < RBEPLUGFUNCS_VERSION )
rbefuncs = NULL ;
}
Plug_Export ( " Shutdown " , World_Bullet_Shutdown ) ;
return World_Bullet_DoInit ( ) ;
}