ODE improvements:
authorvortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 16 Dec 2010 17:49:24 +0000 (17:49 +0000)
committervortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 16 Dec 2010 17:49:24 +0000 (17:49 +0000)
- physics_enable builtin (enable/disable objects)
- physics_addforce (add force to certain point in object)
- physics_addtorgue (add relative torgue)
- extension documented as "DP_PHYSICS_ODE", added additional check if lib is enabled in checextension()
- #ifdef'ed usage of dWorldStepFast1 and make it off by default as it's been removed from ODE trunk
- added "collision" mesh support, if there is some mesh with "collision" texture, all other meshes are ignored and that mesh is used.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10667 d7cf8633-e32d-0410-b094-e92efae38249

clvm_cmds.c
dpdefs/dpextensions.qc
model_shared.c
progs.h
prvm_cmds.c
prvm_cmds.h
svvm_cmds.c
world.c
world.h

index c95864ba9b078cbeadd38312d2e334d795f67e72..a30ce3c0c35745ba95309332a0f8e3e2e55ea543 100644 (file)
@@ -4544,9 +4544,9 @@ NULL,                                                     // #536
 NULL,                                                  // #537
 NULL,                                                  // #538
 NULL,                                                  // #539
-NULL,                                                  // #540
-NULL,                                                  // #541
-NULL,                                                  // #542
+VM_physics_enable,                             // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
+VM_physics_addforce,                   // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
+VM_physics_addtorgue,                  // #542 void(entity e, vector torgue) physics_addtorgue = #542; (DP_PHYSICS_ODE)
 NULL,                                                  // #543
 NULL,                                                  // #544
 NULL,                                                  // #545
index afe67c9b5b83faf675daf74800fa904e9b9ba09f..06361ae69d3a4140f2833b14b1a0a114db5924ae 100644 (file)
@@ -1572,6 +1572,38 @@ void(float effectnum, vector org, vector vel, float howmany) pointparticles = #3
 //description:
 //.movement vector contains the movement input from the player, allowing QC to do as it wishs with the input, and SV_PlayerPhysics will completely replace the player physics if present (works for all MOVETYPE's), see darkplaces mod source for example of this function (in playermovement.qc, adds HalfLife ladders support, as well as acceleration/deceleration while airborn (rather than the quake sudden-stop while airborn), and simplifies the physics a bit)
 
+//DP_PHYSICS_ODE
+//idea: LordHavoc
+//darkplaces implementation: LordHavoc
+//globals:
+//new movetypes:
+const float MOVETYPE_PHYSICS = 32; // need to be set before any physics_* builtins applied
+//new solid types:
+const float SOLID_PHYSICS_BOX = 32;
+const float SOLID_PHYSICS_SPHERE = 33;
+const float SOLID_PHYSICS_CAPSULE = 34;
+//SOLID_BSP;
+//joint types:
+const float JOINTTYPE_POINT = 1;
+const float JOINTTYPE_HINGE = 2;
+const float JOINTTYPE_SLIDER = 3;
+const float JOINTTYPE_UNIVERSAL = 4;
+const float JOINTTYPE_HINGE2 = 5;
+const float JOINTTYPE_FIXED = -1;
+//field definitions:
+.float mass; // ODE mass, standart value is 1
+.float bouncefactor;
+.float bouncestop;
+.float jointtype;
+//builtin definitions:
+void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object
+void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force
+void(entity e, vector torgue) physics_addtorgue = #542; // add relative torgue
+//description: provides Open Dynamics Engine support, requires extenal dll to be present or engine compiled with statical link option
+//be sure to checkextension for it to know if library i loaded and ready, also to enable physics set "physice_ode" cvar to 1
+//note: this extension is highly experimental and may be unstable
+//note: use SOLID_BSP on entities to get a trimesh collision models on them
+
 //DP_SV_PRINT
 //idea: id Software (QuakeWorld Server)
 //darkplaces implementation: Black, LordHavoc
index 74af7c5975a982412dc68f663cddac656c2fbb07..771311e98efe88fb4f4fc1e65c631a45411e8d5b 100644 (file)
@@ -1364,9 +1364,10 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
 
 void Mod_CreateCollisionMesh(dp_model_t *mod)
 {
-       int k;
-       int numcollisionmeshtriangles;
-       const msurface_t *surface;
+       int k, numcollisionmeshtriangles;
+       qboolean usesinglecollisionmesh = false;
+       const msurface_t *surface = NULL;
+
        mempool_t *mempool = mod->mempool;
        if (!mempool && mod->brush.parentmodel)
                mempool = mod->brush.parentmodel->mempool;
@@ -1376,17 +1377,28 @@ void Mod_CreateCollisionMesh(dp_model_t *mod)
        for (k = 0;k < mod->nummodelsurfaces;k++)
        {
                surface = mod->data_surfaces + mod->firstmodelsurface + k;
+               if (!strcmp(surface->texture->name, "collision")) // found collision mesh
+               {
+                       usesinglecollisionmesh = true;
+                       numcollisionmeshtriangles = surface->num_triangles;
+                       break;
+               }
                if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
                        continue;
                numcollisionmeshtriangles += surface->num_triangles;
        }
        mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, false, true);
-       for (k = 0;k < mod->nummodelsurfaces;k++)
-       {
-               surface = mod->data_surfaces + mod->firstmodelsurface + k;
-               if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
-                       continue;
+       if (usesinglecollisionmesh)
                Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+       else
+       {
+               for (k = 0;k < mod->nummodelsurfaces;k++)
+               {
+                       surface = mod->data_surfaces + mod->firstmodelsurface + k;
+                       if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
+                               continue;
+                       Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
+               }
        }
        mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, true, false);
 }
diff --git a/progs.h b/progs.h
index fedd19e554cd66501557b61766a0b29b1c8bf5d2..b7208e5fa01cc7589cb116f048c07a68be052e75 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -32,6 +32,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define JOINTTYPE_HINGE2 5
 #define JOINTTYPE_FIXED -1
 
+#define ODEFUNC_ENABLE                 1
+#define ODEFUNC_DISABLE                        2
+#define ODEFUNC_RELFORCEATPOS  3
+#define ODEFUNC_RELTORGUE              4
+
+typedef struct edict_odefunc_s
+{
+       int type;
+       vec3_t v1;
+       vec3_t v2;
+       struct edict_odefunc_s *next;
+}edict_odefunc_t;
+
 typedef struct edict_engineprivate_s
 {
        // true if this edict is unused
@@ -89,6 +102,7 @@ typedef struct edict_engineprivate_s
        int *ode_element3i;
        int ode_numvertices;
        int ode_numtriangles;
+       edict_odefunc_t *ode_func;
        vec3_t ode_mins;
        vec3_t ode_maxs;
        vec_t ode_mass;
index a1aef535a0842a3de2137488d4feef0d744b7ce3..5755ef7c86a297975ba1c597153ac0c7d621fef7 100644 (file)
@@ -272,7 +272,18 @@ static qboolean checkextension(const char *name)
                while (*e && *e != ' ')
                        e++;
                if ((e - start) == len && !strncasecmp(start, name, len))
+               {
+                       // special sheck for ODE
+                       if (!strncasecmp("DP_PHYSICS_ODE", name, 14))
+                       {
+#ifdef USEODE
+                               return ode_dll ? true : false;
+#else
+                               return false;
+#endif
+                       }
                        return true;
+               }
        }
        return false;
 }
@@ -6865,3 +6876,103 @@ void VM_getsurfacetriangle(void)
        // FIXME: implement rotation/scaling
        VectorMA(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], surface->num_firstvertex, d, PRVM_G_VECTOR(OFS_RETURN));
 }
+
+//
+// physics builtins
+//
+
+void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f);
+
+#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(ed, f); else World_Physics_ApplyCmd(ed, f)
+
+edict_odefunc_t *VM_physics_newstackfunction(prvm_edict_t *ed, edict_odefunc_t *f)
+{
+       edict_odefunc_t *newfunc, *func;
+
+       newfunc = (edict_odefunc_t *)Mem_Alloc(prog->progs_mempool, sizeof(edict_odefunc_t));
+       memcpy(newfunc, f, sizeof(edict_odefunc_t));
+       newfunc->next = NULL;
+       if (!ed->priv.server->ode_func)
+               ed->priv.server->ode_func = newfunc;
+       else
+       {
+               for (func = ed->priv.server->ode_func; func->next; func = func->next);
+               func->next = newfunc;
+       }
+       return newfunc;
+}
+
+// void(entity e, float physics_enabled) physics_enable = #;
+void VM_physics_enable(void)
+{
+       prvm_edict_t *ed;
+       edict_odefunc_t f;
+       
+       VM_SAFEPARMCOUNT(2, VM_physics_enable);
+       ed = PRVM_G_EDICT(OFS_PARM0);
+       if (!ed)
+       {
+               if (developer.integer > 0)
+                       VM_Warning("VM_physics_enable: null entity!\n");
+               return;
+       }
+       // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       {
+               VM_Warning("VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n");
+               return;
+       }
+       f.type = PRVM_G_FLOAT(OFS_PARM1) == 0 ? ODEFUNC_DISABLE : ODEFUNC_ENABLE;
+       VM_physics_ApplyCmd(ed, &f);
+}
+
+// void(entity e, vector force, vector relative_ofs) physics_addforce = #;
+void VM_physics_addforce(void)
+{
+       prvm_edict_t *ed;
+       edict_odefunc_t f;
+       
+       VM_SAFEPARMCOUNT(3, VM_physics_addforce);
+       ed = PRVM_G_EDICT(OFS_PARM0);
+       if (!ed)
+       {
+               if (developer.integer > 0)
+                       VM_Warning("VM_physics_addforce: null entity!\n");
+               return;
+       }
+       // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       {
+               VM_Warning("VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
+               return;
+       }
+       f.type = ODEFUNC_RELFORCEATPOS;
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
+       VectorSubtract(ed->fields.server->origin, PRVM_G_VECTOR(OFS_PARM2), f.v2);
+       VM_physics_ApplyCmd(ed, &f);
+}
+
+// void(entity e, vector torgue) physics_addtorgue = #;
+void VM_physics_addtorgue(void)
+{
+       prvm_edict_t *ed;
+       edict_odefunc_t f;
+       
+       VM_SAFEPARMCOUNT(2, VM_physics_addtorgue);
+       ed = PRVM_G_EDICT(OFS_PARM0);
+       if (!ed)
+       {
+               if (developer.integer > 0)
+                       VM_Warning("VM_physics_addtorgue: null entity!\n");
+               return;
+       }
+       // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
+       if (ed->fields.server->movetype != MOVETYPE_PHYSICS)
+       {
+               VM_Warning("VM_physics_addtorgue: entity is not MOVETYPE_PHYSICS!\n");
+               return;
+       }
+       f.type = ODEFUNC_RELTORGUE;
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
+       VM_physics_ApplyCmd(ed, &f);
+}
index d47aa613639e8dc7b80b203bfff7ad1f2fc8b765..6ca09b19bad9b43f7d412683f6362a3f3b66a5f0 100644 (file)
@@ -473,3 +473,8 @@ void VM_getsurfacenearpoint(void);
 void VM_getsurfaceclippedpoint(void);
 void VM_getsurfacenumtriangles(void);
 void VM_getsurfacetriangle(void);
+
+// physics builtins
+void VM_physics_enable(void);
+void VM_physics_addforce(void);
+void VM_physics_addtorgue(void);
index 890dee78ba19f04a9abca04c34492bfb3c1945d2..d9bc0aedacde87c7cf14d697129aa00e3e99466f 100644 (file)
@@ -167,6 +167,7 @@ const char *vm_sv_extensions =
 "DP_SV_PING "
 "DP_SV_PING_PACKETLOSS "
 "DP_SV_PLAYERPHYSICS "
+"DP_PHYSICS_ODE "
 "DP_SV_POINTPARTICLES "
 "DP_SV_POINTSOUND "
 "DP_SV_PRECACHEANYTIME "
@@ -3679,9 +3680,9 @@ NULL,                                                     // #536
 NULL,                                                  // #537
 NULL,                                                  // #538
 NULL,                                                  // #539
-NULL,                                                  // #540
-NULL,                                                  // #541
-NULL,                                                  // #542
+VM_physics_enable,                             // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
+VM_physics_addforce,                   // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
+VM_physics_addtorgue,                  // #542 void(entity e, vector torgue) physics_addtorgue = #542; (DP_PHYSICS_ODE)
 NULL,                                                  // #543
 NULL,                                                  // #544
 NULL,                                                  // #545
diff --git a/world.c b/world.c
index b54dbc8113fbc15a2477320c89a25e6df9452104..9028195730ee26c0d9e903b21c39ddf7e7dcf588 100644 (file)
--- a/world.c
+++ b/world.c
@@ -323,6 +323,9 @@ void World_LinkEdict(world_t *world, prvm_edict_t *ent, const vec3_t mins, const
 #define USEODE 1
 #endif
 
+// recent ODE trunk has dWorldStepFast1 removed
+//#define ODE_USE_STEPFAST
+
 #ifdef USEODE
 cvar_t physics_ode_quadtree_depth = {0, "physics_ode_quadtree_depth","5", "desired subdivision level of quadtree culling space"};
 cvar_t physics_ode_contactsurfacelayer = {0, "physics_ode_contactsurfacelayer","1", "allows objects to overlap this many units to reduce jitter"};
@@ -584,7 +587,9 @@ void            (ODE_API *dWorldSetQuickStepNumIterations)(dWorldID, int num);
 //dReal           (ODE_API *dWorldGetContactMaxCorrectingVel)(dWorldID);
 void            (ODE_API *dWorldSetContactSurfaceLayer)(dWorldID, dReal depth);
 //dReal           (ODE_API *dWorldGetContactSurfaceLayer)(dWorldID);
+#ifdef ODE_USE_STEPFAST
 void            (ODE_API *dWorldStepFast1)(dWorldID, dReal stepsize, int maxiterations);
+#endif
 //void            (ODE_API *dWorldSetAutoEnableDepthSF1)(dWorldID, int autoEnableDepth);
 //int             (ODE_API *dWorldGetAutoEnableDepthSF1)(dWorldID);
 //dReal           (ODE_API *dWorldGetAutoDisableLinearThreshold)(dWorldID);
@@ -650,9 +655,9 @@ void            (ODE_API *dBodySetMass)(dBodyID, const dMass *mass);
 //void            (ODE_API *dBodyAddForce)(dBodyID, dReal fx, dReal fy, dReal fz);
 //void            (ODE_API *dBodyAddTorque)(dBodyID, dReal fx, dReal fy, dReal fz);
 //void            (ODE_API *dBodyAddRelForce)(dBodyID, dReal fx, dReal fy, dReal fz);
-//void            (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz);
+void            (ODE_API *dBodyAddRelTorque)(dBodyID, dReal fx, dReal fy, dReal fz);
 //void            (ODE_API *dBodyAddForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
-//void            (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
+void            (ODE_API *dBodyAddForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
 //void            (ODE_API *dBodyAddRelForceAtPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
 //void            (ODE_API *dBodyAddRelForceAtRelPos)(dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz);
 //const dReal *   (ODE_API *dBodyGetForce)(dBodyID);
@@ -674,8 +679,8 @@ 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 *dBodyEnable)(dBodyID);
-//void            (ODE_API *dBodyDisable)(dBodyID);
+void            (ODE_API *dBodyEnable)(dBodyID);
+void            (ODE_API *dBodyDisable)(dBodyID);
 int             (ODE_API *dBodyIsEnabled)(dBodyID);
 void            (ODE_API *dBodySetGravityMode)(dBodyID b, int mode);
 int             (ODE_API *dBodyGetGravityMode)(dBodyID b);
@@ -1049,7 +1054,9 @@ static dllfunction_t odefuncs[] =
 //     {"dWorldGetContactMaxCorrectingVel",                    (void **) &dWorldGetContactMaxCorrectingVel},
        {"dWorldSetContactSurfaceLayer",                                (void **) &dWorldSetContactSurfaceLayer},
 //     {"dWorldGetContactSurfaceLayer",                                (void **) &dWorldGetContactSurfaceLayer},
+#ifdef ODE_USE_STEPFAST
        {"dWorldStepFast1",                                                             (void **) &dWorldStepFast1},
+#endif
 //     {"dWorldSetAutoEnableDepthSF1",                                 (void **) &dWorldSetAutoEnableDepthSF1},
 //     {"dWorldGetAutoEnableDepthSF1",                                 (void **) &dWorldGetAutoEnableDepthSF1},
 //     {"dWorldGetAutoDisableLinearThreshold",                 (void **) &dWorldGetAutoDisableLinearThreshold},
@@ -1115,9 +1122,9 @@ static dllfunction_t odefuncs[] =
 //     {"dBodyAddForce",                                                               (void **) &dBodyAddForce},
 //     {"dBodyAddTorque",                                                              (void **) &dBodyAddTorque},
 //     {"dBodyAddRelForce",                                                    (void **) &dBodyAddRelForce},
-//     {"dBodyAddRelTorque",                                                   (void **) &dBodyAddRelTorque},
+       {"dBodyAddRelTorque",                                                   (void **) &dBodyAddRelTorque},
 //     {"dBodyAddForceAtPos",                                                  (void **) &dBodyAddForceAtPos},
-//     {"dBodyAddForceAtRelPos",                                               (void **) &dBodyAddForceAtRelPos},
+       {"dBodyAddForceAtRelPos",                                               (void **) &dBodyAddForceAtRelPos},
 //     {"dBodyAddRelForceAtPos",                                               (void **) &dBodyAddRelForceAtPos},
 //     {"dBodyAddRelForceAtRelPos",                                    (void **) &dBodyAddRelForceAtRelPos},
 //     {"dBodyGetForce",                                                               (void **) &dBodyGetForce},
@@ -1139,8 +1146,8 @@ static dllfunction_t odefuncs[] =
 //     {"dBodySetDynamic",                                                             (void **) &dBodySetDynamic},
 //     {"dBodySetKinematic",                                                   (void **) &dBodySetKinematic},
 //     {"dBodyIsKinematic",                                                    (void **) &dBodyIsKinematic},
-//     {"dBodyEnable",                                                                 (void **) &dBodyEnable},
-//     {"dBodyDisable",                                                                (void **) &dBodyDisable},
+       {"dBodyEnable",                                                                 (void **) &dBodyEnable},
+       {"dBodyDisable",                                                                (void **) &dBodyDisable},
        {"dBodyIsEnabled",                                                              (void **) &dBodyIsEnabled},
        {"dBodySetGravityMode",                                                 (void **) &dBodySetGravityMode},
        {"dBodyGetGravityMode",                                                 (void **) &dBodyGetGravityMode},
@@ -1646,6 +1653,8 @@ void World_Physics_RemoveJointFromEntity(world_t *world, prvm_edict_t *ed)
 
 void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed)
 {
+       edict_odefunc_t *f, *nf;
+
        // entity is not physics controlled, free any physics data
        ed->priv.server->ode_physics = false;
 #ifdef USEODE
@@ -1690,6 +1699,40 @@ void World_Physics_RemoveFromEntity(world_t *world, prvm_edict_t *ed)
        if(ed->priv.server->ode_massbuf)
                Mem_Free(ed->priv.server->ode_massbuf);
        ed->priv.server->ode_massbuf = NULL;
+       // clear functions stack
+       for(f = ed->priv.server->ode_func; f; f = nf)
+       {
+               nf = f->next;
+               Mem_Free(f);
+       }
+       ed->priv.server->ode_func = NULL;
+}
+
+void World_Physics_ApplyCmd(prvm_edict_t *ed, edict_odefunc_t *f)
+{
+       dBodyID body = (dBodyID)ed->priv.server->ode_body;
+
+#ifdef USEODE
+       switch(f->type)
+       {
+       case ODEFUNC_ENABLE:
+               dBodyEnable(body);
+               break;
+       case ODEFUNC_DISABLE:
+               dBodyDisable(body);
+               break;
+       case ODEFUNC_RELFORCEATPOS:
+               dBodyEnable(body);
+               dBodyAddForceAtRelPos(body, f->v1[0], f->v1[1], f->v1[2], f->v2[0], f->v2[1], f->v2[2]);
+               break;
+       case ODEFUNC_RELTORGUE:
+               dBodyEnable(body);
+               dBodyAddRelTorque(body, f->v1[0], f->v1[1], f->v1[2]);
+               break;
+       default:
+               break;
+       }
+#endif
 }
 
 #ifdef USEODE
@@ -1986,6 +2029,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        dBodyID body = (dBodyID)ed->priv.server->ode_body;
        dMass mass;
        dReal test;
+       const dReal *ovelocity, *ospinvelocity;
        void *dataID;
        dVector3 capsulerot[3];
        dp_model_t *model;
@@ -2022,6 +2066,8 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, prvm_edict_t *ed)
        vec_t scale = 1.0f;
        vec_t spinlimit;
        qboolean gravity;
+       edict_odefunc_t *func, *nextf;
+
 #ifdef ODE_DYNAMIC
        if (!ode_dll)
                return;
@@ -2414,9 +2460,10 @@ treatasbox:
 
        if(body)
        {
+
                // limit movement speed to prevent missed collisions at high speed
-               const dReal *ovelocity = dBodyGetLinearVel(body);
-               const dReal *ospinvelocity = dBodyGetAngularVel(body);
+               ovelocity = dBodyGetLinearVel(body);
+               ospinvelocity = dBodyGetAngularVel(body);
                movelimit = ed->priv.server->ode_movelimit * world->physics.ode_movelimit;
                test = VectorLength2(ovelocity);
                if (test > movelimit*movelimit)
@@ -2437,6 +2484,15 @@ treatasbox:
                {
                        dBodySetAngularVel(body, 0, 0, 0);
                }
+
+               // apply functions and clear stack
+               for(func = ed->priv.server->ode_func; func; func = nextf)
+               {
+                       nextf = func->next;
+                       World_Physics_ApplyCmd(ed, func);
+                       Mem_Free(func);
+               }
+               ed->priv.server->ode_func = NULL;
        }
 }
 
@@ -2608,8 +2664,10 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity)
                                dWorldSetQuickStepNumIterations((dWorldID)world->physics.ode_world, bound(1, physics_ode_worldstep_iterations.integer, 200));
                                dWorldQuickStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
                        }
+#ifdef ODE_USE_STEPFAST
                        else if (physics_ode_worldstep.integer == 1)
                                dWorldStepFast1((dWorldID)world->physics.ode_world, world->physics.ode_step, bound(1, physics_ode_worldstep_iterations.integer, 200));
+#endif
                        else
                                dWorldStep((dWorldID)world->physics.ode_world, world->physics.ode_step);
 
diff --git a/world.h b/world.h
index fbf9e8351381ec7cb28cc8fb119ab36513554648..334420fbff9599d29012044e417b139dadf4be51 100644 (file)
--- a/world.h
+++ b/world.h
@@ -118,9 +118,13 @@ void World_End(world_t *world);
 // this is called by SV_Physics
 void World_Physics_Frame(world_t *world, double frametime, double gravity);
 
+// change physics properties of entity
+struct prvm_edict_s;
+struct edict_odefunc_s;
+//void World_Physics_ApplyCmd(prvm_edict_s *ed, edict_odefunc_s *f);
+
 // remove physics data from entity
 // this is called by entity removal
-struct prvm_edict_s;
 void World_Physics_RemoveFromEntity(world_t *world, struct prvm_edict_s *ed);
 void World_Physics_RemoveJointFromEntity(world_t *world, struct prvm_edict_s *ed);