numlist = 0;
// add entities not linked into areagrid because they are too big or
// outside the grid bounds
- if (world->areagrid_outside.next != &world->areagrid_outside)
+ if (world->areagrid_outside.next)
{
grid = &world->areagrid_outside;
for (l = grid->next;l != grid;l = l->next)
grid = world->areagrid + igrid[1] * AREA_GRID + igridmins[0];
for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
{
- if (grid->next != grid)
+ if (grid->next)
{
for (l = grid->next;l != grid;l = l->next)
{
#define USEODE 1
#endif
-// recent ODE trunk has dWorldStepFast1 removed
-//#define ODE_USE_STEPFAST
-
#ifdef USEODE
cvar_t physics_ode_quadtree_depth = {0, "physics_ode_quadtree_depth","5", "desired subdivision level of quadtree culling space"};
cvar_t physics_ode_contactsurfacelayer = {0, "physics_ode_contactsurfacelayer","1", "allows objects to overlap this many units to reduce jitter"};
-cvar_t physics_ode_worldstep = {0, "physics_ode_worldstep","2", "step function to use, 0 - dWorldStep, 1 - dWorldStepFast1, 2 - dWorldQuickStep"};
-cvar_t physics_ode_worldstep_iterations = {0, "physics_ode_worldstep_iterations", "20", "parameter to dWorldQuickStep and dWorldStepFast1"};
+cvar_t physics_ode_worldstep_iterations = {0, "physics_ode_worldstep_iterations", "20", "parameter to dWorldQuickStep"};
cvar_t physics_ode_contact_mu = {0, "physics_ode_contact_mu", "1", "contact solver mu parameter - friction pyramid approximation 1 (see ODE User Guide)"};
cvar_t physics_ode_contact_erp = {0, "physics_ode_contact_erp", "0.96", "contact solver erp parameter - Error Restitution Percent (see ODE User Guide)"};
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_damping_angular_threshold = {0, "physics_ode_world_damping_angular_threshold", "0.01", "world angular damping threshold (see ODE User Guide); use defaults when set to -1"};
cvar_t physics_ode_world_gravitymod = {0, "physics_ode_world_gravitymod", "1", "multiplies gravity got from sv_gravity, this may be needed to tweak if strong damping is used"};
cvar_t physics_ode_iterationsperframe = {0, "physics_ode_iterationsperframe", "1", "divisor for time step, runs multiple physics steps per frame"};
-cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "1", "use constant step (sys_ticrate value) instead of variable step which tends to increase stability"};
+cvar_t physics_ode_constantstep = {0, "physics_ode_constantstep", "0", "use constant step instead of variable step which tends to increase stability, if set to 1 uses sys_ticrate, instead uses it's own value"};
cvar_t physics_ode_autodisable = {0, "physics_ode_autodisable", "1", "automatic disabling of objects which dont move for long period of time, makes object stacking a lot faster"};
cvar_t physics_ode_autodisable_steps = {0, "physics_ode_autodisable_steps", "10", "how many steps object should be dormant to be autodisabled"};
cvar_t physics_ode_autodisable_time = {0, "physics_ode_autodisable_time", "0", "how many seconds object should be dormant to be autodisabled"};
//dReal (ODE_API *dWorldGetERP)(dWorldID);
void (ODE_API *dWorldSetCFM)(dWorldID, dReal cfm);
//dReal (ODE_API *dWorldGetCFM)(dWorldID);
-void (ODE_API *dWorldStep)(dWorldID, dReal stepsize);
+//void (ODE_API *dWorldStep)(dWorldID, dReal stepsize);
//void (ODE_API *dWorldImpulseToForce)(dWorldID, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force);
void (ODE_API *dWorldQuickStep)(dWorldID w, dReal stepsize);
void (ODE_API *dWorldSetQuickStepNumIterations)(dWorldID, int num);
//dReal (ODE_API *dWorldGetContactMaxCorrectingVel)(dWorldID);
void (ODE_API *dWorldSetContactSurfaceLayer)(dWorldID, dReal depth);
//dReal (ODE_API *dWorldGetContactSurfaceLayer)(dWorldID);
-#ifdef ODE_USE_STEPFAST
-void (ODE_API *dWorldStepFast1)(dWorldID, dReal stepsize, int maxiterations);
-#endif
+//void (ODE_API *dWorldStepFast1)(dWorldID, dReal stepsize, int maxiterations);
//void (ODE_API *dWorldSetAutoEnableDepthSF1)(dWorldID, int autoEnableDepth);
//int (ODE_API *dWorldGetAutoEnableDepthSF1)(dWorldID);
//dReal (ODE_API *dWorldGetAutoDisableLinearThreshold)(dWorldID);
// {"dWorldGetERP", (void **) &dWorldGetERP},
{"dWorldSetCFM", (void **) &dWorldSetCFM},
// {"dWorldGetCFM", (void **) &dWorldGetCFM},
- {"dWorldStep", (void **) &dWorldStep},
+// {"dWorldStep", (void **) &dWorldStep},
// {"dWorldImpulseToForce", (void **) &dWorldImpulseToForce},
{"dWorldQuickStep", (void **) &dWorldQuickStep},
{"dWorldSetQuickStepNumIterations", (void **) &dWorldSetQuickStepNumIterations},
// {"dWorldGetContactMaxCorrectingVel", (void **) &dWorldGetContactMaxCorrectingVel},
{"dWorldSetContactSurfaceLayer", (void **) &dWorldSetContactSurfaceLayer},
// {"dWorldGetContactSurfaceLayer", (void **) &dWorldGetContactSurfaceLayer},
-#ifdef ODE_USE_STEPFAST
- {"dWorldStepFast1", (void **) &dWorldStepFast1},
-#endif
+// {"dWorldStepFast1", (void **) &dWorldStepFast1},
// {"dWorldSetAutoEnableDepthSF1", (void **) &dWorldSetAutoEnableDepthSF1},
// {"dWorldGetAutoEnableDepthSF1", (void **) &dWorldGetAutoEnableDepthSF1},
// {"dWorldGetAutoDisableLinearThreshold", (void **) &dWorldGetAutoDisableLinearThreshold},
Cvar_RegisterVariable(&physics_ode_quadtree_depth);
Cvar_RegisterVariable(&physics_ode_contactsurfacelayer);
- Cvar_RegisterVariable(&physics_ode_worldstep);
Cvar_RegisterVariable(&physics_ode_worldstep_iterations);
Cvar_RegisterVariable(&physics_ode_contact_mu);
Cvar_RegisterVariable(&physics_ode_contact_erp);
int movetype = MOVETYPE_NONE;
int numtriangles;
int numvertices;
- int solid = SOLID_NOT;
+ int solid = SOLID_NOT, geomtype = 0;
int triangleindex;
int vertexindex;
mempool_t *mempool;
#endif
VectorClear(entmins);
VectorClear(entmaxs);
+
solid = (int)PRVM_gameedictfloat(ed, solid);
+ geomtype = (int)PRVM_gameedictfloat(ed, geomtype);
movetype = (int)PRVM_gameedictfloat(ed, movetype);
scale = PRVM_gameedictfloat(ed, scale);if (!scale) scale = 1.0f;
modelindex = 0;
mempool = prog->progs_mempool;
model = NULL;
- switch(solid)
+ if (!geomtype)
+ {
+ // VorteX: keep support for deprecated solid fields to not break mods
+ if (solid == SOLID_PHYSICS_TRIMESH || solid == SOLID_BSP)
+ geomtype = GEOMTYPE_TRIMESH;
+ else if (solid == SOLID_PHYSICS_SPHERE)
+ geomtype = GEOMTYPE_SPHERE;
+ else if (solid == SOLID_PHYSICS_CAPSULE)
+ geomtype = GEOMTYPE_CAPSULE;
+ else if (solid == SOLID_PHYSICS_CYLINDER)
+ geomtype = GEOMTYPE_CYLINDER;
+ else if (solid == SOLID_PHYSICS_BOX)
+ geomtype = GEOMTYPE_BOX;
+ else
+ geomtype = GEOMTYPE_BOX;
+ }
+ if (geomtype == GEOMTYPE_TRIMESH)
{
- case SOLID_BSP:
- case SOLID_PHYSICS_TRIMESH:
modelindex = (int)PRVM_gameedictfloat(ed, modelindex);
if (world == &sv.world)
model = SV_GetModelByIndex(modelindex);
modelindex = 0;
massval = 1.0f;
}
- break;
- case SOLID_BBOX:
- //case SOLID_SLIDEBOX:
- case SOLID_CORPSE:
- case SOLID_PHYSICS_BOX:
- case SOLID_PHYSICS_SPHERE:
- case SOLID_PHYSICS_CAPSULE:
+ }
+ else if (geomtype)
+ {
VectorCopy(PRVM_gameedictvector(ed, mins), entmins);
VectorCopy(PRVM_gameedictvector(ed, maxs), entmaxs);
massval = PRVM_gameedictfloat(ed, mass);
- break;
- default:
+ }
+ else
+ {
+ // geometry type not set, falling back
if (ed->priv.server->ode_physics)
World_Physics_RemoveFromEntity(world, ed);
return;
VectorSet(geomsize, 1.0f, 1.0f, 1.0f);
}
- switch(solid)
+ switch(geomtype)
{
- case SOLID_BSP:
- case SOLID_PHYSICS_TRIMESH:
+ case GEOMTYPE_TRIMESH:
ed->priv.server->ode_offsetmatrix = identitymatrix;
if (!model)
{
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:
+ case GEOMTYPE_BOX:
treatasbox:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[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:
+ case GEOMTYPE_SPHERE:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
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:
- case SOLID_PHYSICS_CYLINDER:
+ case GEOMTYPE_CAPSULE:
+ case GEOMTYPE_CYLINDER:
axisindex = 0;
if (geomsize[axisindex] < geomsize[1])
axisindex = 1;
// 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)
- if (solid == SOLID_PHYSICS_CAPSULE)
+ if (geomtype == GEOMTYPE_CYLINDER)
{
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);
+ Sys_Error("World_Physics_BodyFromEntity: unrecognized geomtype 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
r[0][2] = up[0];
r[1][2] = up[1];
r[2][2] = up[2];
- if(body)
+ if (body)
{
- if(movetype == MOVETYPE_PHYSICS)
+ if (movetype == MOVETYPE_PHYSICS)
{
dGeomSetBody((dGeomID)ed->priv.server->ode_geom, body);
dBodySetPosition(body, origin[0], origin[1], origin[2]);
}
}
- if(body)
+ if (body)
{
// limit movement speed to prevent missed collisions at high speed
float bouncestop1 = 60.0f / 800.0f;
float bouncefactor2 = 0.0f;
float bouncestop2 = 60.0f / 800.0f;
+ float erp;
dVector3 grav;
prvm_edict_t *ed1, *ed2;
// 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;
dWorldGetGravity((dWorldID)world->physics.ode_world, grav);
bouncestop1 *= fabs(grav[2]);
+ // get erp
+ // select object that moves faster ang get it's erp
+ erp = (VectorLength2(PRVM_gameedictvector(ed1, velocity)) > VectorLength2(PRVM_gameedictvector(ed2, velocity))) ? PRVM_gameedictfloat(ed1, erp) : PRVM_gameedictfloat(ed2, erp);
+
// generate contact points between the two non-space geoms
numcontacts = dCollide(o1, o2, MAX_CONTACTS, &(contact[0].geom), sizeof(contact[0]));
// add these contact points to the simulation
{
contact[i].surface.mode = (physics_ode_contact_mu.value != -1 ? dContactApprox1 : 0) | (physics_ode_contact_erp.value != -1 ? dContactSoftERP : 0) | (physics_ode_contact_cfm.value != -1 ? dContactSoftCFM : 0) | (bouncefactor1 > 0 ? dContactBounce : 0);
contact[i].surface.mu = physics_ode_contact_mu.value * ed1->priv.server->ode_friction * ed2->priv.server->ode_friction;
- contact[i].surface.soft_erp = physics_ode_contact_erp.value;
+ contact[i].surface.soft_erp = physics_ode_contact_erp.value + erp;
contact[i].surface.soft_cfm = physics_ode_contact_cfm.value;
contact[i].surface.bounce = bouncefactor1;
contact[i].surface.bounce_vel = bouncestop1;
prvm_edict_t *ed;
world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000);
- if (physics_ode_constantstep.integer)
- world->physics.ode_step = sys_ticrate.value / world->physics.ode_iterations;
+ if (physics_ode_constantstep.integer > 0 && physics_ode_constantstep.integer < 1)
+ world->physics.ode_step = physics_ode_constantstep.integer / world->physics.ode_iterations;
+ else if (physics_ode_constantstep.integer)
+ world->physics.ode_step = sys_ticrate.integer / world->physics.ode_iterations;
else
world->physics.ode_step = frametime / world->physics.ode_iterations;
world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step;
collisiontime += (Sys_DirtyTime() - tdelta3)*10000;
// run physics (move objects, calculate new velocities)
- if (physics_ode_worldstep.integer == 2)
- {
- dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200));
+ // be sure not to pass 0 as step time because that causes an ODE error
+ dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200));
+ if (world->physics.ode_step > 0)
dWorldQuickStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
- }
-#ifdef ODE_USE_STEPFAST
- else if (physics_ode_worldstep.integer == 1)
- dWorldStepFast1((dWorldID)world->physics.ode_world, world->physics.ode_step, bound(1, physics_ode_worldstep_iterations.integer, 200));
-#endif
- else
- dWorldStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
// clear the JointGroup now that we're done with it
dJointGroupEmpty((dJointGroupID)world->physics.ode_contactgroup);