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);
}
/*
struct dxJointGroup;
struct dxTriMeshData;
+#define dInfinity 3.402823466e+38f
+
typedef struct dxWorld *dWorldID;
typedef struct dxSpace *dSpaceID;
typedef struct dxBody *dBodyID;
#define dSAP_AXES_ZYX ((2)|(1<<2)|(0<<4))
//const char* (ODE_API *dGetConfiguration)(void);
-//int (ODE_API *dCheckConfiguration)( const char* token );
+int (ODE_API *dCheckConfiguration)( const char* token );
int (ODE_API *dInitODE)(void);
//int (ODE_API *dInitODE2)(unsigned int uiInitFlags);
//int (ODE_API *dAllocateODEDataForThread)(unsigned int uiAllocateFlags);
//dJointID (ODE_API *dJointCreatePR)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePU)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePiston)(dWorldID, dJointGroupID);
-//dJointID (ODE_API *dJointCreateFixed)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateFixed)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreateNull)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreateAMotor)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreateLMotor)(dWorldID, dJointGroupID);
//int (ODE_API *dSpaceGetClass)(dSpaceID space);
//
void (ODE_API *dGeomDestroy)(dGeomID geom);
-//void (ODE_API *dGeomSetData)(dGeomID geom, void* data);
-//void * (ODE_API *dGeomGetData)(dGeomID geom);
+void (ODE_API *dGeomSetData)(dGeomID geom, void* data);
+void * (ODE_API *dGeomGetData)(dGeomID geom);
void (ODE_API *dGeomSetBody)(dGeomID geom, dBodyID body);
dBodyID (ODE_API *dGeomGetBody)(dGeomID geom);
-//void (ODE_API *dGeomSetPosition)(dGeomID geom, dReal x, dReal y, dReal z);
+void (ODE_API *dGeomSetPosition)(dGeomID geom, dReal x, dReal y, dReal z);
void (ODE_API *dGeomSetRotation)(dGeomID geom, const dMatrix3 R);
//void (ODE_API *dGeomSetQuaternion)(dGeomID geom, const dQuaternion Q);
//const dReal * (ODE_API *dGeomGetPosition)(dGeomID geom);
static dllfunction_t odefuncs[] =
{
// {"dGetConfiguration", (void **) &dGetConfiguration},
-// {"dCheckConfiguration", (void **) &dCheckConfiguration},
+ {"dCheckConfiguration", (void **) &dCheckConfiguration},
{"dInitODE", (void **) &dInitODE},
// {"dInitODE2", (void **) &dInitODE2},
// {"dAllocateODEDataForThread", (void **) &dAllocateODEDataForThread},
// {"dJointCreatePR", (void **) &dJointCreatePR},
// {"dJointCreatePU", (void **) &dJointCreatePU},
// {"dJointCreatePiston", (void **) &dJointCreatePiston},
-// {"dJointCreateFixed", (void **) &dJointCreateFixed},
+ {"dJointCreateFixed", (void **) &dJointCreateFixed},
// {"dJointCreateNull", (void **) &dJointCreateNull},
// {"dJointCreateAMotor", (void **) &dJointCreateAMotor},
// {"dJointCreateLMotor", (void **) &dJointCreateLMotor},
// {"dSpaceGetGeom", (void **) &dSpaceGetGeom},
// {"dSpaceGetClass", (void **) &dSpaceGetClass},
{"dGeomDestroy", (void **) &dGeomDestroy},
-// {"dGeomSetData", (void **) &dGeomSetData},
-// {"dGeomGetData", (void **) &dGeomGetData},
+ {"dGeomSetData", (void **) &dGeomSetData},
+ {"dGeomGetData", (void **) &dGeomGetData},
{"dGeomSetBody", (void **) &dGeomSetBody},
{"dGeomGetBody", (void **) &dGeomGetBody},
-// {"dGeomSetPosition", (void **) &dGeomSetPosition},
+ {"dGeomSetPosition", (void **) &dGeomSetPosition},
{"dGeomSetRotation", (void **) &dGeomSetRotation},
// {"dGeomSetQuaternion", (void **) &dGeomSetQuaternion},
// {"dGeomGetPosition", (void **) &dGeomGetPosition},
#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",
{
dInitODE();
// dInitODE2(0);
-#ifdef ODE_DNYAMIC
+#ifdef ODE_DYNAMIC
# ifdef dSINGLE
if (!dCheckConfiguration("ODE_single_precision"))
# else
void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed)
{
// entity is not physics controlled, free any physics data
- prvm_edict_t *ed2;
ed->priv.server->ode_physics = false;
#ifdef USEODE
if (ed->priv.server->ode_geom)
{
dJointID j;
dBodyID b1, b2;
+ prvm_edict_t *ed2;
while(dBodyGetNumJoints((dBodyID)ed->priv.server->ode_body))
{
j = dBodyGetJoint((dBodyID)ed->priv.server->ode_body, 0);
Mem_Free(ed->priv.server->ode_element3i);
ed->priv.server->ode_element3i = NULL;
ed->priv.server->ode_numtriangles = 0;
+ if(ed->priv.server->ode_massbuf)
+ Mem_Free(ed->priv.server->ode_massbuf);
+ ed->priv.server->ode_massbuf = NULL;
}
#ifdef USEODE
break;
case JOINTTYPE_HINGE2:
break;
+ case JOINTTYPE_FIXED:
+ break;
}
return;
}
VectorCopy(angles, ed->priv.server->ode_angles);
VectorCopy(avelocity, ed->priv.server->ode_avelocity);
ed->priv.server->ode_gravity = dBodyGetGravityMode(body);
+
+ if(!strcmp(prog->name, "server")) // FIXME some better way?
+ {
+ SV_LinkEdict(ed);
+ SV_LinkEdict_TouchAreaGrid(ed);
+ }
}
static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed)
int jointtype = 0;
int enemy = 0, aiment = 0;
vec3_t origin, velocity, angles, forward, left, up, movedir;
+ vec_t CFM, ERP, FMax, Stop, Vel;
prvm_eval_t *val;
- float H = (!strcmp(prog->name, "server") ? sv.frametime : cl.mtime[0] - cl.mtime[1]) / world->physics.ode_iterations;
VectorClear(origin);
VectorClear(velocity);
VectorClear(angles);
+ VectorClear(movedir);
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);if (val) movetype = (int)val->_float;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.enemy);if (val) enemy = val->_int;
if(aiment <= 0 || aiment >= prog->num_edicts || prog->edicts[aiment].priv.required->free || prog->edicts[aiment].priv.server->ode_body == 0)
aiment = 0;
// see http://www.ode.org/old_list_archives/2006-January/017614.html
- if(movedir[0] > 0)
// 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[2];
+ float D = movedir[1];
float R = 2.0 * D * sqrt(K); // we assume D is premultiplied by sqrt(sprungMass)
- float ERP = (H * K) / (H * K + R);
- float CFM = 1.0 / (H * K + R);
- movedir[0] = CFM;
- movedir[2] = ERP;
+ CFM = 1.0 / (world->physics.ode_step * K + R); // always > 0
+ ERP = world->physics.ode_step * K * CFM;
+ Vel = 0;
+ FMax = 0;
+ Stop = movedir[2];
+ }
+ else if(movedir[1] < 0)
+ {
+ CFM = 0;
+ ERP = 0;
+ Vel = movedir[0];
+ FMax = -movedir[1]; // TODO do we need to multiply with world.physics.ode_step?
+ Stop = movedir[2] > 0 ? movedir[2] : dInfinity;
+ }
+ else // movedir[0] > 0, movedir[1] == 0 or movedir[0] < 0, movedir[1] >= 0
+ {
+ CFM = 0;
+ ERP = 0;
+ Vel = 0;
+ FMax = 0;
+ Stop = dInfinity;
}
- movedir[1] *= H; // make movedir[1] actually "force per second" to allow this to be used for non-springs
if(jointtype == ed->priv.server->ode_joint_type && VectorCompare(origin, ed->priv.server->ode_joint_origin) && VectorCompare(velocity, ed->priv.server->ode_joint_velocity) && VectorCompare(angles, ed->priv.server->ode_joint_angles) && enemy == ed->priv.server->ode_joint_enemy && aiment == ed->priv.server->ode_joint_aiment && VectorCompare(movedir, ed->priv.server->ode_joint_movedir))
return; // nothing to do
AngleVectorsFLU(angles, forward, left, up);
case JOINTTYPE_HINGE2:
j = dJointCreateHinge2(world->physics.ode_world, 0);
break;
+ case JOINTTYPE_FIXED:
+ j = dJointCreateFixed(world->physics.ode_world, 0);
+ break;
case 0:
default:
// no joint
j = 0;
break;
}
+ 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);
+ }
ed->priv.server->ode_joint = (void *) j;
ed->priv.server->ode_joint_type = jointtype;
ed->priv.server->ode_joint_enemy = enemy;
VectorCopy(origin, ed->priv.server->ode_joint_origin);
VectorCopy(velocity, ed->priv.server->ode_joint_velocity);
VectorCopy(angles, ed->priv.server->ode_joint_angles);
+ VectorCopy(movedir, ed->priv.server->ode_joint_movedir);
if(j)
{
+ //Con_Printf("made new joint %i\n", (int) (ed - prog->edicts));
dJointSetData(j, (void *) ed);
if(enemy)
b1 = (dBodyID)prog->edicts[enemy].priv.server->ode_body;
if(aiment)
b2 = (dBodyID)prog->edicts[aiment].priv.server->ode_body;
dJointAttach(j, b1, b2);
-#define SETPARAMS(t,id) \
- if(movedir[0] > 0) \
- dJointSet##t##Param(j, dParamCFM##id, movedir[0]); \
- else if(movedir[0] < 0) \
- dJointSet##t##Param(j, dParamCFM##id, 0); \
- if(movedir[1] > 0) \
- { \
- dJointSet##t##Param(j, dParamLoStop##id, 0); \
- dJointSet##t##Param(j, dParamHiStop##id, 0); \
- dJointSet##t##Param(j, dParamFMax##id, movedir[1]); \
- } \
- else \
- dJointSet##t##Param(j, dParamFMax##id, -movedir[1]); \
- if(movedir[2] > 0) \
- dJointSet##t##Param(j, dParamStopERP##id, movedir[2]); \
- else if(movedir[2] < 0) \
- dJointSet##t##Param(j, dParamStopERP##id, 0)
+
switch(jointtype)
{
case JOINTTYPE_POINT:
case JOINTTYPE_HINGE:
dJointSetHingeAnchor(j, origin[0], origin[1], origin[2]);
dJointSetHingeAxis(j, forward[0], forward[1], forward[2]);
- SETPARAMS(Hinge,);
+ dJointSetHingeParam(j, dParamFMax, FMax);
+ dJointSetHingeParam(j, dParamHiStop, Stop);
+ dJointSetHingeParam(j, dParamLoStop, -Stop);
+ dJointSetHingeParam(j, dParamStopCFM, CFM);
+ dJointSetHingeParam(j, dParamStopERP, ERP);
+ dJointSetHingeParam(j, dParamVel, Vel);
break;
case JOINTTYPE_SLIDER:
dJointSetSliderAxis(j, forward[0], forward[1], forward[2]);
- SETPARAMS(Slider,);
+ dJointSetSliderParam(j, dParamFMax, FMax);
+ dJointSetSliderParam(j, dParamHiStop, Stop);
+ dJointSetSliderParam(j, dParamLoStop, -Stop);
+ dJointSetSliderParam(j, dParamStopCFM, CFM);
+ dJointSetSliderParam(j, dParamStopERP, ERP);
+ dJointSetSliderParam(j, dParamVel, Vel);
break;
case JOINTTYPE_UNIVERSAL:
dJointSetUniversalAnchor(j, origin[0], origin[1], origin[2]);
dJointSetUniversalAxis1(j, forward[0], forward[1], forward[2]);
dJointSetUniversalAxis2(j, up[0], up[1], up[2]);
- SETPARAMS(Universal,);
- SETPARAMS(Universal,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:
dJointSetHinge2Anchor(j, origin[0], origin[1], origin[2]);
dJointSetHinge2Axis1(j, forward[0], forward[1], forward[2]);
dJointSetHinge2Axis2(j, velocity[0], velocity[1], velocity[2]);
- SETPARAMS(Hinge2,);
- SETPARAMS(Hinge2,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:
break;
case 0:
default:
- Host_Error("what? but above the joint was valid...\n");
+ Sys_Error("what? but above the joint was valid...\n");
break;
}
+#undef SETPARAMS
+
}
}
#endif
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.movetype);if (val && val->_float) scale = val->_float;
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.scale);if (val && val->_float) scale = val->_float;
modelindex = 0;
+ if (world == &sv.world)
+ mempool = sv_mempool;
+ else if (world == &cl.world)
+ mempool = cls.levelmempool;
+ else
+ mempool = NULL;
switch(solid)
{
case SOLID_BSP:
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.modelindex);
if (val)
modelindex = (int)val->_float;
- if (world == &sv.world && modelindex >= 1 && modelindex < MAX_MODELS)
- {
- model = sv.models[modelindex];
- mempool = sv_mempool;
- }
- else if (world == &cl.world && modelindex >= 1 && modelindex < MAX_MODELS)
- {
- model = cl.model_precache[modelindex];
- mempool = cls.levelmempool;
- }
+ if (world == &sv.world)
+ model = SV_GetModelByIndex(modelindex);
+ else if (world == &cl.world)
+ model = CL_GetModelByIndex(modelindex);
else
- {
model = NULL;
- mempool = NULL;
- modelindex = 0;
- }
if (model)
{
VectorScale(model->normalmins, scale, entmins);
// 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_body = (void *)(body = dBodyCreate(world->physics.ode_world));
ed->priv.server->ode_geom = (void *)dCreateTriMesh(world->physics.ode_space, dataID, NULL, NULL, NULL);
- dGeomSetBody(ed->priv.server->ode_geom, body);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
break;
case SOLID_BBOX:
case SOLID_CORPSE:
case SOLID_PHYSICS_BOX:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
- ed->priv.server->ode_body = (void *)(body = dBodyCreate(world->physics.ode_world));
ed->priv.server->ode_geom = (void *)dCreateBox(world->physics.ode_space, geomsize[0], geomsize[1], geomsize[2]);
dMassSetBoxTotal(&mass, massval, geomsize[0], geomsize[1], geomsize[2]);
- dGeomSetBody(ed->priv.server->ode_geom, body);
- dBodySetMass(body, &mass);
break;
case SOLID_PHYSICS_SPHERE:
Matrix4x4_CreateTranslate(&ed->priv.server->ode_offsetmatrix, geomcenter[0], geomcenter[1], geomcenter[2]);
- ed->priv.server->ode_body = (void *)(body = dBodyCreate(world->physics.ode_world));
ed->priv.server->ode_geom = (void *)dCreateSphere(world->physics.ode_space, geomsize[0] * 0.5f);
dMassSetSphereTotal(&mass, massval, geomsize[0] * 0.5f);
- dGeomSetBody(ed->priv.server->ode_geom, body);
- dBodySetMass(body, &mass);
- dBodySetData(body, (void*)ed);
break;
case SOLID_PHYSICS_CAPSULE:
axisindex = 0;
// 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_body = (void *)(body = dBodyCreate(world->physics.ode_world));
ed->priv.server->ode_geom = (void *)dCreateCapsule(world->physics.ode_space, radius, length);
dMassSetCapsuleTotal(&mass, massval, axisindex+1, radius, length);
- dGeomSetBody(ed->priv.server->ode_geom, body);
- dBodySetMass(body, &mass);
break;
default:
Sys_Error("World_Physics_BodyFromEntity: unrecognized solid value %i was accepted by filter\n", solid);
}
Matrix4x4_Invert_Simple(&ed->priv.server->ode_offsetimatrix, &ed->priv.server->ode_offsetmatrix);
+ ed->priv.server->ode_massbuf = Mem_Alloc(mempool, sizeof(mass));
+ memcpy(ed->priv.server->ode_massbuf, &mass, sizeof(dMass));
+ }
+
+ if(ed->priv.server->ode_geom)
+ dGeomSetData(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);
+ dBodySetData(body, (void*)ed);
+ dBodySetMass(body, (dMass *) ed->priv.server->ode_massbuf);
+ modified = true;
+ }
+ }
+ else
+ {
+ if (ed->priv.server->ode_body != NULL)
+ {
+ if(ed->priv.server->ode_geom)
+ dGeomSetBody(ed->priv.server->ode_geom, 0);
+ dBodyDestroy((dBodyID) ed->priv.server->ode_body);
+ ed->priv.server->ode_body = NULL;
+ modified = true;
+ }
}
// get current data from entity
// compatibility for legacy entities
//if (!VectorLength2(forward) || solid == SOLID_BSP)
{
- AngleVectorsFLU(angles, forward, left, up);
+ float pitchsign = 1;
+ vec3_t qangles, qavelocity;
+ VectorCopy(angles, qangles);
+ VectorCopy(avelocity, qavelocity);
+
+ if(!strcmp(prog->name, "server")) // FIXME some better way?
+ {
+ pitchsign = SV_GetPitchSign(ed);
+ }
+ else if(!strcmp(prog->name, "client"))
+ {
+ pitchsign = CL_GetPitchSign(ed);
+ }
+ qangles[PITCH] *= pitchsign;
+ qavelocity[PITCH] *= pitchsign;
+
+ AngleVectorsFLU(qangles, forward, left, up);
// convert single-axis rotations in avelocity to spinvelocity
// FIXME: untested math - check signs
- VectorSet(spinvelocity, DEG2RAD(avelocity[PITCH]), DEG2RAD(avelocity[ROLL]), DEG2RAD(avelocity[YAW]));
+ VectorSet(spinvelocity, DEG2RAD(qavelocity[PITCH]), DEG2RAD(qavelocity[ROLL]), DEG2RAD(qavelocity[YAW]));
}
// compatibility for legacy entities
}
}
- // limit movement speed to prevent missed collisions at high speed
- movelimit = ed->priv.server->ode_movelimit * world->physics.ode_movelimit;
- test = VectorLength2(velocity);
- if (test > movelimit*movelimit)
- {
- modified = true;
- // scale down linear velocity to the movelimit
- // scale down angular velocity the same amount for consistency
- f = movelimit / sqrt(test);
- VectorScale(velocity, f, velocity);
- VectorScale(avelocity, f, avelocity);
- VectorScale(spinvelocity, f, spinvelocity);
- }
-
- // make sure the angular velocity is not exploding
- spinlimit = physics_ode_spinlimit.value;
- test = VectorLength2(spinvelocity);
- if (test > spinlimit)
- {
- modified = true;
- VectorClear(avelocity);
- VectorClear(spinvelocity);
- }
-
// check if the qc edited any position data
if (!VectorCompare(origin, ed->priv.server->ode_origin)
|| !VectorCompare(velocity, ed->priv.server->ode_velocity)
// store the qc values into the physics engine
body = ed->priv.server->ode_body;
- if (body && modified)
+ if (modified && ed->priv.server->ode_geom)
{
dVector3 r[3];
matrix4x4_t entitymatrix;
matrix4x4_t bodymatrix;
- {
- float pitchsign = 1;
- if(!strcmp(prog->name, "server")) // FIXME some better way?
- {
- pitchsign = SV_GetPitchSign(ed);
- }
- else if(!strcmp(prog->name, "client"))
- {
- pitchsign = CL_GetPitchSign(ed);
- }
- angles[PITCH] *= pitchsign;
- avelocity[PITCH] *= pitchsign;
- }
+#if 0
+ Con_Printf("entity %i got changed by QC\n", (int) (ed - prog->edicts));
+ if(!VectorCompare(origin, ed->priv.server->ode_origin))
+ Con_Printf(" origin: %f %f %f -> %f %f %f\n", ed->priv.server->ode_origin[0], ed->priv.server->ode_origin[1], ed->priv.server->ode_origin[2], origin[0], origin[1], origin[2]);
+ if(!VectorCompare(velocity, ed->priv.server->ode_velocity))
+ Con_Printf(" velocity: %f %f %f -> %f %f %f\n", ed->priv.server->ode_velocity[0], ed->priv.server->ode_velocity[1], ed->priv.server->ode_velocity[2], velocity[0], velocity[1], velocity[2]);
+ if(!VectorCompare(angles, ed->priv.server->ode_angles))
+ Con_Printf(" angles: %f %f %f -> %f %f %f\n", ed->priv.server->ode_angles[0], ed->priv.server->ode_angles[1], ed->priv.server->ode_angles[2], angles[0], angles[1], angles[2]);
+ if(!VectorCompare(avelocity, ed->priv.server->ode_avelocity))
+ Con_Printf(" avelocity: %f %f %f -> %f %f %f\n", ed->priv.server->ode_avelocity[0], ed->priv.server->ode_avelocity[1], ed->priv.server->ode_avelocity[2], avelocity[0], avelocity[1], avelocity[2]);
+ if(gravity != ed->priv.server->ode_gravity)
+ Con_Printf(" gravity: %i -> %i\n", ed->priv.server->ode_gravity, gravity);
+#endif
+
+ // values for BodyFromEntity to check if the qc modified anything later
+ VectorCopy(origin, ed->priv.server->ode_origin);
+ 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 = gravity;
Matrix4x4_FromVectors(&entitymatrix, forward, left, up, origin);
Matrix4x4_Concat(&bodymatrix, &entitymatrix, &ed->priv.server->ode_offsetmatrix);
r[0][2] = up[0];
r[1][2] = up[1];
r[2][2] = up[2];
- dGeomSetBody(ed->priv.server->ode_geom, ed->priv.server->ode_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);
- dBodySetData(body, (void*)ed);
- // setting body to NULL makes an immovable object
- if (movetype != MOVETYPE_PHYSICS)
- dGeomSetBody(ed->priv.server->ode_geom, 0);
+ if(body)
+ {
+ if(movetype == MOVETYPE_PHYSICS)
+ {
+ dGeomSetBody(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);
+ }
+ else
+ {
+ dGeomSetBody(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);
+ }
+ }
+ 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]);
+ }
+ }
+
+ if(body)
+ {
+ // limit movement speed to prevent missed collisions at high speed
+ const dReal *ovelocity = dBodyGetLinearVel(body);
+ const dReal *ospinvelocity = dBodyGetAngularVel(body);
+ movelimit = ed->priv.server->ode_movelimit * world->physics.ode_movelimit;
+ test = VectorLength2(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);
+ dBodySetLinearVel(body, velocity[0], velocity[1], velocity[2]);
+ dBodySetAngularVel(body, spinvelocity[0], spinvelocity[1], spinvelocity[2]);
+ }
+
+ // make sure the angular velocity is not exploding
+ spinlimit = physics_ode_spinlimit.value;
+ test = VectorLength2(ospinvelocity);
+ if (test > spinlimit)
+ {
+ dBodySetAngularVel(body, 0, 0, 0);
+ }
}
}
float bouncefactor2 = 0.0f;
float bouncestop2 = 60.0f / 800.0f;
dVector3 grav;
- prvm_edict_t *ed;
+ prvm_edict_t *ed1, *ed2;
if (dGeomIsSpace(o1) || dGeomIsSpace(o2))
{
if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact))
return;
- if(b1)
+ ed1 = (prvm_edict_t *) dGeomGetData(o1);
+ if(ed1 && ed1->priv.server->free)
+ ed1 = NULL;
+ if(ed1)
{
- ed = (prvm_edict_t *) dBodyGetData(b1);
- if(ed)
- {
- val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.bouncefactor);
- if (val!=0 && val->_float)
- bouncefactor1 = val->_float;
+ val = PRVM_EDICTFIELDVALUE(ed1, prog->fieldoffsets.bouncefactor);
+ if (val!=0 && val->_float)
+ bouncefactor1 = val->_float;
- val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.bouncestop);
- if (val!=0 && val->_float)
- bouncestop1 = val->_float;
- }
+ val = PRVM_EDICTFIELDVALUE(ed1, prog->fieldoffsets.bouncestop);
+ if (val!=0 && val->_float)
+ bouncestop1 = val->_float;
}
- if(b2)
+ ed2 = (prvm_edict_t *) dGeomGetData(o2);
+ if(ed2 && ed2->priv.server->free)
+ ed2 = NULL;
+ if(ed2)
{
- ed = (prvm_edict_t *) dBodyGetData(b2);
- if(ed)
- {
- val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.bouncefactor);
- if (val!=0 && val->_float)
- bouncefactor2 = val->_float;
+ val = PRVM_EDICTFIELDVALUE(ed2, prog->fieldoffsets.bouncefactor);
+ if (val!=0 && val->_float)
+ bouncefactor2 = val->_float;
+
+ val = PRVM_EDICTFIELDVALUE(ed2, prog->fieldoffsets.bouncestop);
+ if (val!=0 && val->_float)
+ bouncestop2 = val->_float;
+ }
- val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.bouncestop);
- if (val!=0 && val->_float)
- bouncestop2 = val->_float;
+ if(!strcmp(prog->name, "server"))
+ {
+ if(ed1 && ed1->fields.server->touch)
+ {
+ SV_LinkEdict_TouchAreaGrid_Call(ed1, ed2 ? ed2 : prog->edicts);
+ }
+ if(ed2 && ed2->fields.server->touch)
+ {
+ SV_LinkEdict_TouchAreaGrid_Call(ed2, ed1 ? ed1 : prog->edicts);
}
}
int i;
prvm_edict_t *ed;
+ world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000);
+ world->physics.ode_step = frametime / world->physics.ode_iterations;
+ world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step;
+
// copy physics properties from entities to physics engine
if (prog)
{
World_Physics_Frame_JointFromEntity(world, ed);
}
- world->physics.ode_iterations = bound(1, physics_ode_iterationsperframe.integer, 1000);
- world->physics.ode_step = frametime / world->physics.ode_iterations;
- world->physics.ode_movelimit = physics_ode_movelimit.value / world->physics.ode_step;
for (i = 0;i < world->physics.ode_iterations;i++)
{
// set the gravity
// copy physics properties from physics engine to entities
if (prog)
for (i = 1, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++)
- if (!prog->edicts[i].priv.required->free && PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype)->_float == MOVETYPE_PHYSICS)
+ if (!prog->edicts[i].priv.required->free)
World_Physics_Frame_BodyToEntity(world, ed);
}
#endif