X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=world.c;h=6aa27808130df41dd4ce8b2fc33460c8130a99d8;hb=e715e4021280ddf816419e498c70b9aca81a1479;hp=b51813439b4adc1a677d03ea7e78904877573702;hpb=885d752dc15aa5475109ac08806e01e5a5c58ec4;p=xonotic%2Fdarkplaces.git diff --git a/world.c b/world.c index b5181343..6aa27808 100644 --- a/world.c +++ b/world.c @@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // world.c -- world query functions #include "quakedef.h" +#include "clvm_cmds.h" /* @@ -331,6 +332,8 @@ cvar_t physics_ode_worldstepfast_iterations = {0, "physics_ode_worldstepfast_ite 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"}; @@ -342,7 +345,8 @@ cvar_t physics_ode_spinlimit = {0, "physics_ode_spinlimit", "10000", "reset spin #include "ode/ode.h" #else #ifdef WINAPI -#define ODE_API WINAPI +// ODE does not use WINAPI +#define ODE_API #else #define ODE_API #endif @@ -404,6 +408,49 @@ typedef enum dJointType } 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; @@ -506,9 +553,9 @@ dWorldID (ODE_API *dWorldCreate)(void); 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); @@ -606,8 +653,8 @@ void (ODE_API *dBodySetMass)(dBodyID, const dMass *mass); //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); @@ -633,12 +680,12 @@ int (ODE_API *dBodyGetGravityMode)(dBodyID b); //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); @@ -647,7 +694,7 @@ dJointID (ODE_API *dJointCreateContact)(dWorldID, dJointGroupID, const dC //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); @@ -656,36 +703,36 @@ void (ODE_API *dJointAttach)(dJointID, dBodyID body1, dBodyID body2); //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); @@ -971,9 +1018,9 @@ static dllfunction_t odefuncs[] = {"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}, @@ -1071,8 +1118,8 @@ static dllfunction_t odefuncs[] = // {"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}, @@ -1098,12 +1145,12 @@ static dllfunction_t odefuncs[] = // {"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}, @@ -1112,7 +1159,7 @@ static dllfunction_t odefuncs[] = // {"dJointCreateAMotor", (void **) &dJointCreateAMotor}, // {"dJointCreateLMotor", (void **) &dJointCreateLMotor}, // {"dJointCreatePlane2D", (void **) &dJointCreatePlane2D}, -// {"dJointDestroy", (void **) &dJointDestroy}, + {"dJointDestroy", (void **) &dJointDestroy}, {"dJointGroupCreate", (void **) &dJointGroupCreate}, {"dJointGroupDestroy", (void **) &dJointGroupDestroy}, {"dJointGroupEmpty", (void **) &dJointGroupEmpty}, @@ -1121,36 +1168,36 @@ static dllfunction_t odefuncs[] = // {"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}, @@ -1422,6 +1469,8 @@ static void World_Physics_Init(void) 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); @@ -1485,7 +1534,10 @@ static void World_Physics_EnableODE(world_t *world) 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 @@ -1511,16 +1563,49 @@ static void World_Physics_End(world_t *world) #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) @@ -1551,12 +1636,30 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) 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); @@ -1578,8 +1681,22 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) 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); @@ -1598,6 +1715,139 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) 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; @@ -1857,6 +2107,8 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) 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) @@ -1949,6 +2201,21 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) 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); @@ -2091,9 +2358,15 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) // 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;