Try to add some ragdoll joints to the bullet plugin.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5518 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
a6ec9fd9b5
commit
87fdee2282
1 changed files with 161 additions and 233 deletions
|
@ -135,19 +135,22 @@ class QCFilterCallback : public btOverlapFilterCallback
|
||||||
//owners don't collide (unless one is world, obviouslyish)
|
//owners don't collide (unless one is world, obviouslyish)
|
||||||
if (collides)
|
if (collides)
|
||||||
{
|
{
|
||||||
btRigidBody *b1 = (btRigidBody*)proxy0->m_clientObject;
|
auto b1 = (btRigidBody*)proxy0->m_clientObject;
|
||||||
btRigidBody *b2 = (btRigidBody*)proxy1->m_clientObject;
|
auto b2 = (btRigidBody*)proxy1->m_clientObject;
|
||||||
//don't let two qc-controlled entities collide in Bullet, that's the job of quake.
|
//don't let two qc-controlled entities collide in Bullet, that's the job of quake.
|
||||||
if (b1->isStaticOrKinematicObject() && b2->isStaticOrKinematicObject())
|
if (b1->isStaticOrKinematicObject() && b2->isStaticOrKinematicObject())
|
||||||
return false;
|
return false;
|
||||||
wedict_t *e1 = (wedict_t*)b1->getUserPointer();
|
auto e1 = (wedict_t*)b1->getUserPointer();
|
||||||
wedict_t *e2 = (wedict_t*)b2->getUserPointer();
|
auto e2 = (wedict_t*)b2->getUserPointer();
|
||||||
|
if (e1&&e2)
|
||||||
|
{
|
||||||
if ((e1->v->solid == SOLID_TRIGGER && e2->v->solid != SOLID_BSP) ||
|
if ((e1->v->solid == SOLID_TRIGGER && e2->v->solid != SOLID_BSP) ||
|
||||||
(e2->v->solid == SOLID_TRIGGER && e1->v->solid != SOLID_BSP))
|
(e2->v->solid == SOLID_TRIGGER && e1->v->solid != SOLID_BSP))
|
||||||
return false; //triggers only collide with bsp objects.
|
return false; //triggers only collide with bsp objects.
|
||||||
if (e1->entnum && e2->entnum)
|
if (e1->entnum && e2->entnum)
|
||||||
collides = e1->v->owner != e2->entnum && e2->v->owner != e1->entnum;
|
collides = e1->v->owner != e2->entnum && e2->v->owner != e1->entnum;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return collides;
|
return collides;
|
||||||
}
|
}
|
||||||
|
@ -155,8 +158,8 @@ class QCFilterCallback : public btOverlapFilterCallback
|
||||||
|
|
||||||
static void QDECL World_Bullet_End(world_t *world)
|
static void QDECL World_Bullet_End(world_t *world)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
world->rbe = NULL;
|
world->rbe = nullptr;
|
||||||
delete ctx->dworld;
|
delete ctx->dworld;
|
||||||
delete ctx->solver;
|
delete ctx->solver;
|
||||||
delete ctx->collisionconfig;
|
delete ctx->collisionconfig;
|
||||||
|
@ -176,7 +179,7 @@ static void QDECL World_Bullet_RemoveJointFromEntity(world_t *world, wedict_t *e
|
||||||
|
|
||||||
static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed)
|
static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btRigidBody *body;
|
btRigidBody *body;
|
||||||
btCollisionShape *geom;
|
btCollisionShape *geom;
|
||||||
if (!ed->rbe.physics)
|
if (!ed->rbe.physics)
|
||||||
|
@ -202,115 +205,6 @@ static void QDECL World_Bullet_RemoveFromEntity(world_t *world, wedict_t *ed)
|
||||||
ed->rbe.massbuf = NULL;
|
ed->rbe.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->rbe.body.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->rbe.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->rbe.origin);
|
|
||||||
VectorCopy(velocity, ed->rbe.velocity);
|
|
||||||
VectorCopy(angles, ed->rbe.angles);
|
|
||||||
VectorCopy(avelocity, ed->rbe.avelocity);
|
|
||||||
// ed->rbe.gravity = (qboolean)dBodyGetGravityMode(body);
|
|
||||||
|
|
||||||
World_LinkEdict(world, ed, true);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool NegativeMeshPitch(world_t *world, wedict_t *ent)
|
static bool NegativeMeshPitch(world_t *world, wedict_t *ent)
|
||||||
{
|
{
|
||||||
if (ent->v->modelindex)
|
if (ent->v->modelindex)
|
||||||
|
@ -340,10 +234,10 @@ static btTransform transformFromQuake(world_t *world, wedict_t *ent)
|
||||||
|
|
||||||
static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
||||||
{
|
{
|
||||||
bulletcontext_t *rbe = (bulletcontext_t*)world->rbe;
|
auto rbe = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btTypedConstraint *j = NULL;
|
btTypedConstraint *j = nullptr;
|
||||||
btRigidBody *b1 = NULL;
|
btRigidBody *b1 = nullptr;
|
||||||
btRigidBody *b2 = NULL;
|
btRigidBody *b2 = nullptr;
|
||||||
int movetype = 0;
|
int movetype = 0;
|
||||||
int jointtype = 0;
|
int jointtype = 0;
|
||||||
int enemy = 0, aiment = 0;
|
int enemy = 0, aiment = 0;
|
||||||
|
@ -352,8 +246,8 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
||||||
vec_t Stop;
|
vec_t Stop;
|
||||||
// vec_t Vel;
|
// vec_t Vel;
|
||||||
vec3_t forward;
|
vec3_t forward;
|
||||||
movetype = (int)ed->v->movetype;
|
movetype = ed->v->movetype;
|
||||||
jointtype = (int)ed->xv->jointtype;
|
jointtype = ed->xv->jointtype;
|
||||||
enemy = ed->v->enemy;
|
enemy = ed->v->enemy;
|
||||||
aiment = ed->v->aiment;
|
aiment = ed->v->aiment;
|
||||||
btVector3 origin(ed->v->origin[0], ed->v->origin[1], ed->v->origin[2]);
|
btVector3 origin(ed->v->origin[0], ed->v->origin[1], ed->v->origin[2]);
|
||||||
|
@ -407,7 +301,7 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
||||||
{
|
{
|
||||||
j = (btTypedConstraint*)ed->rbe.joint.joint;
|
j = (btTypedConstraint*)ed->rbe.joint.joint;
|
||||||
rbe->dworld->removeConstraint(j);
|
rbe->dworld->removeConstraint(j);
|
||||||
ed->rbe.joint.joint = NULL;
|
ed->rbe.joint.joint = nullptr;
|
||||||
delete j;
|
delete j;
|
||||||
}
|
}
|
||||||
if (!jointtype)
|
if (!jointtype)
|
||||||
|
@ -427,7 +321,7 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
||||||
VectorCopy(ed->v->angles, ed->rbe.joint_angles);
|
VectorCopy(ed->v->angles, ed->rbe.joint_angles);
|
||||||
VectorCopy(movedir, ed->rbe.joint_movedir);
|
VectorCopy(movedir, ed->rbe.joint_movedir);
|
||||||
|
|
||||||
rbefuncs->AngleVectors(ed->v->angles, forward, NULL, NULL);
|
rbefuncs->AngleVectors(ed->v->angles, forward, nullptr, nullptr);
|
||||||
|
|
||||||
//Con_Printf("making new joint %i\n", (int) (ed - prog->edicts));
|
//Con_Printf("making new joint %i\n", (int) (ed - prog->edicts));
|
||||||
switch(jointtype)
|
switch(jointtype)
|
||||||
|
@ -530,7 +424,7 @@ static void World_Bullet_Frame_JointFromEntity(world_t *world, wedict_t *ed)
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
default:
|
default:
|
||||||
j = NULL;
|
j = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,9 +440,9 @@ static void MatToTransform(const float *mat, btTransform &tr)
|
||||||
{
|
{
|
||||||
tr.setBasis(btMatrix3x3(
|
tr.setBasis(btMatrix3x3(
|
||||||
mat[0], mat[1], mat[2],
|
mat[0], mat[1], mat[2],
|
||||||
mat[3], mat[4], mat[5],
|
mat[4], mat[5], mat[6],
|
||||||
mat[6], mat[7], mat[8]));
|
mat[8], mat[9], mat[10]));
|
||||||
tr.setOrigin(btVector3(mat[9], mat[10], mat[11]));
|
tr.setOrigin(btVector3(mat[3], mat[7], mat[11]));
|
||||||
}
|
}
|
||||||
static void MatFromTransform(float *mat, const btTransform &tr)
|
static void MatFromTransform(float *mat, const btTransform &tr)
|
||||||
{
|
{
|
||||||
|
@ -560,31 +454,32 @@ static void MatFromTransform(float *mat, const btTransform &tr)
|
||||||
mat[0] = r0[0];
|
mat[0] = r0[0];
|
||||||
mat[1] = r0[1];
|
mat[1] = r0[1];
|
||||||
mat[2] = r0[2];
|
mat[2] = r0[2];
|
||||||
mat[3] = r1[0];
|
mat[3] =o[0];
|
||||||
mat[4] = r1[1];
|
mat[4] = r1[0];
|
||||||
mat[5] = r1[2];
|
mat[5] = r1[1];
|
||||||
mat[6] = r2[0];
|
mat[6] = r1[2];
|
||||||
mat[7] = r2[1];
|
mat[7] =o[1];
|
||||||
mat[8] = r2[2];
|
mat[8] = r2[0];
|
||||||
mat[9] = o[0];
|
mat[9] = r2[1];
|
||||||
mat[10] = o[1];
|
mat[10]= r2[2];
|
||||||
mat[11]=o[2];
|
mat[11]=o[2];
|
||||||
}
|
}
|
||||||
static qboolean QDECL World_Bullet_RagMatrixToBody(rbebody_t *bodyptr, float *mat)
|
static qboolean QDECL World_Bullet_RagMatrixToBody(rbebody_t *bodyptr, float *mat)
|
||||||
{ //mat is a 4*3 matrix
|
{ //mat is a 4*3 matrix
|
||||||
btTransform tr;
|
btTransform tr;
|
||||||
btRigidBody *body = (btRigidBody*)bodyptr->body;
|
auto body = reinterpret_cast<btRigidBody*>(bodyptr->body);
|
||||||
MatToTransform(mat, tr);
|
MatToTransform(mat, tr);
|
||||||
body->setWorldTransform(tr);
|
body->setWorldTransform(tr);
|
||||||
return qtrue;
|
return qtrue;
|
||||||
}
|
}
|
||||||
static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent)
|
static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *bodyptr, rbebodyinfo_t *bodyinfo, float *mat, wedict_t *ent)
|
||||||
{
|
{
|
||||||
btRigidBody *body = NULL;
|
btRigidBody *body = nullptr;
|
||||||
btCollisionShape *geom = NULL;
|
btCollisionShape *geom = nullptr;
|
||||||
float radius;
|
float radius;
|
||||||
|
float threshold;
|
||||||
// float length;
|
// float length;
|
||||||
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
// int axisindex;
|
// int axisindex;
|
||||||
ctx->hasextraobjs = true;
|
ctx->hasextraobjs = true;
|
||||||
|
|
||||||
|
@ -630,10 +525,13 @@ static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *body
|
||||||
Con_DPrintf("World_Bullet_RagCreateBody: unsupported geomshape %i\n", bodyinfo->geomshape);
|
Con_DPrintf("World_Bullet_RagCreateBody: unsupported geomshape %i\n", bodyinfo->geomshape);
|
||||||
case GEOMTYPE_BOX:
|
case GEOMTYPE_BOX:
|
||||||
geom = new btBoxShape(btVector3(bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]) * 0.5);
|
geom = new btBoxShape(btVector3(bodyinfo->dimensions[0], bodyinfo->dimensions[1], bodyinfo->dimensions[2]) * 0.5);
|
||||||
|
radius = sqrt(DotProduct(bodyinfo->dimensions,bodyinfo->dimensions));
|
||||||
|
threshold = min(bodyinfo->dimensions[0], min(bodyinfo->dimensions[1], bodyinfo->dimensions[2]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEOMTYPE_SPHERE:
|
case GEOMTYPE_SPHERE:
|
||||||
geom = new btSphereShape(bodyinfo->dimensions[0] * 0.5f);
|
threshold = radius = bodyinfo->dimensions[0] * 0.5f;
|
||||||
|
geom = new btSphereShape(radius);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEOMTYPE_CAPSULE:
|
case GEOMTYPE_CAPSULE:
|
||||||
|
@ -642,6 +540,8 @@ static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *body
|
||||||
case GEOMTYPE_CAPSULE_Z:
|
case GEOMTYPE_CAPSULE_Z:
|
||||||
radius = (bodyinfo->dimensions[0]+bodyinfo->dimensions[1]) * 0.5f;
|
radius = (bodyinfo->dimensions[0]+bodyinfo->dimensions[1]) * 0.5f;
|
||||||
geom = new btCapsuleShapeZ(radius, bodyinfo->dimensions[2]);
|
geom = new btCapsuleShapeZ(radius, bodyinfo->dimensions[2]);
|
||||||
|
threshold = min(radius, bodyinfo->dimensions[2]*0.5);
|
||||||
|
radius = max(radius, bodyinfo->dimensions[2]*0.5);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEOMTYPE_CYLINDER:
|
case GEOMTYPE_CYLINDER:
|
||||||
|
@ -650,6 +550,8 @@ static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *body
|
||||||
case GEOMTYPE_CYLINDER_Z:
|
case GEOMTYPE_CYLINDER_Z:
|
||||||
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5;
|
radius = (bodyinfo->dimensions[0] + bodyinfo->dimensions[1]) * 0.5;
|
||||||
geom = new btCylinderShapeZ(btVector3(radius, radius, bodyinfo->dimensions[2])*0.5);
|
geom = new btCylinderShapeZ(btVector3(radius, radius, bodyinfo->dimensions[2])*0.5);
|
||||||
|
threshold = min(radius, bodyinfo->dimensions[2]*0.5);
|
||||||
|
radius = max(radius, bodyinfo->dimensions[2]*0.5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bodyptr->geom = geom;
|
bodyptr->geom = geom;
|
||||||
|
@ -657,20 +559,21 @@ static qboolean QDECL World_Bullet_RagCreateBody(world_t *world, rbebody_t *body
|
||||||
//now create the body too
|
//now create the body too
|
||||||
|
|
||||||
btVector3 fallInertia(0, 0, 0);
|
btVector3 fallInertia(0, 0, 0);
|
||||||
((btCollisionShape*)geom)->calculateLocalInertia(bodyinfo->mass, fallInertia);
|
geom->calculateLocalInertia(bodyinfo->mass, fallInertia);
|
||||||
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(bodyinfo->mass, NULL, (btCollisionShape*)geom, fallInertia);
|
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(bodyinfo->mass, nullptr, geom, fallInertia);
|
||||||
MatToTransform(mat, fallRigidBodyCI.m_startWorldTransform);
|
MatToTransform(mat, fallRigidBodyCI.m_startWorldTransform);
|
||||||
body = new btRigidBody(fallRigidBodyCI);
|
body = new btRigidBody(fallRigidBodyCI);
|
||||||
body->setUserPointer(ent);
|
body->setUserPointer(ent);
|
||||||
bodyptr->body = (void*)body;
|
bodyptr->body = reinterpret_cast<void*>(body);
|
||||||
|
|
||||||
//motion threshhold should be speed/physicsframerate.
|
//motion threshhold should be speed/physicsframerate.
|
||||||
//FIXME: recalculate...
|
//FIXME: recalculate...
|
||||||
body->setCcdMotionThreshold((bodyinfo->dimensions[0]+bodyinfo->dimensions[1]+bodyinfo->dimensions[2])*(4/3));
|
body->setCcdMotionThreshold(threshold/64);
|
||||||
//radius should be the body's radius
|
//radius should be the body's radius
|
||||||
body->setCcdSweptSphereRadius((bodyinfo->dimensions[0]+bodyinfo->dimensions[1]+bodyinfo->dimensions[2])*(0.5/3));
|
|
||||||
|
|
||||||
ctx->dworld->addRigidBody(body, ent->xv->dimension_solid, ent->xv->dimension_hit);
|
body->setCcdSweptSphereRadius(radius);
|
||||||
|
|
||||||
|
ctx->dworld->addRigidBody(body, ent?ent->xv->dimension_solid:~0, ent?ent->xv->dimension_hit:~0);
|
||||||
|
|
||||||
return qtrue;
|
return qtrue;
|
||||||
}
|
}
|
||||||
|
@ -766,47 +669,77 @@ static void QDECL World_Bullet_RagMatrixFromJoint(rbejoint_t *joint, rbejointinf
|
||||||
|
|
||||||
static void QDECL World_Bullet_RagMatrixFromBody(world_t *world, rbebody_t *bodyptr, float *mat)
|
static void QDECL World_Bullet_RagMatrixFromBody(world_t *world, rbebody_t *bodyptr, float *mat)
|
||||||
{
|
{
|
||||||
// bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
|
//auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btRigidBody *body = (btRigidBody*)bodyptr->body;
|
auto body = reinterpret_cast<btRigidBody*>(bodyptr->body);
|
||||||
MatFromTransform(mat, body->getCenterOfMassTransform());
|
MatFromTransform(mat, body->getCenterOfMassTransform());
|
||||||
}
|
}
|
||||||
static void QDECL World_Bullet_RagEnableJoint(rbejoint_t *joint, qboolean enabled)
|
static void QDECL World_Bullet_RagEnableJoint(rbejoint_t *joint, qboolean enabled)
|
||||||
{
|
{
|
||||||
/*
|
auto j = reinterpret_cast<btTypedConstraint*>(joint->joint);
|
||||||
if (enabled)
|
j->setEnabled(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])
|
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])
|
||||||
{
|
{
|
||||||
/*
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
|
btTypedConstraint *j;
|
||||||
|
btVector3 org(aaa2[0][0], aaa2[0][1], aaa2[0][2]);
|
||||||
|
btVector3 axis1(aaa2[1][0], aaa2[1][1], aaa2[1][2]);
|
||||||
|
btVector3 axis2(aaa2[2][0], aaa2[2][1], aaa2[2][2]);
|
||||||
|
auto rb1 = reinterpret_cast<btRigidBody*>(body1->body);
|
||||||
|
auto rb2 = reinterpret_cast<btRigidBody*>(body2->body);
|
||||||
|
|
||||||
switch(info->type)
|
switch(info->type)
|
||||||
{
|
{
|
||||||
case JOINTTYPE_POINT:
|
case JOINTTYPE_POINT:
|
||||||
joint->ode_joint = dJointCreateBall(world->rbe.world, 0);
|
{
|
||||||
|
auto point = new btPoint2PointConstraint(*rb1, *rb2, rb1->getWorldTransform().getOrigin()-org, rb2->getWorldTransform().getOrigin()-org);
|
||||||
|
// point->setParam(BT_P2P_FLAGS_ERP, info->ERP);
|
||||||
|
// point->setParam(BT_P2P_FLAGS_CFM, info->CFM);
|
||||||
|
j = point;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JOINTTYPE_HINGE:
|
case JOINTTYPE_HINGE:
|
||||||
joint->ode_joint = dJointCreateHinge(world->rbe.world, 0);
|
{
|
||||||
break;
|
auto hinge = new btHingeConstraint(*rb1, *rb2, org, org, axis1, axis2);
|
||||||
case JOINTTYPE_SLIDER:
|
hinge->setLimit(info->LoStop, info->HiStop /*other stuff!*/);
|
||||||
joint->ode_joint = dJointCreateSlider(world->rbe.world, 0);
|
// hinge->setParam(BT_HINGE_FLAGS_CFM_NORM, info->CFM);
|
||||||
|
// hinge->setParam(BT_HINGE_FLAGS_CFM_STOP, info->CFM2);
|
||||||
|
// hinge->setParam(BT_HINGE_FLAGS_ERP_NORM, info->ERP);
|
||||||
|
// hinge->setParam(BT_HINGE_FLAGS_ERP_STOP, info->ERP2);
|
||||||
|
j = hinge;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
// case JOINTTYPE_SLIDER:
|
||||||
|
// j = btSliderConstraint(rb1, rb2, tr1, tr2, false);
|
||||||
|
// break;
|
||||||
case JOINTTYPE_UNIVERSAL:
|
case JOINTTYPE_UNIVERSAL:
|
||||||
joint->ode_joint = dJointCreateUniversal(world->rbe.world, 0);
|
{
|
||||||
|
auto uni = new btUniversalConstraint(*rb1, *rb2, org, axis1, axis2);
|
||||||
|
// uni->setParam(BT_6DOF_FLAGS_CFM_NORM, info->CFM);
|
||||||
|
// uni->setParam(BT_6DOF_FLAGS_CFM_STOP, info->CFM2);
|
||||||
|
// uni->setParam(BT_6DOF_FLAGS_ERP_STOP, info->ERP);
|
||||||
|
uni->setUpperLimit(info->HiStop, info->HiStop2);
|
||||||
|
uni->setLowerLimit(info->LoStop, info->LoStop2);
|
||||||
|
j = uni;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case JOINTTYPE_HINGE2:
|
case JOINTTYPE_HINGE2:
|
||||||
joint->ode_joint = dJointCreateHinge2(world->rbe.world, 0);
|
{
|
||||||
break;
|
auto hinge2 = new btHinge2Constraint(*rb1, *rb2, org, axis1, axis2);
|
||||||
case JOINTTYPE_FIXED:
|
hinge2->setUpperLimit(info->HiStop);
|
||||||
joint->ode_joint = dJointCreateFixed(world->rbe.world, 0);
|
hinge2->setLowerLimit(info->LoStop);
|
||||||
|
j = hinge2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
// case JOINTTYPE_FIXED:
|
||||||
|
// j = btFixedConstraint(rb1, rb2, tr1, tr2);
|
||||||
|
// break;
|
||||||
default:
|
default:
|
||||||
joint->ode_joint = NULL;
|
Con_Printf("Bullet: joint type %i not supported\n", info->type);
|
||||||
|
j = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (joint->ode_joint)
|
/* if (joint->ode_joint)
|
||||||
{
|
{
|
||||||
//Con_Printf("made new joint %i\n", (int) (ed - prog->edicts));
|
//Con_Printf("made new joint %i\n", (int) (ed - prog->edicts));
|
||||||
// dJointSetData(joint->ode_joint, NULL);
|
// dJointSetData(joint->ode_joint, NULL);
|
||||||
|
@ -876,16 +809,19 @@ static void QDECL World_Bullet_RagCreateJoint(world_t *world, rbejoint_t *joint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
if (j)
|
||||||
|
ctx->dworld->addConstraint(j, true);
|
||||||
|
joint->joint = reinterpret_cast<void*>(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void QDECL World_Bullet_RagDestroyBody(world_t *world, rbebody_t *bodyptr)
|
static void QDECL World_Bullet_RagDestroyBody(world_t *world, rbebody_t *bodyptr)
|
||||||
{
|
{
|
||||||
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btRigidBody *body = (btRigidBody*)bodyptr->body;
|
auto body = reinterpret_cast<btRigidBody*>(bodyptr->body);
|
||||||
btCollisionShape *geom = (btCollisionShape*)bodyptr->geom;
|
auto geom = reinterpret_cast<btCollisionShape*>(bodyptr->geom);
|
||||||
|
|
||||||
bodyptr->body = NULL;
|
bodyptr->body = nullptr;
|
||||||
bodyptr->geom = NULL;
|
bodyptr->geom = nullptr;
|
||||||
|
|
||||||
if (body)
|
if (body)
|
||||||
{
|
{
|
||||||
|
@ -898,11 +834,14 @@ static void QDECL World_Bullet_RagDestroyBody(world_t *world, rbebody_t *bodyptr
|
||||||
|
|
||||||
static void QDECL World_Bullet_RagDestroyJoint(world_t *world, rbejoint_t *joint)
|
static void QDECL World_Bullet_RagDestroyJoint(world_t *world, rbejoint_t *joint)
|
||||||
{
|
{
|
||||||
/*
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
if (joint->ode_joint)
|
auto j = reinterpret_cast<btTypedConstraint*>(joint->joint);
|
||||||
dJointDestroy(joint->ode_joint);
|
if (j)
|
||||||
joint->ode_joint = NULL;
|
{
|
||||||
*/
|
ctx->dworld->removeConstraint(j);
|
||||||
|
delete j;
|
||||||
|
}
|
||||||
|
joint->joint = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//bullet gives us a handy way to get/set motion states. we can cheesily update entity fields this way.
|
//bullet gives us a handy way to get/set motion states. we can cheesily update entity fields this way.
|
||||||
|
@ -980,8 +919,8 @@ public:
|
||||||
|
|
||||||
static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
{
|
{
|
||||||
bulletcontext_t *ctx = (bulletcontext_t*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btRigidBody *body = NULL;
|
btRigidBody *body = nullptr;
|
||||||
// btScalar mass;
|
// btScalar mass;
|
||||||
float test;
|
float test;
|
||||||
// void *dataID;
|
// void *dataID;
|
||||||
|
@ -1013,16 +952,16 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
// vec_t spinlimit;
|
// vec_t spinlimit;
|
||||||
qboolean gravity;
|
qboolean gravity;
|
||||||
|
|
||||||
geomtype = (int)ed->xv->geomtype;
|
geomtype = ed->xv->geomtype;
|
||||||
solid = (int)ed->v->solid;
|
solid = ed->v->solid;
|
||||||
movetype = (int)ed->v->movetype;
|
movetype = ed->v->movetype;
|
||||||
scale = ed->xv->scale?ed->xv->scale:1;
|
scale = ed->xv->scale?ed->xv->scale:1;
|
||||||
modelindex = 0;
|
modelindex = 0;
|
||||||
model = NULL;
|
model = nullptr;
|
||||||
|
|
||||||
if (!geomtype)
|
if (!geomtype)
|
||||||
{
|
{
|
||||||
switch((int)ed->v->solid)
|
switch(solid)
|
||||||
{
|
{
|
||||||
case SOLID_NOT: geomtype = GEOMTYPE_NONE; break;
|
case SOLID_NOT: geomtype = GEOMTYPE_NONE; break;
|
||||||
case SOLID_TRIGGER: geomtype = GEOMTYPE_NONE; break;
|
case SOLID_TRIGGER: geomtype = GEOMTYPE_NONE; break;
|
||||||
|
@ -1039,11 +978,11 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
switch(geomtype)
|
switch(geomtype)
|
||||||
{
|
{
|
||||||
case GEOMTYPE_TRIMESH:
|
case GEOMTYPE_TRIMESH:
|
||||||
modelindex = (int)ed->v->modelindex;
|
modelindex = ed->v->modelindex;
|
||||||
model = world->Get_CModel(world, modelindex);
|
model = world->Get_CModel(world, modelindex);
|
||||||
if (!model || model->loadstate != MLS_LOADED)
|
if (!model || model->loadstate != MLS_LOADED)
|
||||||
{
|
{
|
||||||
model = NULL;
|
model = nullptr;
|
||||||
modelindex = 0;
|
modelindex = 0;
|
||||||
}
|
}
|
||||||
if (model)
|
if (model)
|
||||||
|
@ -1122,7 +1061,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
{
|
{
|
||||||
case GEOMTYPE_TRIMESH:
|
case GEOMTYPE_TRIMESH:
|
||||||
// foo Matrix4x4_Identity(ed->rbe.offsetmatrix);
|
// foo Matrix4x4_Identity(ed->rbe.offsetmatrix);
|
||||||
geom = NULL;
|
geom = nullptr;
|
||||||
if (!model)
|
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));
|
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));
|
||||||
|
@ -1283,7 +1222,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ed->rbe.body.body == NULL)
|
if (ed->rbe.body.body == nullptr)
|
||||||
{
|
{
|
||||||
btRigidBody::btRigidBodyConstructionInfo rbci(ed->rbe.mass, new QCMotionState(ed,world), (btCollisionShape*)ed->rbe.body.geom, btVector3(0, 0, 0));
|
btRigidBody::btRigidBodyConstructionInfo rbci(ed->rbe.mass, new QCMotionState(ed,world), (btCollisionShape*)ed->rbe.body.geom, btVector3(0, 0, 0));
|
||||||
body = new btRigidBody(rbci);
|
body = new btRigidBody(rbci);
|
||||||
|
@ -1432,7 +1371,7 @@ static void World_Bullet_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
||||||
// r[1][2] = up[1];
|
// r[1][2] = up[1];
|
||||||
// r[2][2] = up[2];
|
// r[2][2] = up[2];
|
||||||
|
|
||||||
QCMotionState *ms = (QCMotionState*)body->getMotionState();
|
auto ms = (QCMotionState*)body->getMotionState();
|
||||||
ms->ReloadMotionState();
|
ms->ReloadMotionState();
|
||||||
body->setMotionState(ms);
|
body->setMotionState(ms);
|
||||||
body->setLinearVelocity(btVector3(velocity[0], velocity[1], velocity[2]));
|
body->setLinearVelocity(btVector3(velocity[0], velocity[1], velocity[2]));
|
||||||
|
@ -1616,7 +1555,7 @@ static void VARGS nearCallback (void *data, dGeomID o1, dGeomID o2)
|
||||||
|
|
||||||
static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gravity)
|
static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gravity)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
if (world->rbe_hasphysicsents || ctx->hasextraobjs)
|
if (world->rbe_hasphysicsents || ctx->hasextraobjs)
|
||||||
{
|
{
|
||||||
int iters;
|
int iters;
|
||||||
|
@ -1631,23 +1570,23 @@ static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gr
|
||||||
// copy physics properties from entities to physics engine
|
// copy physics properties from entities to physics engine
|
||||||
for (i = 0;i < world->num_edicts;i++)
|
for (i = 0;i < world->num_edicts;i++)
|
||||||
{
|
{
|
||||||
ed = (wedict_t*)EDICT_NUM_PB(world->progs, i);
|
ed = WEDICT_NUM_PB(world->progs, i);
|
||||||
if (!ED_ISFREE(ed))
|
if (!ED_ISFREE(ed))
|
||||||
World_Bullet_Frame_BodyFromEntity(world, ed);
|
World_Bullet_Frame_BodyFromEntity(world, ed);
|
||||||
}
|
}
|
||||||
// oh, and it must be called after all bodies were created
|
// oh, and it must be called after all bodies were created
|
||||||
for (i = 0;i < world->num_edicts;i++)
|
for (i = 0;i < world->num_edicts;i++)
|
||||||
{
|
{
|
||||||
ed = (wedict_t*)EDICT_NUM_PB(world->progs, i);
|
ed = WEDICT_NUM_PB(world->progs, i);
|
||||||
if (!ED_ISFREE(ed))
|
if (!ED_ISFREE(ed))
|
||||||
World_Bullet_Frame_JointFromEntity(world, ed);
|
World_Bullet_Frame_JointFromEntity(world, ed);
|
||||||
}
|
}
|
||||||
while(ctx->cmdqueuehead)
|
while(ctx->cmdqueuehead)
|
||||||
{
|
{
|
||||||
rbecommandqueue_t *cmd = ctx->cmdqueuehead;
|
auto cmd = ctx->cmdqueuehead;
|
||||||
ctx->cmdqueuehead = cmd->next;
|
ctx->cmdqueuehead = cmd->next;
|
||||||
if (!cmd->next)
|
if (!cmd->next)
|
||||||
ctx->cmdqueuetail = NULL;
|
ctx->cmdqueuetail = nullptr;
|
||||||
World_Bullet_RunCmd(world, cmd);
|
World_Bullet_RunCmd(world, cmd);
|
||||||
Z_Free(cmd);
|
Z_Free(cmd);
|
||||||
}
|
}
|
||||||
|
@ -1676,23 +1615,12 @@ static void QDECL World_Bullet_Frame(world_t *world, double frametime, double gr
|
||||||
|
|
||||||
// clear the JointGroup now that we're done with it
|
// clear the JointGroup now that we're done with it
|
||||||
// dJointGroupEmpty(world->rbe.contactgroup);
|
// dJointGroupEmpty(world->rbe.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_PB(world->progs, i);
|
|
||||||
if (!ED_ISFREE(ed))
|
|
||||||
World_Bullet_Frame_BodyToEntity(world, ed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd)
|
static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd)
|
||||||
{
|
{
|
||||||
btRigidBody *body = (btRigidBody*)(cmd->edict->rbe.body.body);
|
auto body = (btRigidBody*)(cmd->edict->rbe.body.body);
|
||||||
switch(cmd->command)
|
switch(cmd->command)
|
||||||
{
|
{
|
||||||
case RBECMD_ENABLE:
|
case RBECMD_ENABLE:
|
||||||
|
@ -1725,15 +1653,15 @@ static void World_Bullet_RunCmd(world_t *world, rbecommandqueue_t *cmd)
|
||||||
|
|
||||||
static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *val)
|
static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *val)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
rbecommandqueue_t *cmd = (rbecommandqueue_t*)BZ_Malloc(sizeof(*cmd));
|
auto cmd = (rbecommandqueue_t*)BZ_Malloc(sizeof(rbecommandqueue_t));
|
||||||
world->rbe_hasphysicsents = qtrue; //just in case.
|
world->rbe_hasphysicsents = qtrue; //just in case.
|
||||||
memcpy(cmd, val, sizeof(*cmd));
|
memcpy(cmd, val, sizeof(*cmd));
|
||||||
cmd->next = NULL;
|
cmd->next = nullptr;
|
||||||
//add on the end of the queue, so that order is preserved.
|
//add on the end of the queue, so that order is preserved.
|
||||||
if (ctx->cmdqueuehead)
|
if (ctx->cmdqueuehead)
|
||||||
{
|
{
|
||||||
rbecommandqueue_t *ot = ctx->cmdqueuetail;
|
auto ot = ctx->cmdqueuetail;
|
||||||
ot->next = ctx->cmdqueuetail = cmd;
|
ot->next = ctx->cmdqueuetail = cmd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1742,8 +1670,8 @@ static void QDECL World_Bullet_PushCommand(world_t *world, rbecommandqueue_t *va
|
||||||
|
|
||||||
static void QDECL World_Bullet_TraceEntity(world_t *world, wedict_t *ed, vec3_t start, vec3_t end, trace_t *trace)
|
static void QDECL World_Bullet_TraceEntity(world_t *world, wedict_t *ed, vec3_t start, vec3_t end, trace_t *trace)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx = (struct bulletcontext_s*)world->rbe;
|
auto ctx = reinterpret_cast<bulletcontext_t*>(world->rbe);
|
||||||
btCollisionShape *shape = (btCollisionShape*)ed->rbe.body.geom;
|
auto shape = (btCollisionShape*)ed->rbe.body.geom;
|
||||||
|
|
||||||
//btCollisionAlgorithm
|
//btCollisionAlgorithm
|
||||||
class myConvexResultCallback : public btCollisionWorld::ConvexResultCallback
|
class myConvexResultCallback : public btCollisionWorld::ConvexResultCallback
|
||||||
|
@ -1764,7 +1692,7 @@ static void QDECL World_Bullet_TraceEntity(world_t *world, wedict_t *ed, vec3_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} result;
|
} result;
|
||||||
result.m_impactent = NULL;
|
result.m_impactent = nullptr;
|
||||||
result.m_closestHitFraction = trace->fraction;
|
result.m_closestHitFraction = trace->fraction;
|
||||||
|
|
||||||
btTransform from(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(start[0], start[1], start[2]));
|
btTransform from(btMatrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1), btVector3(start[0], start[1], start[2]));
|
||||||
|
@ -1785,14 +1713,14 @@ static void QDECL World_Bullet_TraceEntity(world_t *world, wedict_t *ed, vec3_t
|
||||||
|
|
||||||
static void QDECL World_Bullet_Start(world_t *world)
|
static void QDECL World_Bullet_Start(world_t *world)
|
||||||
{
|
{
|
||||||
struct bulletcontext_s *ctx;
|
bulletcontext_t *ctx;
|
||||||
if (world->rbe)
|
if (world->rbe)
|
||||||
return; //no thanks, we already have one. somehow.
|
return; //no thanks, we already have one. somehow.
|
||||||
|
|
||||||
if (!physics_bullet_enable->value)
|
if (!physics_bullet_enable->value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ctx = (struct bulletcontext_s*)BZ_Malloc(sizeof(*ctx));
|
ctx = reinterpret_cast<bulletcontext_t*>(BZ_Malloc(sizeof(*ctx)));
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
ctx->gworld = world;
|
ctx->gworld = world;
|
||||||
ctx->funcs.End = World_Bullet_End;
|
ctx->funcs.End = World_Bullet_End;
|
||||||
|
@ -1869,7 +1797,7 @@ static bool World_Bullet_DoInit(void)
|
||||||
{
|
{
|
||||||
if (!rbefuncs || !rbefuncs->RegisterPhysicsEngine)
|
if (!rbefuncs || !rbefuncs->RegisterPhysicsEngine)
|
||||||
{
|
{
|
||||||
rbefuncs = NULL;
|
rbefuncs = nullptr;
|
||||||
Con_Printf("Bullet plugin failed: Engine doesn't support physics engine plugins.\n");
|
Con_Printf("Bullet plugin failed: Engine doesn't support physics engine plugins.\n");
|
||||||
}
|
}
|
||||||
else if (!rbefuncs->RegisterPhysicsEngine("Bullet", World_Bullet_Start))
|
else if (!rbefuncs->RegisterPhysicsEngine("Bullet", World_Bullet_Start))
|
||||||
|
|
Loading…
Reference in a new issue