From e45962dc6d1c22ef753eed71b4077e42e8f65521 Mon Sep 17 00:00:00 2001 From: divverent Date: Fri, 23 Oct 2009 07:07:42 +0000 Subject: [PATCH] speed up ODE by not creating bodies for non-physics entities any more (only creating geoms now); fix speed limit code to no longer cause "butterfly flying" git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9386 d7cf8633-e32d-0410-b094-e92efae38249 --- world.c | 143 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/world.c b/world.c index c2a9059a..39d985d0 100644 --- a/world.c +++ b/world.c @@ -867,7 +867,7 @@ void (ODE_API *dGeomDestroy)(dGeomID geom); //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); @@ -1330,7 +1330,7 @@ static dllfunction_t odefuncs[] = // {"dGeomGetData", (void **) &dGeomGetData}, {"dGeomSetBody", (void **) &dGeomSetBody}, {"dGeomGetBody", (void **) &dGeomGetBody}, -// {"dGeomSetPosition", (void **) &dGeomSetPosition}, + {"dGeomSetPosition", (void **) &dGeomSetPosition}, {"dGeomSetRotation", (void **) &dGeomSetRotation}, // {"dGeomSetQuaternion", (void **) &dGeomSetQuaternion}, // {"dGeomGetPosition", (void **) &dGeomGetPosition}, @@ -1790,6 +1790,7 @@ 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) { dJointSetData(j, (void *) ed); @@ -1900,7 +1901,7 @@ 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; switch(solid) { @@ -2032,9 +2033,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 +2041,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,11 +2071,8 @@ 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); @@ -2091,6 +2080,21 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed) Matrix4x4_Invert_Simple(&ed->priv.server->ode_offsetimatrix, &ed->priv.server->ode_offsetmatrix); } + 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, &mass); + } + } + else + { + // let's keep the body around in case we need it again (in case QC toggles between MOVETYPE_PHYSICS and MOVETYPE_NONE) + } + // get current data from entity VectorClear(origin); VectorClear(velocity); @@ -2165,30 +2169,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,12 +2179,31 @@ 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) { dVector3 r[3]; matrix4x4_t entitymatrix; matrix4x4_t bodymatrix; + 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); + + // 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; + { float pitchsign = 1; if(!strcmp(prog->name, "server")) // FIXME some better way? @@ -2231,16 +2230,58 @@ 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, 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); + } + else + { + dGeomSetBody(ed->priv.server->ode_geom, 0); + dGeomSetPosition(ed->priv.server->ode_geom, origin[0], origin[1], origin[2]); + dGeomSetRotation(ed->priv.server->ode_geom, r[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); + } } } @@ -2402,7 +2443,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 -- 2.39.2