+
+ AnglesFromVectors(angles, forward, up, false);
+ VectorSet(avelocity, RAD2DEG(spinvelocity[PITCH]), RAD2DEG(spinvelocity[ROLL]), RAD2DEG(spinvelocity[YAW]));
+
+ {
+ float pitchsign = 1;
+ if(prog == SVVM_prog) // FIXME some better way?
+ {
+ pitchsign = SV_GetPitchSign(prog, ed);
+ }
+ else if(prog == CLVM_prog)
+ {
+ pitchsign = CL_GetPitchSign(prog, ed);
+ }
+ angles[PITCH] *= pitchsign;
+ avelocity[PITCH] *= pitchsign;
+ }
+
+ VectorCopy(origin, PRVM_gameedictvector(ed, origin));
+ VectorCopy(velocity, PRVM_gameedictvector(ed, velocity));
+ //VectorCopy(forward, PRVM_gameedictvector(ed, axis_forward));
+ //VectorCopy(left, PRVM_gameedictvector(ed, axis_left));
+ //VectorCopy(up, PRVM_gameedictvector(ed, axis_up));
+ //VectorCopy(spinvelocity, PRVM_gameedictvector(ed, spinvelocity));
+ VectorCopy(angles, PRVM_gameedictvector(ed, angles));
+ VectorCopy(avelocity, PRVM_gameedictvector(ed, avelocity));
+
+ // 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 = dBodyGetGravityMode(body) != 0;
+
+ if(prog == SVVM_prog) // FIXME some better way?
+ {
+ SV_LinkEdict(ed);
+ SV_LinkEdict_TouchAreaGrid(ed);
+ }
+}
+
+static void World_Physics_Frame_ForceFromEntity(world_t *world, prvm_edict_t *ed)
+{
+ prvm_prog_t *prog = world->prog;
+ int forcetype = 0, movetype = 0, enemy = 0;
+ vec3_t movedir, origin;
+
+ movetype = (int)PRVM_gameedictfloat(ed, movetype);
+ forcetype = (int)PRVM_gameedictfloat(ed, forcetype);
+ if (movetype == MOVETYPE_PHYSICS)
+ forcetype = FORCETYPE_NONE; // can't have both
+ if (!forcetype)
+ return;
+ enemy = PRVM_gameedictedict(ed, enemy);
+ if (enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].free || prog->edicts[enemy].priv.server->ode_body == 0)
+ return;
+ VectorCopy(PRVM_gameedictvector(ed, movedir), movedir);
+ VectorCopy(PRVM_gameedictvector(ed, origin), origin);
+ dBodyEnable((dBodyID)prog->edicts[enemy].priv.server->ode_body);
+ switch(forcetype)
+ {
+ case FORCETYPE_FORCE:
+ if (movedir[0] || movedir[1] || movedir[2])
+ dBodyAddForce((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]);
+ break;
+ case FORCETYPE_FORCEATPOS:
+ if (movedir[0] || movedir[1] || movedir[2])
+ dBodyAddForceAtPos((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2], origin[0], origin[1], origin[2]);
+ break;
+ case FORCETYPE_TORQUE:
+ if (movedir[0] || movedir[1] || movedir[2])
+ dBodyAddTorque((dBodyID)prog->edicts[enemy].priv.server->ode_body, movedir[0], movedir[1], movedir[2]);
+ break;
+ case FORCETYPE_NONE:
+ default:
+ // bad force
+ break;
+ }
+}
+
+static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed)
+{
+ prvm_prog_t *prog = world->prog;
+ 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;
+ vec_t CFM, ERP, FMax, Stop, Vel;
+
+ movetype = (int)PRVM_gameedictfloat(ed, movetype);
+ jointtype = (int)PRVM_gameedictfloat(ed, jointtype);
+ VectorClear(origin);
+ VectorClear(velocity);
+ VectorClear(angles);
+ VectorClear(movedir);
+ enemy = PRVM_gameedictedict(ed, enemy);
+ aiment = PRVM_gameedictedict(ed, aiment);
+ VectorCopy(PRVM_gameedictvector(ed, origin), origin);
+ VectorCopy(PRVM_gameedictvector(ed, velocity), velocity);
+ VectorCopy(PRVM_gameedictvector(ed, angles), angles);
+ VectorCopy(PRVM_gameedictvector(ed, movedir), movedir);
+ if(movetype == MOVETYPE_PHYSICS)
+ jointtype = JOINTTYPE_NONE; // can't have both
+ if(enemy <= 0 || enemy >= prog->num_edicts || prog->edicts[enemy].free || prog->edicts[enemy].priv.server->ode_body == 0)
+ enemy = 0;
+ if(aiment <= 0 || aiment >= prog->num_edicts || prog->edicts[aiment].free || prog->edicts[aiment].priv.server->ode_body == 0)
+ aiment = 0;
+ // see http://www.ode.org/old_list_archives/2006-January/017614.html
+ // 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[1];
+ float R = 2.0 * D * sqrt(K); // we assume D is premultiplied by sqrt(sprungMass)
+ 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;
+ }
+ 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((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_HINGE:
+ j = dJointCreateHinge((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_SLIDER:
+ j = dJointCreateSlider((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_UNIVERSAL:
+ j = dJointCreateUniversal((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_HINGE2:
+ j = dJointCreateHinge2((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_FIXED:
+ j = dJointCreateFixed((dWorldID)world->physics.ode_world, 0);
+ break;
+ case JOINTTYPE_NONE:
+ default:
+ // no joint
+ j = 0;
+ break;
+ }
+ if(ed->priv.server->ode_joint)
+ {
+ //Con_Printf("deleted old joint %i\n", (int) (ed - prog->edicts));
+ dJointAttach((dJointID)ed->priv.server->ode_joint, 0, 0);
+ dJointDestroy((dJointID)ed->priv.server->ode_joint);
+ }
+ ed->priv.server->ode_joint = (void *) j;
+ ed->priv.server->ode_joint_type = jointtype;
+ 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);
+ 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);
+
+ 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]);
+ 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]);
+ 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]);
+ 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]);
+ 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:
+ Sys_Error("what? but above the joint was valid...\n");
+ break;
+ }
+#undef SETPARAMS
+
+ }