ODE: joints
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 22 Oct 2009 06:42:34 +0000 (06:42 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Thu, 22 Oct 2009 06:42:34 +0000 (06:42 +0000)
fields: jointtype, origin, angles, and depending on joint type, velocity as secondary axis
also, clean up pitchsign code to make ODE work with bmodels

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

13 files changed:
cl_main.c
clvm_cmds.c
clvm_cmds.h
csprogs.c
progs.h
progsvm.h
prvm_edict.c
server.h
sv_main.c
sv_phys.c
svvm_cmds.c
world.c
world.h

index af8c310..bf4d1d8 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -1001,6 +1001,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
        // if model is alias or this is a tenebrae-like dlight, reverse pitch direction
        else if (e->state_current.lightpflags & PFLAGS_FULLDYNAMIC)
                angles[0] = -angles[0];
+               // NOTE: this must be synced to SV_GetPitchSign!
 
        if ((e->render.effects & EF_ROTATE) && !(e->render.flags & RENDER_VIEWMODEL))
        {
index 7745663..959e043 100644 (file)
@@ -2232,12 +2232,19 @@ int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
        return 1;
 }
 
+int CL_GetPitchSign(prvm_edict_t *ent)
+{
+       dp_model_t *model;
+       if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
+               return -1;
+       return 1;
+}
+
 void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
        prvm_eval_t *val;
        float scale;
        float pitchsign = 1;
-       dp_model_t *model;
 
        scale = 1;
        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
@@ -2249,8 +2256,7 @@ void CL_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
                Matrix4x4_CreateFromQuakeEntity(out, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale * cl_viewmodel_scale.value);
        else
        {
-               if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
-                       pitchsign = -1;
+               pitchsign = CL_GetPitchSign(ent);
                Matrix4x4_CreateFromQuakeEntity(out, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], pitchsign * ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
        }
 }
index f081381..32aebeb 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __CLVM_CMDS_H__
 #define __CLVM_CMDS_H__
 
+int CL_GetPitchSign(prvm_edict_t *ent);
 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex);
 
 /* These are VM built-ins that originate in the client-side programs support
index 18d5c64..1f774fa 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -732,6 +732,7 @@ void CL_VM_CB_FreeEdict(prvm_edict_t *ed)
        World_UnlinkEdict(ed);
        memset(ed->fields.client, 0, sizeof(*ed->fields.client));
        World_Physics_RemoveFromEntity(&cl.world, ed);
+       World_Physics_RemoveJointFromEntity(&cl.world, ed);
 }
 
 void CL_VM_CB_CountEdicts(void)
diff --git a/progs.h b/progs.h
index 8327013..c3f3870 100644 (file)
--- a/progs.h
+++ b/progs.h
@@ -25,6 +25,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define ENTITYGRIDAREAS 16
 #define MAX_ENTITYCLUSTERS 16
 
+#define JOINTTYPE_POINT 1
+#define JOINTTYPE_HINGE 2
+#define JOINTTYPE_SLIDER 3
+#define JOINTTYPE_UNIVERSAL 4
+#define JOINTTYPE_HINGE2 5
+#define JOINTTYPE_PISTON 6
+
 typedef struct edict_engineprivate_s
 {
        // true if this edict is unused
@@ -73,6 +80,7 @@ typedef struct edict_engineprivate_s
        qboolean ode_physics;
        void *ode_body;
        void *ode_geom;
+       void *ode_joint;
        float *ode_vertex3f;
        int *ode_element3i;
        int ode_numvertices;
@@ -89,6 +97,12 @@ typedef struct edict_engineprivate_s
        vec_t ode_movelimit; // smallest component of (maxs[]-mins[])
        matrix4x4_t ode_offsetmatrix;
        matrix4x4_t ode_offsetimatrix;
+       int ode_joint_type;
+       int ode_joint_enemy;
+       int ode_joint_aiment;
+       vec3_t ode_joint_origin; // joint anchor
+       vec3_t ode_joint_angles; // joint axis
+       vec3_t ode_joint_velocity; // second joint axis
 }
 edict_engineprivate_t;
 
index d547789..229e60e 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -246,6 +246,9 @@ typedef struct prvm_prog_fieldoffsets_s
        //int spinvelocity; // ssqc / csqc (physics)
        //int angles; // ssqc / csqc (physics)
        int avelocity; // ssqc / csqc (physics)
+       int jointtype; // ssqc / csqc (physics)
+       int enemy; // ssqc / csqc (physics)
+       int aiment; // ssqc / csqc (physics)
 }
 prvm_prog_fieldoffsets_t;
 
index bbf7bae..7b2b3e1 100644 (file)
@@ -1650,6 +1650,9 @@ void PRVM_FindOffsets(void)
        //prog->fieldoffsets.spinvelocity                   = PRVM_ED_FindFieldOffset("spinvelocity");
        prog->fieldoffsets.angles                         = PRVM_ED_FindFieldOffset("angles");
        prog->fieldoffsets.avelocity                      = PRVM_ED_FindFieldOffset("avelocity");
+       prog->fieldoffsets.aiment                         = PRVM_ED_FindFieldOffset("aiment");
+       prog->fieldoffsets.enemy                          = PRVM_ED_FindFieldOffset("enemy");
+       prog->fieldoffsets.jointtype                      = PRVM_ED_FindFieldOffset("jointtype");
 
        prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
        prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
index d904c55..3869748 100644 (file)
--- a/server.h
+++ b/server.h
@@ -555,5 +555,7 @@ void SV_VM_End(void);
 
 const char *Host_TimingReport(void); ///< for output in Host_Status_f
 
+int SV_GetPitchSign(prvm_edict_t *ent);
+
 #endif
 
index 7d95115..ac717fa 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -1429,18 +1429,21 @@ qboolean SV_CanSeeBox(int numtraces, vec_t enlarge, vec3_t eye, vec3_t entboxmin
                {
                        touch = touchedicts[touchindex];
                        modelindex = (unsigned int)touch->fields.server->modelindex;
-                       model = sv.models[(int)touch->fields.server->modelindex];
-                       // get the entity matrix
-                       pitchsign = (model->type == mod_alias) ? -1 : 1;
-                       Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
-                       Matrix4x4_Invert_Simple(&imatrix, &matrix);
-                       // see if the ray hits this entity
-                       Matrix4x4_Transform(&imatrix, eye, starttransformed);
-                       Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
-                       if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed))
+                       model = (modelindex >= 1 && modelindex < MAX_MODELS) ? sv.models[(int)touch->fields.server->modelindex] : NULL;
+                       if(model && model->brush.TraceLineOfSight)
                        {
-                               blocked++;
-                               break;
+                               // get the entity matrix
+                               pitchsign = SV_GetPitchSign(touch);
+                               Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+                               Matrix4x4_Invert_Simple(&imatrix, &matrix);
+                               // see if the ray hits this entity
+                               Matrix4x4_Transform(&imatrix, eye, starttransformed);
+                               Matrix4x4_Transform(&imatrix, endpoints[traceindex], endtransformed);
+                               if (!model->brush.TraceLineOfSight(model, starttransformed, endtransformed))
+                               {
+                                       blocked++;
+                                       break;
+                               }
                        }
                }
                // check if the ray was blocked
@@ -3290,6 +3293,7 @@ static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
        ed->fields.server->solid = 0;
 
        World_Physics_RemoveFromEntity(&sv.world, ed);
+       World_Physics_RemoveJointFromEntity(&sv.world, ed);
 
        // make sure csqc networking is aware of the removed entity
        e = PRVM_NUM_FOR_EDICT(ed);
index e4292c1..db22156 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -43,6 +43,25 @@ solid_edge items only clip against bsp models.
 
 void SV_Physics_Toss (prvm_edict_t *ent);
 
+int SV_GetPitchSign(prvm_edict_t *ent)
+{
+       dp_model_t *model;
+       int modelindex;
+       if (
+                       ((modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
+                       ?
+                       model->type == mod_alias
+                       :
+                       (
+                        (((unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
+                        ||
+                        ((gamemode == GAME_TENEBRAE) && ((unsigned int)ent->fields.server->effects & (16 | 32)))
+                       )
+          )
+               return -1;
+       return 1;
+}
+
 /*
 ===============================================================================
 
@@ -199,19 +218,7 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                        // if the modelindex is 0, it shouldn't be SOLID_BSP!
                        if (modelindex > 0 && modelindex < MAX_MODELS)
                                model = sv.models[(int)touch->fields.server->modelindex];
-                       //pitchsign = 1;
-                       if (
-                               ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex]))
-                               ?
-                                       model->type == mod_alias
-                               :
-                                       (
-                                               (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
-                                               ||
-                                               ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32)))
-                                       )
-                       )
-                               pitchsign = -1;
+                       pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
                        Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
@@ -374,19 +381,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                        // if the modelindex is 0, it shouldn't be SOLID_BSP!
                        if (modelindex > 0 && modelindex < MAX_MODELS)
                                model = sv.models[(int)touch->fields.server->modelindex];
-                       //pitchsign = 1;
-                       if (
-                               ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex]))
-                               ?
-                                       model->type == mod_alias
-                               :
-                                       (
-                                               (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
-                                               ||
-                                               ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32)))
-                                       )
-                       )
-                               pitchsign = -1;
+                       pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
                        Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
@@ -587,18 +582,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                        if (modelindex > 0 && modelindex < MAX_MODELS)
                                model = sv.models[(int)touch->fields.server->modelindex];
                        //pitchsign = 1;
-                       if (
-                               ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex]))
-                               ?
-                                       model->type == mod_alias
-                               :
-                                       (
-                                               (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
-                                               ||
-                                               ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32)))
-                                       )
-                       )
-                               pitchsign = -1;
+                       pitchsign = SV_GetPitchSign(touch);
                }
                if (model)
                        Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
index f1f15f6..57ef2ee 100644 (file)
@@ -2620,8 +2620,6 @@ void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
        prvm_eval_t *val;
        float scale;
        float pitchsign = 1;
-       int modelindex;
-       dp_model_t *model;
 
        scale = 1;
        val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
@@ -2632,18 +2630,7 @@ void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatri
                Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], scale * cl_viewmodel_scale.value);
        else
        {
-               if (
-                       ((modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)ent->fields.server->modelindex]))
-                       ?
-                               model->type == mod_alias
-                       :
-                               (
-                                       (((unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
-                                       ||
-                                       ((gamemode == GAME_TENEBRAE) && ((unsigned int)ent->fields.server->effects & (16 | 32)))
-                               )
-               )
-                       pitchsign = -1;
+               pitchsign = SV_GetPitchSign(ent);
                Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], pitchsign * ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale);
        }
 }
diff --git a/world.c b/world.c
index 0013516..2f9118b 100644 (file)
--- 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"
 
 /*
 
@@ -1512,16 +1513,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)
@@ -1552,12 +1586,32 @@ 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;
+                       case JOINTTYPE_PISTON:
+                               break;
+               }
                return;
+       }
        // store the physics engine data into the entity
        o = dBodyGetPosition(body);
        r = dBodyGetRotation(body);
@@ -1579,9 +1633,23 @@ 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);
+       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);
        //val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.axis_forward);if (val) VectorCopy(forward, val->vector);
@@ -1599,6 +1667,109 @@ 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;
+       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);
+       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;
+       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)
+               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 JOINTTYPE_PISTON:
+                       j = dJointCreatePiston(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);
+               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]);
+                               break;
+                       case JOINTTYPE_SLIDER:
+                               dJointSetSliderAxis(j, forward[0], forward[1], forward[2]);
+                               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]);
+                               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]);
+                               break;
+                       case JOINTTYPE_PISTON:
+                               dJointSetPistonAxis(j, forward[0], forward[1], forward[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;
@@ -1858,6 +2029,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)
@@ -1950,6 +2123,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);
@@ -2092,9 +2280,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;
diff --git a/world.h b/world.h
index 7e3cf3a..4dad70b 100644 (file)
--- a/world.h
+++ b/world.h
@@ -119,6 +119,7 @@ void World_Physics_Frame(world_t *world, double frametime, double gravity);
 // 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);
 
 #endif