X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=world.c;h=f705982ea63237f82e0bf9148dc5193977520601;hb=fcdaa4edcc329da6cebc246e0e2db876603f0e05;hp=7d03bb2c5b529db6493b1d4acfcfa6856a55e8bb;hpb=40ede0998143855ae68b3399d8c5ed4313f79f47;p=xonotic%2Fdarkplaces.git diff --git a/world.c b/world.c index 7d03bb2c..f705982e 100644 --- a/world.c +++ b/world.c @@ -113,16 +113,16 @@ void World_SetSize(world_t *world, const char *filename, const vec3_t mins, cons if (world->areagrid_marknumber < 1) world->areagrid_marknumber = 1; // choose either the world box size, or a larger box to ensure the grid isn't too fine - world->areagrid_size[0] = max(world->areagrid_maxs[0] - world->areagrid_mins[0], AREA_GRID * sv_areagrid_mingridsize.value); - world->areagrid_size[1] = max(world->areagrid_maxs[1] - world->areagrid_mins[1], AREA_GRID * sv_areagrid_mingridsize.value); - world->areagrid_size[2] = max(world->areagrid_maxs[2] - world->areagrid_mins[2], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[0] = max(world->maxs[0] - world->mins[0], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[1] = max(world->maxs[1] - world->mins[1], AREA_GRID * sv_areagrid_mingridsize.value); + world->areagrid_size[2] = max(world->maxs[2] - world->mins[2], AREA_GRID * sv_areagrid_mingridsize.value); // figure out the corners of such a box, centered at the center of the world box - world->areagrid_mins[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] - world->areagrid_size[0]) * 0.5f; - world->areagrid_mins[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] - world->areagrid_size[1]) * 0.5f; - world->areagrid_mins[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] - world->areagrid_size[2]) * 0.5f; - world->areagrid_maxs[0] = (world->areagrid_mins[0] + world->areagrid_maxs[0] + world->areagrid_size[0]) * 0.5f; - world->areagrid_maxs[1] = (world->areagrid_mins[1] + world->areagrid_maxs[1] + world->areagrid_size[1]) * 0.5f; - world->areagrid_maxs[2] = (world->areagrid_mins[2] + world->areagrid_maxs[2] + world->areagrid_size[2]) * 0.5f; + world->areagrid_mins[0] = (world->mins[0] + world->maxs[0] - world->areagrid_size[0]) * 0.5f; + world->areagrid_mins[1] = (world->mins[1] + world->maxs[1] - world->areagrid_size[1]) * 0.5f; + world->areagrid_mins[2] = (world->mins[2] + world->maxs[2] - world->areagrid_size[2]) * 0.5f; + world->areagrid_maxs[0] = (world->mins[0] + world->maxs[0] + world->areagrid_size[0]) * 0.5f; + world->areagrid_maxs[1] = (world->mins[1] + world->maxs[1] + world->areagrid_size[1]) * 0.5f; + world->areagrid_maxs[2] = (world->mins[2] + world->maxs[2] + world->areagrid_size[2]) * 0.5f; // now calculate the actual useful info from that VectorNegate(world->areagrid_mins, world->areagrid_bias); world->areagrid_scale[0] = AREA_GRID / world->areagrid_size[0]; @@ -131,8 +131,8 @@ void World_SetSize(world_t *world, const char *filename, const vec3_t mins, cons 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); } /* @@ -371,6 +371,8 @@ struct dxJointNode; struct dxJointGroup; struct dxTriMeshData; +#define dInfinity 3.402823466e+38f + typedef struct dxWorld *dWorldID; typedef struct dxSpace *dSpaceID; typedef struct dxBody *dBodyID; @@ -524,7 +526,7 @@ typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); #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); @@ -689,7 +691,7 @@ 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 *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); @@ -863,11 +865,11 @@ void (ODE_API *dSpaceDestroy)(dSpaceID); //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); @@ -990,7 +992,7 @@ dGeomID (ODE_API *dCreateTriMesh)(dSpaceID space, dTriMeshDataID Data, d static dllfunction_t odefuncs[] = { // {"dGetConfiguration", (void **) &dGetConfiguration}, -// {"dCheckConfiguration", (void **) &dCheckConfiguration}, + {"dCheckConfiguration", (void **) &dCheckConfiguration}, {"dInitODE", (void **) &dInitODE}, // {"dInitODE2", (void **) &dInitODE2}, // {"dAllocateODEDataForThread", (void **) &dAllocateODEDataForThread}, @@ -1154,7 +1156,7 @@ static dllfunction_t odefuncs[] = // {"dJointCreatePR", (void **) &dJointCreatePR}, // {"dJointCreatePU", (void **) &dJointCreatePU}, // {"dJointCreatePiston", (void **) &dJointCreatePiston}, -// {"dJointCreateFixed", (void **) &dJointCreateFixed}, + {"dJointCreateFixed", (void **) &dJointCreateFixed}, // {"dJointCreateNull", (void **) &dJointCreateNull}, // {"dJointCreateAMotor", (void **) &dJointCreateAMotor}, // {"dJointCreateLMotor", (void **) &dJointCreateLMotor}, @@ -1326,11 +1328,11 @@ static dllfunction_t odefuncs[] = // {"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}, @@ -1447,9 +1449,7 @@ static void World_Physics_Init(void) #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", @@ -1482,7 +1482,7 @@ static void World_Physics_Init(void) { dInitODE(); // dInitODE2(0); -#ifdef ODE_DNYAMIC +#ifdef ODE_DYNAMIC # ifdef dSINGLE if (!dCheckConfiguration("ODE_single_precision")) # else @@ -1576,7 +1576,6 @@ void World_Physics_RemoveJointFromEntity(world_t *world, prvm_edict_t *ed) 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) @@ -1586,6 +1585,7 @@ void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed) { 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); @@ -1616,6 +1616,9 @@ void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed) 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 @@ -1657,6 +1660,8 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) break; case JOINTTYPE_HINGE2: break; + case JOINTTYPE_FIXED: + break; } return; } @@ -1713,6 +1718,12 @@ static void World_Physics_Frame_BodyToEntity(world_t *world, prvm_edict_t *ed) 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) @@ -1724,11 +1735,12 @@ 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; @@ -1744,19 +1756,35 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed 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); @@ -1777,12 +1805,21 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed 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; @@ -1790,31 +1827,17 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed 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: @@ -1823,31 +1846,65 @@ static void World_Physics_Frame_JointFromEntity(world_t *world, prvm_edict_t *ed 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 + } } @@ -1900,30 +1957,26 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) #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); @@ -2032,9 +2085,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) // 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: @@ -2042,20 +2093,13 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) 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; @@ -2079,16 +2123,40 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) // 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 @@ -2116,10 +2184,26 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) // 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 @@ -2165,30 +2249,6 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) } } - // 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) @@ -2199,25 +2259,32 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) // 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); @@ -2231,16 +2298,62 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) 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); + } } } @@ -2260,7 +2373,7 @@ static void nearCallback (void *data, dGeomID o1, dGeomID o2) 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)) { @@ -2284,33 +2397,43 @@ static void nearCallback (void *data, dGeomID o1, dGeomID 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); } } @@ -2359,6 +2482,10 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) 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) { @@ -2371,9 +2498,6 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity) 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 @@ -2402,7 +2526,7 @@ void World_Physics_Frame(world_t *world, double frametime, double 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