// world.c -- world query functions
#include "quakedef.h"
+#include "clvm_cmds.h"
/*
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_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_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"};
#include "ode/ode.h"
#else
#ifdef WINAPI
-#define ODE_API WINAPI
+// ODE does not use WINAPI
+#define ODE_API
#else
#define ODE_API
#endif
}
dJointType;
+#define D_ALL_PARAM_NAMES(start) \
+ /* parameters for limits and motors */ \
+ dParamLoStop = start, \
+ dParamHiStop, \
+ dParamVel, \
+ dParamFMax, \
+ dParamFudgeFactor, \
+ dParamBounce, \
+ dParamCFM, \
+ dParamStopERP, \
+ dParamStopCFM, \
+ /* parameters for suspension */ \
+ dParamSuspensionERP, \
+ dParamSuspensionCFM, \
+ dParamERP, \
+
+#define D_ALL_PARAM_NAMES_X(start,x) \
+ /* parameters for limits and motors */ \
+ dParamLoStop ## x = start, \
+ dParamHiStop ## x, \
+ dParamVel ## x, \
+ dParamFMax ## x, \
+ dParamFudgeFactor ## x, \
+ dParamBounce ## x, \
+ dParamCFM ## x, \
+ dParamStopERP ## x, \
+ dParamStopCFM ## x, \
+ /* parameters for suspension */ \
+ dParamSuspensionERP ## x, \
+ dParamSuspensionCFM ## x, \
+ dParamERP ## x,
+
+enum {
+ D_ALL_PARAM_NAMES(0)
+ D_ALL_PARAM_NAMES_X(0x100,2)
+ D_ALL_PARAM_NAMES_X(0x200,3)
+
+ /* add a multiple of this constant to the basic parameter numbers to get
+ * the parameters for the second, third etc axes.
+ */
+ dParamGroup=0x100
+};
+
typedef struct dMass
{
dReal mass;
void (ODE_API *dWorldDestroy)(dWorldID world);
void (ODE_API *dWorldSetGravity)(dWorldID, dReal x, dReal y, dReal z);
void (ODE_API *dWorldGetGravity)(dWorldID, dVector3 gravity);
-//void (ODE_API *dWorldSetERP)(dWorldID, dReal erp);
+void (ODE_API *dWorldSetERP)(dWorldID, dReal erp);
//dReal (ODE_API *dWorldGetERP)(dWorldID);
-//void (ODE_API *dWorldSetCFM)(dWorldID, dReal cfm);
+void (ODE_API *dWorldSetCFM)(dWorldID, dReal cfm);
//dReal (ODE_API *dWorldGetCFM)(dWorldID);
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 *dBodySetFiniteRotationAxis)(dBodyID, dReal x, dReal y, dReal z);
//int (ODE_API *dBodyGetFiniteRotationMode)(dBodyID);
//void (ODE_API *dBodyGetFiniteRotationAxis)(dBodyID, dVector3 result);
-//int (ODE_API *dBodyGetNumJoints)(dBodyID b);
-//dJointID (ODE_API *dBodyGetJoint)(dBodyID, int index);
+int (ODE_API *dBodyGetNumJoints)(dBodyID b);
+dJointID (ODE_API *dBodyGetJoint)(dBodyID, int index);
//void (ODE_API *dBodySetDynamic)(dBodyID);
//void (ODE_API *dBodySetKinematic)(dBodyID);
//int (ODE_API *dBodyIsKinematic)(dBodyID);
//void (ODE_API *dBodySetMaxAngularSpeed)(dBodyID b, dReal max_speed);
//int (ODE_API *dBodyGetGyroscopicMode)(dBodyID b);
//void (ODE_API *dBodySetGyroscopicMode)(dBodyID b, int enabled);
-//dJointID (ODE_API *dJointCreateBall)(dWorldID, dJointGroupID);
-//dJointID (ODE_API *dJointCreateHinge)(dWorldID, dJointGroupID);
-//dJointID (ODE_API *dJointCreateSlider)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateBall)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateHinge)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateSlider)(dWorldID, dJointGroupID);
dJointID (ODE_API *dJointCreateContact)(dWorldID, dJointGroupID, const dContact *);
-//dJointID (ODE_API *dJointCreateHinge2)(dWorldID, dJointGroupID);
-//dJointID (ODE_API *dJointCreateUniversal)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateHinge2)(dWorldID, dJointGroupID);
+dJointID (ODE_API *dJointCreateUniversal)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePR)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePU)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePiston)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreateAMotor)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreateLMotor)(dWorldID, dJointGroupID);
//dJointID (ODE_API *dJointCreatePlane2D)(dWorldID, dJointGroupID);
-//void (ODE_API *dJointDestroy)(dJointID);
+void (ODE_API *dJointDestroy)(dJointID);
dJointGroupID (ODE_API *dJointGroupCreate)(int max_size);
void (ODE_API *dJointGroupDestroy)(dJointGroupID);
void (ODE_API *dJointGroupEmpty)(dJointGroupID);
//void (ODE_API *dJointEnable)(dJointID);
//void (ODE_API *dJointDisable)(dJointID);
//int (ODE_API *dJointIsEnabled)(dJointID);
-//void (ODE_API *dJointSetData)(dJointID, void *data);
-//void * (ODE_API *dJointGetData)(dJointID);
+void (ODE_API *dJointSetData)(dJointID, void *data);
+void * (ODE_API *dJointGetData)(dJointID);
//dJointType (ODE_API *dJointGetType)(dJointID);
-//dBodyID (ODE_API *dJointGetBody)(dJointID, int index);
+dBodyID (ODE_API *dJointGetBody)(dJointID, int index);
//void (ODE_API *dJointSetFeedback)(dJointID, dJointFeedback *);
//dJointFeedback *(ODE_API *dJointGetFeedback)(dJointID);
-//void (ODE_API *dJointSetBallAnchor)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetBallAnchor)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetBallAnchor2)(dJointID, dReal x, dReal y, dReal z);
-//void (ODE_API *dJointSetBallParam)(dJointID, int parameter, dReal value);
-//void (ODE_API *dJointSetHingeAnchor)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetBallParam)(dJointID, int parameter, dReal value);
+void (ODE_API *dJointSetHingeAnchor)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetHingeAnchorDelta)(dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az);
-//void (ODE_API *dJointSetHingeAxis)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetHingeAxis)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetHingeAxisOffset)(dJointID j, dReal x, dReal y, dReal z, dReal angle);
-//void (ODE_API *dJointSetHingeParam)(dJointID, int parameter, dReal value);
+void (ODE_API *dJointSetHingeParam)(dJointID, int parameter, dReal value);
//void (ODE_API *dJointAddHingeTorque)(dJointID joint, dReal torque);
-//void (ODE_API *dJointSetSliderAxis)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetSliderAxis)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetSliderAxisDelta)(dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az);
-//void (ODE_API *dJointSetSliderParam)(dJointID, int parameter, dReal value);
+void (ODE_API *dJointSetSliderParam)(dJointID, int parameter, dReal value);
//void (ODE_API *dJointAddSliderForce)(dJointID joint, dReal force);
-//void (ODE_API *dJointSetHinge2Anchor)(dJointID, dReal x, dReal y, dReal z);
-//void (ODE_API *dJointSetHinge2Axis1)(dJointID, dReal x, dReal y, dReal z);
-//void (ODE_API *dJointSetHinge2Axis2)(dJointID, dReal x, dReal y, dReal z);
-//void (ODE_API *dJointSetHinge2Param)(dJointID, int parameter, dReal value);
+void (ODE_API *dJointSetHinge2Anchor)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetHinge2Axis1)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetHinge2Axis2)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetHinge2Param)(dJointID, int parameter, dReal value);
//void (ODE_API *dJointAddHinge2Torques)(dJointID joint, dReal torque1, dReal torque2);
-//void (ODE_API *dJointSetUniversalAnchor)(dJointID, dReal x, dReal y, dReal z);
-//void (ODE_API *dJointSetUniversalAxis1)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetUniversalAnchor)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetUniversalAxis1)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetUniversalAxis1Offset)(dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2);
-//void (ODE_API *dJointSetUniversalAxis2)(dJointID, dReal x, dReal y, dReal z);
+void (ODE_API *dJointSetUniversalAxis2)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetUniversalAxis2Offset)(dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2);
-//void (ODE_API *dJointSetUniversalParam)(dJointID, int parameter, dReal value);
+void (ODE_API *dJointSetUniversalParam)(dJointID, int parameter, dReal value);
//void (ODE_API *dJointAddUniversalTorques)(dJointID joint, dReal torque1, dReal torque2);
//void (ODE_API *dJointSetPRAnchor)(dJointID, dReal x, dReal y, dReal z);
//void (ODE_API *dJointSetPRAxis1)(dJointID, dReal x, dReal y, dReal z);
{"dWorldDestroy", (void **) &dWorldDestroy},
{"dWorldSetGravity", (void **) &dWorldSetGravity},
{"dWorldGetGravity", (void **) &dWorldGetGravity},
-// {"dWorldSetERP", (void **) &dWorldSetERP},
+ {"dWorldSetERP", (void **) &dWorldSetERP},
// {"dWorldGetERP", (void **) &dWorldGetERP},
-// {"dWorldSetCFM", (void **) &dWorldSetCFM},
+ {"dWorldSetCFM", (void **) &dWorldSetCFM},
// {"dWorldGetCFM", (void **) &dWorldGetCFM},
{"dWorldStep", (void **) &dWorldStep},
// {"dWorldImpulseToForce", (void **) &dWorldImpulseToForce},
// {"dBodySetFiniteRotationAxis", (void **) &dBodySetFiniteRotationAxis},
// {"dBodyGetFiniteRotationMode", (void **) &dBodyGetFiniteRotationMode},
// {"dBodyGetFiniteRotationAxis", (void **) &dBodyGetFiniteRotationAxis},
-// {"dBodyGetNumJoints", (void **) &dBodyGetNumJoints},
-// {"dBodyGetJoint", (void **) &dBodyGetJoint},
+ {"dBodyGetNumJoints", (void **) &dBodyGetNumJoints},
+ {"dBodyGetJoint", (void **) &dBodyGetJoint},
// {"dBodySetDynamic", (void **) &dBodySetDynamic},
// {"dBodySetKinematic", (void **) &dBodySetKinematic},
// {"dBodyIsKinematic", (void **) &dBodyIsKinematic},
// {"dBodySetMaxAngularSpeed", (void **) &dBodySetMaxAngularSpeed},
// {"dBodyGetGyroscopicMode", (void **) &dBodyGetGyroscopicMode},
// {"dBodySetGyroscopicMode", (void **) &dBodySetGyroscopicMode},
-// {"dJointCreateBall", (void **) &dJointCreateBall},
-// {"dJointCreateHinge", (void **) &dJointCreateHinge},
-// {"dJointCreateSlider", (void **) &dJointCreateSlider},
+ {"dJointCreateBall", (void **) &dJointCreateBall},
+ {"dJointCreateHinge", (void **) &dJointCreateHinge},
+ {"dJointCreateSlider", (void **) &dJointCreateSlider},
{"dJointCreateContact", (void **) &dJointCreateContact},
-// {"dJointCreateHinge2", (void **) &dJointCreateHinge2},
-// {"dJointCreateUniversal", (void **) &dJointCreateUniversal},
+ {"dJointCreateHinge2", (void **) &dJointCreateHinge2},
+ {"dJointCreateUniversal", (void **) &dJointCreateUniversal},
// {"dJointCreatePR", (void **) &dJointCreatePR},
// {"dJointCreatePU", (void **) &dJointCreatePU},
// {"dJointCreatePiston", (void **) &dJointCreatePiston},
// {"dJointCreateAMotor", (void **) &dJointCreateAMotor},
// {"dJointCreateLMotor", (void **) &dJointCreateLMotor},
// {"dJointCreatePlane2D", (void **) &dJointCreatePlane2D},
-// {"dJointDestroy", (void **) &dJointDestroy},
+ {"dJointDestroy", (void **) &dJointDestroy},
{"dJointGroupCreate", (void **) &dJointGroupCreate},
{"dJointGroupDestroy", (void **) &dJointGroupDestroy},
{"dJointGroupEmpty", (void **) &dJointGroupEmpty},
// {"dJointEnable", (void **) &dJointEnable},
// {"dJointDisable", (void **) &dJointDisable},
// {"dJointIsEnabled", (void **) &dJointIsEnabled},
-// {"dJointSetData", (void **) &dJointSetData},
-// {"dJointGetData", (void **) &dJointGetData},
+ {"dJointSetData", (void **) &dJointSetData},
+ {"dJointGetData", (void **) &dJointGetData},
// {"dJointGetType", (void **) &dJointGetType},
-// {"dJointGetBody", (void **) &dJointGetBody},
+ {"dJointGetBody", (void **) &dJointGetBody},
// {"dJointSetFeedback", (void **) &dJointSetFeedback},
// {"dJointGetFeedback", (void **) &dJointGetFeedback},
-// {"dJointSetBallAnchor", (void **) &dJointSetBallAnchor},
+ {"dJointSetBallAnchor", (void **) &dJointSetBallAnchor},
// {"dJointSetBallAnchor2", (void **) &dJointSetBallAnchor2},
-// {"dJointSetBallParam", (void **) &dJointSetBallParam},
-// {"dJointSetHingeAnchor", (void **) &dJointSetHingeAnchor},
+ {"dJointSetBallParam", (void **) &dJointSetBallParam},
+ {"dJointSetHingeAnchor", (void **) &dJointSetHingeAnchor},
// {"dJointSetHingeAnchorDelta", (void **) &dJointSetHingeAnchorDelta},
-// {"dJointSetHingeAxis", (void **) &dJointSetHingeAxis},
+ {"dJointSetHingeAxis", (void **) &dJointSetHingeAxis},
// {"dJointSetHingeAxisOffset", (void **) &dJointSetHingeAxisOffset},
-// {"dJointSetHingeParam", (void **) &dJointSetHingeParam},
+ {"dJointSetHingeParam", (void **) &dJointSetHingeParam},
// {"dJointAddHingeTorque", (void **) &dJointAddHingeTorque},
-// {"dJointSetSliderAxis", (void **) &dJointSetSliderAxis},
+ {"dJointSetSliderAxis", (void **) &dJointSetSliderAxis},
// {"dJointSetSliderAxisDelta", (void **) &dJointSetSliderAxisDelta},
-// {"dJointSetSliderParam", (void **) &dJointSetSliderParam},
+ {"dJointSetSliderParam", (void **) &dJointSetSliderParam},
// {"dJointAddSliderForce", (void **) &dJointAddSliderForce},
-// {"dJointSetHinge2Anchor", (void **) &dJointSetHinge2Anchor},
-// {"dJointSetHinge2Axis1", (void **) &dJointSetHinge2Axis1},
-// {"dJointSetHinge2Axis2", (void **) &dJointSetHinge2Axis2},
-// {"dJointSetHinge2Param", (void **) &dJointSetHinge2Param},
+ {"dJointSetHinge2Anchor", (void **) &dJointSetHinge2Anchor},
+ {"dJointSetHinge2Axis1", (void **) &dJointSetHinge2Axis1},
+ {"dJointSetHinge2Axis2", (void **) &dJointSetHinge2Axis2},
+ {"dJointSetHinge2Param", (void **) &dJointSetHinge2Param},
// {"dJointAddHinge2Torques", (void **) &dJointAddHinge2Torques},
-// {"dJointSetUniversalAnchor", (void **) &dJointSetUniversalAnchor},
-// {"dJointSetUniversalAxis1", (void **) &dJointSetUniversalAxis1},
+ {"dJointSetUniversalAnchor", (void **) &dJointSetUniversalAnchor},
+ {"dJointSetUniversalAxis1", (void **) &dJointSetUniversalAxis1},
// {"dJointSetUniversalAxis1Offset", (void **) &dJointSetUniversalAxis1Offset},
-// {"dJointSetUniversalAxis2", (void **) &dJointSetUniversalAxis2},
+ {"dJointSetUniversalAxis2", (void **) &dJointSetUniversalAxis2},
// {"dJointSetUniversalAxis2Offset", (void **) &dJointSetUniversalAxis2Offset},
-// {"dJointSetUniversalParam", (void **) &dJointSetUniversalParam},
+ {"dJointSetUniversalParam", (void **) &dJointSetUniversalParam},
// {"dJointAddUniversalTorques", (void **) &dJointAddUniversalTorques},
// {"dJointSetPRAnchor", (void **) &dJointSetPRAnchor},
// {"dJointSetPRAxis1", (void **) &dJointSetPRAxis1},
Cvar_RegisterVariable(&physics_ode_contact_mu);
Cvar_RegisterVariable(&physics_ode_contact_erp);
Cvar_RegisterVariable(&physics_ode_contact_cfm);
+ Cvar_RegisterVariable(&physics_ode_world_erp);
+ Cvar_RegisterVariable(&physics_ode_world_cfm);
Cvar_RegisterVariable(&physics_ode_iterationsperframe);
Cvar_RegisterVariable(&physics_ode_movelimit);
Cvar_RegisterVariable(&physics_ode_spinlimit);
world->physics.ode_world = dWorldCreate();
world->physics.ode_space = dQuadTreeSpaceCreate(NULL, center, extents, bound(1, physics_ode_quadtree_depth.integer, 10));
world->physics.ode_contactgroup = dJointGroupCreate(0);
- // we don't currently set dWorldSetCFM or dWorldSetERP because the defaults seem fine
+ if(physics_ode_world_erp.value >= 0)
+ dWorldSetERP(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);
}
#endif
#endif
}
+void World_Physics_RemoveJointFromEntity(world_t *world, prvm_edict_t *ed)
+{
+ ed->priv.server->ode_joint_type = 0;
+#ifdef USEODE
+ if(ed->priv.server->ode_joint)
+ dJointDestroy((dJointID)ed->priv.server->ode_joint);
+ ed->priv.server->ode_joint = NULL;
+#endif
+}
+
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)
dGeomDestroy((dGeomID)ed->priv.server->ode_geom);
ed->priv.server->ode_geom = NULL;
if (ed->priv.server->ode_body)
+ {
+ dJointID j;
+ dBodyID b1, b2;
+ while(dBodyGetNumJoints((dBodyID)ed->priv.server->ode_body))
+ {
+ j = dBodyGetJoint((dBodyID)ed->priv.server->ode_body, 0);
+ ed2 = (prvm_edict_t *) dJointGetData(j);
+ b1 = dJointGetBody(j, 0);
+ b2 = dJointGetBody(j, 1);
+ if(b1 == (dBodyID)ed->priv.server->ode_body)
+ {
+ b1 = 0;
+ ed2->priv.server->ode_joint_enemy = 0;
+ }
+ if(b2 == (dBodyID)ed->priv.server->ode_body)
+ {
+ b2 = 0;
+ ed2->priv.server->ode_joint_aiment = 0;
+ }
+ dJointAttach(j, b1, b2);
+ }
dBodyDestroy((dBodyID)ed->priv.server->ode_body);
+ }
ed->priv.server->ode_body = NULL;
#endif
if (ed->priv.server->ode_vertex3f)
vec3_t origin;
vec3_t spinvelocity;
vec3_t velocity;
+ int jointtype;
if (!body)
return;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movetype);
movetype = (int)val->_float;
if (movetype != MOVETYPE_PHYSICS)
+ {
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.jointtype);if (val) jointtype = (int)val->_float;
+ switch(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;
+ }
return;
+ }
// store the physics engine data into the entity
o = dBodyGetPosition(body);
r = dBodyGetRotation(body);
Matrix4x4_Concat(&entitymatrix, &bodymatrix, &ed->priv.server->ode_offsetimatrix);
Matrix4x4_ToVectors(&entitymatrix, forward, left, up, origin);
- AnglesFromVectors(angles, forward, up, true);
- VectorSet(avelocity, RAD2DEG(spinvelocity[PITCH]), RAD2DEG(spinvelocity[YAW]), RAD2DEG(spinvelocity[ROLL]));
+ AnglesFromVectors(angles, forward, up, false);
+ VectorSet(avelocity, RAD2DEG(spinvelocity[PITCH]), RAD2DEG(spinvelocity[ROLL]), RAD2DEG(spinvelocity[YAW]));
+
+ {
+ 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;
+ }
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.origin);if (val) VectorCopy(origin, val->vector);
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.velocity);if (val) VectorCopy(velocity, val->vector);
ed->priv.server->ode_gravity = dBodyGetGravityMode(body);
}
+static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed)
+{
+ dJointID j = 0;
+ dBodyID b1 = 0;
+ dBodyID b2 = 0;
+ int movetype = 0;
+ int jointtype = 0;
+ int enemy = 0, aiment = 0;
+ vec3_t origin, velocity, angles, forward, left, up, movedir;
+ prvm_eval_t *val;
+ VectorClear(origin);
+ VectorClear(velocity);
+ VectorClear(angles);
+ 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;
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.aiment);if (val) aiment = val->_int;
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.origin);if (val) VectorCopy(val->vector, origin);
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.velocity);if (val) VectorCopy(val->vector, velocity);
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.angles);if (val) VectorCopy(val->vector, angles);
+ val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.movedir);if (val) VectorCopy(val->vector, movedir);
+ if(movetype == MOVETYPE_PHYSICS)
+ jointtype = 0; // can't have both
+ if(enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].priv.required->free || prog->edicts[enemy].priv.server->ode_body == 0)
+ enemy = 0;
+ 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)
+ {
+ float K = movedir[0];
+ float D = movedir[2];
+ float H = (!strcmp(prog->name, "server") ? sv.frametime : cl.mtime[0] - cl.mtime[1]) / world->physics.ode_iterations;
+ 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;
+ }
+ 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);
+ switch(jointtype)
+ {
+ case JOINTTYPE_POINT:
+ j = dJointCreateBall(world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_HINGE:
+ j = dJointCreateHinge(world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_SLIDER:
+ j = dJointCreateSlider(world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_UNIVERSAL:
+ j = dJointCreateUniversal(world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_HINGE2:
+ j = dJointCreateHinge2(world->physics.ode_world, 0);
+ break;
+ case 0:
+ default:
+ // no joint
+ j = 0;
+ break;
+ }
+ ed->priv.server->ode_joint = (void *) j;
+ ed->priv.server->ode_joint_type = jointtype;
+ ed->priv.server->ode_joint_enemy = enemy;
+ ed->priv.server->ode_joint_aiment = aiment;
+ VectorCopy(origin, ed->priv.server->ode_joint_origin);
+ VectorCopy(velocity, ed->priv.server->ode_joint_velocity);
+ VectorCopy(angles, ed->priv.server->ode_joint_angles);
+ if(j)
+ {
+ 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]); \
+ 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:
+ dJointSetBallAnchor(j, origin[0], origin[1], origin[2]);
+ break;
+ case JOINTTYPE_HINGE:
+ dJointSetHingeAnchor(j, origin[0], origin[1], origin[2]);
+ dJointSetHingeAxis(j, forward[0], forward[1], forward[2]);
+ SETPARAMS(Hinge,);
+ break;
+ case JOINTTYPE_SLIDER:
+ dJointSetSliderAxis(j, forward[0], forward[1], forward[2]);
+ SETPARAMS(Slider,);
+ 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);
+ 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);
+ break;
+ case 0:
+ default:
+ Host_Error("what? but above the joint was valid...\n");
+ break;
+ }
+ }
+}
+
static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
{
const float *iv;
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.angles);if (val) VectorCopy(val->vector, angles);
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.avelocity);if (val) VectorCopy(val->vector, avelocity);
val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.gravity);if (val) { if(val->_float != 0.0f && val->_float < 0.5f) gravity = false; }
+ if(ed == prog->edicts)
+ gravity = false;
// compatibility for legacy entities
//if (!VectorLength2(forward) || solid == SOLID_BSP)
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;
+ }
+
Matrix4x4_FromVectors(&entitymatrix, forward, left, up, origin);
Matrix4x4_Concat(&bodymatrix, &entitymatrix, &ed->priv.server->ode_offsetmatrix);
Matrix4x4_ToVectors(&bodymatrix, forward, left, up, origin);
// copy physics properties from entities to physics engine
if (prog)
+ {
for (i = 0, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++)
if (!prog->edicts[i].priv.required->free)
World_Physics_Frame_BodyFromEntity(world, ed);
+ // oh, and it must be called after all bodies were created
+ for (i = 0, ed = prog->edicts + i;i < prog->num_edicts;i++, ed++)
+ if (!prog->edicts[i].priv.required->free)
+ 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;