#include "quakedef.h"
#include "clvm_cmds.h"
+#include "cl_collision.h"
/*
if (world->areagrid_marknumber < 1)
world->areagrid_marknumber = 1;
// choose either the world box size, or a larger box to ensure the grid isn't too fine
- world->areagrid_size[0] = max(world->areagrid_maxs[0] - world->areagrid_mins[0], AREA_GRID * sv_areagrid_mingridsize.value);
- world->areagrid_size[1] = max(world->areagrid_maxs[1] - world->areagrid_mins[1], AREA_GRID * sv_areagrid_mingridsize.value);
- world->areagrid_size[2] = max(world->areagrid_maxs[2] - world->areagrid_mins[2], AREA_GRID * sv_areagrid_mingridsize.value);
+ world->areagrid_size[0] = max(world->maxs[0] - world->mins[0], AREA_GRID * sv_areagrid_mingridsize.value);
+ world->areagrid_size[1] = max(world->maxs[1] - world->mins[1], AREA_GRID * sv_areagrid_mingridsize.value);
+ world->areagrid_size[2] = max(world->maxs[2] - world->mins[2], AREA_GRID * sv_areagrid_mingridsize.value);
// figure out the corners of such a box, centered at the center of the world box
- world->areagrid_mins[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] - world->areagrid_size[0]) * 0.5f;
- world->areagrid_mins[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] - world->areagrid_size[1]) * 0.5f;
- world->areagrid_mins[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] - world->areagrid_size[2]) * 0.5f;
- world->areagrid_maxs[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] + world->areagrid_size[0]) * 0.5f;
- world->areagrid_maxs[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] + world->areagrid_size[1]) * 0.5f;
- world->areagrid_maxs[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] + world->areagrid_size[2]) * 0.5f;
+ world->areagrid_mins[0] = (world->mins[0] + world->maxs[0] - world->areagrid_size[0]) * 0.5f;
+ world->areagrid_mins[1] = (world->mins[1] + world->maxs[1] - world->areagrid_size[1]) * 0.5f;
+ world->areagrid_mins[2] = (world->mins[2] + world->maxs[2] - world->areagrid_size[2]) * 0.5f;
+ world->areagrid_maxs[0] = (world->mins[0] + world->maxs[0] + world->areagrid_size[0]) * 0.5f;
+ world->areagrid_maxs[1] = (world->mins[1] + world->maxs[1] + world->areagrid_size[1]) * 0.5f;
+ world->areagrid_maxs[2] = (world->mins[2] + world->maxs[2] + world->areagrid_size[2]) * 0.5f;
// now calculate the actual useful info from that
VectorNegate(world->areagrid_mins, world->areagrid_bias);
world->areagrid_scale[0] = AREA_GRID / world->areagrid_size[0];
World_ClearLink(&world->areagrid_outside);
for (i = 0;i < AREA_GRIDNODES;i++)
World_ClearLink(&world->areagrid[i]);
- if (developer.integer >= 10)
- Con_Printf("areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, world->areagrid_mins[0], world->areagrid_mins[1], world->areagrid_mins[2], world->areagrid_maxs[0], world->areagrid_maxs[1], world->areagrid_maxs[2], world->areagrid_size[0], world->areagrid_size[1], world->areagrid_size[2], 1.0f / world->areagrid_scale[0], 1.0f / world->areagrid_scale[1], 1.0f / world->areagrid_scale[2], sv_areagrid_mingridsize.value);
+ if (developer_extra.integer)
+ Con_DPrintf("areagrid settings: divisions %ix%ix1 : box %f %f %f : %f %f %f size %f %f %f grid %f %f %f (mingrid %f)\n", AREA_GRID, AREA_GRID, world->areagrid_mins[0], world->areagrid_mins[1], world->areagrid_mins[2], world->areagrid_maxs[0], world->areagrid_maxs[1], world->areagrid_maxs[2], world->areagrid_size[0], world->areagrid_size[1], world->areagrid_size[2], 1.0f / world->areagrid_scale[0], 1.0f / world->areagrid_scale[1], 1.0f / world->areagrid_scale[2], sv_areagrid_mingridsize.value);
}
/*
// physics engine support
//============================================================================
-//#ifndef ODE_STATIC
-//#define ODE_DYNAMIC 1
-//#endif
+#ifndef ODE_STATIC
+# define ODE_DYNAMIC 1
+#endif
#if defined(ODE_STATIC) || defined(ODE_DYNAMIC)
#define USEODE 1
cvar_t physics_ode_contact_cfm = {0, "physics_ode_contact_cfm", "0", "contact solver cfm parameter - Constraint Force Mixing (see ODE User Guide)"};
cvar_t physics_ode_world_erp = {0, "physics_ode_world_erp", "-1", "world solver erp parameter - Error Restitution Percent (see ODE User Guide); use defaults when set to -1"};
cvar_t physics_ode_world_cfm = {0, "physics_ode_world_cfm", "-1", "world solver cfm parameter - Constraint Force Mixing (see ODE User Guide); not touched when -1"};
-cvar_t physics_ode_iterationsperframe = {0, "physics_ode_iterationsperframe", "4", "divisor for time step, runs multiple physics steps per frame"};
+cvar_t physics_ode_iterationsperframe = {0, "physics_ode_iterationsperframe", "1", "divisor for time step, runs multiple physics steps per frame"};
cvar_t physics_ode_movelimit = {0, "physics_ode_movelimit", "0.5", "clamp velocity if a single move would exceed this percentage of object thickness, to prevent flying through walls"};
cvar_t physics_ode_spinlimit = {0, "physics_ode_spinlimit", "10000", "reset spin velocity if it gets too large"};
+cvar_t physics_ode = {0, "physics_ode", "0", "run ODE physics (VERY experimental and potentially buggy)"};
// LordHavoc: this large chunk of definitions comes from the ODE library
// include files.
#ifdef ODE_DYNAMIC
const char* dllnames [] =
{
-# if defined(WIN64)
- "libode1_64.dll",
-# elif defined(WIN32)
+# if defined(WIN32)
"libode1.dll",
# elif defined(MACOSX)
"libode.1.dylib",
Cvar_RegisterVariable(&physics_ode_iterationsperframe);
Cvar_RegisterVariable(&physics_ode_movelimit);
Cvar_RegisterVariable(&physics_ode_spinlimit);
+ Cvar_RegisterVariable(&physics_ode);
#ifdef ODE_DYNAMIC
// Load the DLL
world->physics.ode_space = dQuadTreeSpaceCreate(NULL, center, extents, bound(1, physics_ode_quadtree_depth.integer, 10));
world->physics.ode_contactgroup = dJointGroupCreate(0);
if(physics_ode_world_erp.value >= 0)
- dWorldSetERP(world->physics.ode_world, physics_ode_world_erp.value);
+ dWorldSetERP((dWorldID)world->physics.ode_world, physics_ode_world_erp.value);
if(physics_ode_world_cfm.value >= 0)
- dWorldSetCFM(world->physics.ode_world, physics_ode_world_cfm.value);
+ dWorldSetCFM((dWorldID)world->physics.ode_world, physics_ode_world_cfm.value);
}
#endif
#ifdef USEODE
if (world->physics.ode)
{
- dWorldDestroy(world->physics.ode_world);
- dSpaceDestroy(world->physics.ode_space);
- dJointGroupDestroy(world->physics.ode_contactgroup);
+ dWorldDestroy((dWorldID)world->physics.ode_world);
+ dSpaceDestroy((dSpaceID)world->physics.ode_space);
+ dJointGroupDestroy((dJointGroupID)world->physics.ode_contactgroup);
world->physics.ode = false;
}
#endif
movetype = (int)val->_float;
if (movetype != MOVETYPE_PHYSICS)
{
- val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
+ jointtype = 0;val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
switch(jointtype)
{
// TODO feed back data from physics
VectorCopy(velocity, ed->priv.server->ode_velocity);
VectorCopy(angles, ed->priv.server->ode_angles);
VectorCopy(avelocity, ed->priv.server->ode_avelocity);
- ed->priv.server->ode_gravity = dBodyGetGravityMode(body);
+ ed->priv.server->ode_gravity = dBodyGetGravityMode(body) != 0;
if(!strcmp(prog->name, "server")) // FIXME some better way?
{
switch(jointtype)
{
case JOINTTYPE_POINT:
- j = dJointCreateBall(world->physics.ode_world, 0);
+ j = dJointCreateBall((dWorldID)world->physics.ode_world, 0);
break;
case JOINTTYPE_HINGE:
- j = dJointCreateHinge(world->physics.ode_world, 0);
+ j = dJointCreateHinge((dWorldID)world->physics.ode_world, 0);
break;
case JOINTTYPE_SLIDER:
- j = dJointCreateSlider(world->physics.ode_world, 0);
+ j = dJointCreateSlider((dWorldID)world->physics.ode_world, 0);
break;
case JOINTTYPE_UNIVERSAL:
- j = dJointCreateUniversal(world->physics.ode_world, 0);
+ j = dJointCreateUniversal((dWorldID)world->physics.ode_world, 0);
break;
case JOINTTYPE_HINGE2:
- j = dJointCreateHinge2(world->physics.ode_world, 0);
+ j = dJointCreateHinge2((dWorldID)world->physics.ode_world, 0);
break;
case JOINTTYPE_FIXED:
- j = dJointCreateFixed(world->physics.ode_world, 0);
+ j = dJointCreateFixed((dWorldID)world->physics.ode_world, 0);
break;
case 0:
default:
if(ed->priv.server->ode_joint)
{
//Con_Printf("deleted old joint %i\n", (int) (ed - prog->edicts));
- dJointAttach(ed->priv.server->ode_joint, 0, 0);
- dJointDestroy(ed->priv.server->ode_joint);
+ dJointAttach((dJointID)ed->priv.server->ode_joint, 0, 0);
+ dJointDestroy((dJointID)ed->priv.server->ode_joint);
}
ed->priv.server->ode_joint = (void *) j;
ed->priv.server->ode_joint_type = jointtype;
if (!ode_dll)
return;
#endif
+ VectorClear(entmins);
+ VectorClear(entmaxs);
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.solid);if (val) solid = (int)val->_float;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);if (val) movetype = (int)val->_float;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale);if (val && val->_float) scale = val->_float;
mempool = cls.levelmempool;
else
mempool = NULL;
+ model = NULL;
switch(solid)
{
case SOLID_BSP:
if (!model)
{
Con_Printf("entity %i (classname %s) has no model\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string));
- break;
+ goto treatasbox;
}
// add an optimized mesh to the model containing only the SUPERCONTENTS_SOLID surfaces
if (!model->brush.collisionmesh)
if (!model->brush.collisionmesh || !model->brush.collisionmesh->numtriangles)
{
Con_Printf("entity %i (classname %s) has no geometry\n", PRVM_NUM_FOR_EDICT(ed), PRVM_GetString(PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.classname)->string));
- break;
+ goto treatasbox;
}
// ODE requires persistent mesh storage, so we need to copy out
// the data from the model because renderer restarts could free it
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
// now create the geom
dataID = dGeomTriMeshDataCreate();
- dGeomTriMeshDataBuildSingle(dataID, (void*)ed->priv.server->ode_vertex3f, sizeof(float[3]), ed->priv.server->ode_numvertices, ed->priv.server->ode_element3i, ed->priv.server->ode_numtriangles*3, sizeof(int[3]));
- ed->priv.server->ode_geom = (void *)dCreateTriMesh(world->physics.ode_space, dataID, NULL, NULL, NULL);
+ dGeomTriMeshDataBuildSingle((dTriMeshDataID)dataID, (void*)ed->priv.server->ode_vertex3f, sizeof(float[3]), ed->priv.server->ode_numvertices, ed->priv.server->ode_element3i, ed->priv.server->ode_numtriangles*3, sizeof(int[3]));
+ ed->priv.server->ode_geom = (void *)dCreateTriMesh((dSpaceID)world->physics.ode_space, (dTriMeshDataID)dataID, NULL, NULL, NULL);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
break;
case SOLID_BBOX:
case SOLID_SLIDEBOX:
case SOLID_CORPSE:
case SOLID_PHYSICS_BOX:
+treatasbox:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
- ed->priv.server->ode_geom = (void *)dCreateBox(world->physics.ode_space, geomsize[0], geomsize[1], geomsize[2]);
+ ed->priv.server->ode_geom = (void *)dCreateBox((dSpaceID)world->physics.ode_space, geomsize[0], geomsize[1], geomsize[2]);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
break;
case SOLID_PHYSICS_SPHERE:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
- ed->priv.server->ode_geom = (void *)dCreateSphere(world->physics.ode_space, geomsize[0] * 0.5f);
+ ed->priv.server->ode_geom = (void *)dCreateSphere((dSpaceID)world->physics.ode_space, geomsize[0] * 0.5f);
dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f);
break;
case SOLID_PHYSICS_CAPSULE:
// because we want to support more than one axisindex, we have to
// create a transform, and turn on its cleanup setting (which will
// cause the child to be destroyed when it is destroyed)
- ed->priv.server->ode_geom = (void *)dCreateCapsule(world->physics.ode_space, radius, length);
+ ed->priv.server->ode_geom = (void *)dCreateCapsule((dSpaceID)world->physics.ode_space, radius, length);
dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length);
break;
default:
Sys_Error("World_Physics_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
+ // this goto only exists to prevent warnings from the compiler
+ // about uninitialized variables (mass), while allowing it to
+ // catch legitimate uninitialized variable warnings
+ goto treatasbox;
}
Matrix4x4_Invert_Simple(&ed->priv.server->ode_offsetimatrix, &ed->priv.server->ode_offsetmatrix);
ed->priv.server->ode_massbuf = Mem_Alloc(mempool, sizeof(mass));
}
if(ed->priv.server->ode_geom)
- dGeomSetData(ed->priv.server->ode_geom, (void*)ed);
+ dGeomSetData((dGeomID)ed->priv.server->ode_geom, (void*)ed);
if (movetype == MOVETYPE_PHYSICS && ed->priv.server->ode_geom)
{
if (ed->priv.server->ode_body == NULL)
{
- ed->priv.server->ode_body = (void *)(body = dBodyCreate(world->physics.ode_world));
- dGeomSetBody(ed->priv.server->ode_geom, body);
+ ed->priv.server->ode_body = (void *)(body = dBodyCreate((dWorldID)world->physics.ode_world));
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body);
dBodySetData(body, (void*)ed);
dBodySetMass(body, (dMass *) ed->priv.server->ode_massbuf);
modified = true;
if (ed->priv.server->ode_body != NULL)
{
if(ed->priv.server->ode_geom)
- dGeomSetBody(ed->priv.server->ode_geom, 0);
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0);
dBodyDestroy((dBodyID) ed->priv.server->ode_body);
ed->priv.server->ode_body = NULL;
modified = true;
modified = true;
// store the qc values into the physics engine
- body = ed->priv.server->ode_body;
+ body = (dBodyID)ed->priv.server->ode_body;
if (modified && ed->priv.server->ode_geom)
{
dVector3 r[3];
{
if(movetype == MOVETYPE_PHYSICS)
{
- dGeomSetBody(ed->priv.server->ode_geom, body);
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body);
dBodySetPosition(body, origin[0], origin[1], origin[2]);
dBodySetRotation(body, r[0]);
dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]);
}
else
{
- dGeomSetBody(ed->priv.server->ode_geom, body);
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body);
dBodySetPosition(body, origin[0], origin[1], origin[2]);
dBodySetRotation(body, r[0]);
dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]);
dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]);
dBodySetGravityMode(body, gravity);
- dGeomSetBody(ed->priv.server->ode_geom, 0);
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0);
}
}
else
{
// no body... then let's adjust the parameters of the geom directly
- dGeomSetBody(ed->priv.server->ode_geom, 0); // just in case we previously HAD a body (which should never happen)
- dGeomSetPosition(ed->priv.server->ode_geom, origin[0], origin[1], origin[2]);
- dGeomSetRotation(ed->priv.server->ode_geom, r[0]);
+ dGeomSetBody((dGeomID)ed->priv.server->ode_geom, 0); // just in case we previously HAD a body (which should never happen)
+ dGeomSetPosition((dGeomID)ed->priv.server->ode_geom, origin[0], origin[1], origin[2]);
+ dGeomSetRotation((dGeomID)ed->priv.server->ode_geom, r[0]);
}
}
bouncefactor1 = bouncefactor2;
}
}
- dWorldGetGravity(world->physics.ode_world, grav);
+ dWorldGetGravity((dWorldID)world->physics.ode_world, grav);
bouncestop1 *= fabs(grav[2]);
// generate contact points between the two non-space geoms
contact[i].surface.soft_cfm = physics_ode_contact_cfm.value;
contact[i].surface.bounce = bouncefactor1;
contact[i].surface.bounce_vel = bouncestop1;
- c = dJointCreateContact(world->physics.ode_world, world->physics.ode_contactgroup, contact + i);
+ c = dJointCreateContact((dWorldID)world->physics.ode_world, (dJointGroupID)world->physics.ode_contactgroup, contact + i);
dJointAttach(c, b1, b2);
}
}
void World_Physics_Frame(world_t *world, double frametime, double gravity)
{
#ifdef USEODE
- if (world->physics.ode)
+ if (world->physics.ode && physics_ode.integer)
{
int i;
prvm_edict_t *ed;
for (i = 0;i < world->physics.ode_iterations;i++)
{
// set the gravity
- dWorldSetGravity(world->physics.ode_world, 0, 0, -gravity);
+ dWorldSetGravity((dWorldID)world->physics.ode_world, 0, 0, -gravity);
// set the tolerance for closeness of objects
- dWorldSetContactSurfaceLayer(world->physics.ode_world, max(0, physics_ode_contactsurfacelayer.value));
+ dWorldSetContactSurfaceLayer((dWorldID)world->physics.ode_world, max(0, physics_ode_contactsurfacelayer.value));
// run collisions for the current world state, creating JointGroup
- dSpaceCollide(world->physics.ode_space, (void *)world, nearCallback);
+ dSpaceCollide((dSpaceID)world->physics.ode_space, (void *)world, nearCallback);
// run physics (move objects, calculate new velocities)
if (physics_ode_worldquickstep.integer)
{
- dWorldSetQuickStepNumIterations(world->physics.ode_world, bound(1, physics_ode_worldquickstep_iterations.integer, 200));
- dWorldQuickStep(world->physics.ode_world, world->physics.ode_step);
+ dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldquickstep_iterations.integer, 200));
+ dWorldQuickStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
}
else if (physics_ode_worldstepfast.integer)
- dWorldStepFast1(world->physics.ode_world, world->physics.ode_step, bound(1, physics_ode_worldstepfast_iterations.integer, 200));
+ dWorldStepFast1((dWorldID)world->physics.ode_world, world->physics.ode_step, bound(1, physics_ode_worldstepfast_iterations.integer, 200));
else
- dWorldStep(world->physics.ode_world, world->physics.ode_step);
+ dWorldStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
// clear the JointGroup now that we're done with it
- dJointGroupEmpty(world->physics.ode_contactgroup);
+ dJointGroupEmpty((dJointGroupID)world->physics.ode_contactgroup);
}
// copy physics properties from physics engine to entities