Completely rework body rotation mechanism
authorparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sun, 11 Jul 2010 13:53:07 +0000 (13:53 +0000)
committerparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sun, 11 Jul 2010 13:53:07 +0000 (13:53 +0000)
(See path_corner "angles" attribute description in entities.ent.)

git-svn-id: https://s.snth.net/svn/neverball/trunk@3192 78b8d119-cf0a-0410-b17c-f493084dd1d7

NeverballPack/neverball.game/data/entities.ent
ball/game_client.c
share/mapc.c
share/solid.c
share/solid.h
share/solid_all.c
share/solid_all.h
share/solid_gl.c
share/solid_sim_sol.c

index ccd6452..0550829 100644 (file)
@@ -97,6 +97,7 @@ Attributes:
 * <real key="speed" name="Travel time" value="1.0">Duration of the trip along this path segment, in seconds.  The default is "1.0".</real>
 * <boolean key="state" name="State" value="1">Determines whether the path is enabled.  An object will only move along an enabled path.  An object may be stopped and started by toggling the state of the path to which it is attached.  "0" means no, "1" means yes.  The default is 1.</boolean>
 * <boolean key="smooth" name="Smooth" value="1">Determines whether an object moves smoothly along this path segment or at a constant speed.  "0" means no, "1" means yes.  The default is 1.</boolean>
+* <angles key="angles" name="Orientation" value="0 0 0">Defines the final orientation of the object at this path_corner.  The first two values are angles giving the axis of rotation (first angle is inverse elevation, second angle is azimuth).  The third value is an angle giving the amount of rotation about the axis.  As the object travels between two path corners, its orientation is interpolated between the orientations of the corners.</angles>
 </point>
 
 
index 284cfc7..4273b6e 100644 (file)
@@ -359,7 +359,7 @@ static void game_run_cmd(const union cmd *cmd)
                 struct s_body *bp = file.bv + i;
                 struct s_path *pp = file.pv + bp->pi;
 
-                if (bp->pi >= 0 && pp->f && (bp->fl & P_ROTATING) == 0)
+                if (bp->pi >= 0 && pp->f)
                     bp->t += dt;
             }
             break;
@@ -383,7 +383,6 @@ static void game_run_cmd(const union cmd *cmd)
             break;
 
         case CMD_BODY_ORIENTATION:
-            q_cpy(file.bv[cmd->bodyorient.bi].e, cmd->bodyorient.e);
             break;
 
         case CMD_NONE:
index e3edcb8..2b247b1 100644 (file)
@@ -839,6 +839,36 @@ static void make_path(struct s_file *fp,
             pp->p[1] = +z / SCALE;
             pp->p[2] = -y / SCALE;
         }
+
+        if (strcmp(k[i], "angles") == 0)
+        {
+            float x = 0.0f, y = 0.0f, z = 0.0f;
+
+            /* Pitch, yaw and roll. */
+
+            sscanf(v[i], "%f %f %f", &x, &y, &z);
+
+            /*
+             * Find the direction vector from pitch and yaw, use it as
+             * the rotation axis.
+             */
+
+            x = V_RAD(-x);
+            y = V_RAD(+y);
+
+            pp->e[1] =  fcosf(y) * fcosf(x);
+            pp->e[2] =  fsinf(x);
+            pp->e[3] = -fsinf(y) * fcosf(x);
+
+            /* Use roll as the rotation angle. */
+
+            z = V_RAD(+z) * 0.5f;
+
+            pp->e[0] = fcosf(z);
+            v_scl(pp->e + 1, pp->e + 1, fsinf(z));
+
+            pp->fl |= P_ORIENTED;
+        }
     }
 }
 
@@ -908,10 +938,6 @@ static void make_body(struct s_file *fp,
         else if (strcmp(k[i], "origin") == 0)
             sscanf(v[i], "%f %f %f", &x, &y, &z);
 
-        else if (strcmp(k[i], "classname") == 0 &&
-                 strcmp(v[i], "func_rotating") == 0)
-            bp->fl |= P_ROTATING;
-
         else if (read_dict_entries && strcmp(k[i], "classname") != 0)
             make_dict(fp, k[i], v[i]);
     }
@@ -1289,7 +1315,6 @@ static void read_ent(struct s_file *fp, fs_file fin)
         make_body(fp, k, v, c, l0);
     }
     if (!strcmp(v[i], "func_train"))               make_body(fp, k, v, c, l0);
-    if (!strcmp(v[i], "func_rotating"))            make_body(fp, k, v, c, l0);
     if (!strcmp(v[i], "misc_model"))               make_body(fp, k, v, c, l0);
 }
 
index 000c9d2..b300d52 100644 (file)
@@ -26,7 +26,8 @@ enum
     SOL_VER_MINIMUM = 6,
     SOL_VER_LUMP_POLY,
     SOL_VER_BODY_FLAG,
-    SOL_VER_CURRENT = SOL_VER_BODY_FLAG
+    SOL_VER_PATH_FLAGS,
+    SOL_VER_CURRENT = SOL_VER_PATH_FLAGS
 };
 
 #define MAGIC 0x4c4f53af
@@ -135,6 +136,17 @@ static void sol_load_path(fs_file fin, struct s_path *pp)
     get_index(fin, &pp->pi);
     get_index(fin, &pp->f);
     get_index(fin, &pp->s);
+
+    if (sol_version >= SOL_VER_PATH_FLAGS)
+        get_index(fin, &pp->fl);
+
+    pp->e[0] = 1.0f;
+    pp->e[1] = 0.0f;
+    pp->e[2] = 0.0f;
+    pp->e[3] = 0.0f;
+
+    if (pp->fl & P_ORIENTED)
+        get_array(fin, pp->e, 4);
 }
 
 static void sol_load_body(fs_file fin, struct s_body *bp)
@@ -148,11 +160,6 @@ static void sol_load_body(fs_file fin, struct s_body *bp)
 
     if (sol_version >= SOL_VER_BODY_FLAG)
         get_index(fin, &bp->fl);
-
-    bp->e[0] = 1.0f;
-    bp->e[1] = 0.0f;
-    bp->e[2] = 0.0f;
-    bp->e[3] = 0.0f;
 }
 
 static void sol_load_item(fs_file fin, struct s_item *hp)
@@ -483,6 +490,10 @@ static void sol_stor_path(fs_file fout, struct s_path *pp)
     put_index(fout, &pp->pi);
     put_index(fout, &pp->f);
     put_index(fout, &pp->s);
+    put_index(fout, &pp->fl);
+
+    if (pp->fl & P_ORIENTED)
+        put_array(fout, pp->e, 4);
 }
 
 static void sol_stor_body(fs_file fout, struct s_body *bp)
index 150e5c2..bebb37a 100644 (file)
 #define ITEM_GROW       2
 #define ITEM_SHRINK     3
 
-/* Body flags. */
+/* Path flags. */
 
-#define P_ROTATING 1
+#define P_ORIENTED 1
 
 /*---------------------------------------------------------------------------*/
 
@@ -179,17 +179,21 @@ struct s_node
 struct s_path
 {
     float p[3];                                /* starting position          */
+    float e[4];                                /* orientation (quaternion)   */
     float t;                                   /* travel time                */
 
     int pi;
     int f;                                     /* enable flag                */
     int s;                                     /* smooth flag                */
+
+    int fl;                                    /* flags                      */
+
+    /* TODO: merge enable and smooth into flags. */
 };
 
 struct s_body
 {
     float t;                                   /* time on current path       */
-    float e[4];                                /* orientation (quaternion)   */
 
     GLuint ol;                                 /* opaque geometry list       */
     GLuint tl;                                 /* transparent geometry list  */
index b1021b1..36f8f87 100644 (file)
@@ -69,44 +69,76 @@ void sol_body_v(float v[3],
     }
 }
 
+void sol_body_e(float e[4],
+                const struct s_file *fp,
+                const struct s_body *bp)
+{
+    struct s_path *pp = fp->pv + bp->pi;
+
+    if (bp->pi >= 0)
+    {
+        struct s_path *pq = fp->pv + pp->pi;
+
+        if (pp->fl & P_ORIENTED || pq->fl & P_ORIENTED)
+        {
+            q_slerp(e, pp->e, pq->e, bp->t / pp->t);
+            return;
+        }
+    }
+
+    e[0] = 1.0f;
+    e[1] = 0.0f;
+    e[2] = 0.0f;
+    e[3] = 0.0f;
+}
+
 void sol_body_w(float w[3],
                 const struct s_file *fp,
                 const struct s_body *bp)
 {
-    if (bp->fl & P_ROTATING)
+    struct s_path *pp = fp->pv + bp->pi;
+
+    if (bp->pi >= 0 && pp->f)
     {
-        struct s_path *pp = fp->pv + bp->pi;
+        struct s_path *pq = fp->pv + pp->pi;
 
-        if (bp->pi >= 0 && pp->f)
+        if (pp->fl & P_ORIENTED || pq->fl & P_ORIENTED)
         {
-            struct s_path *pq = fp->pv + pp->pi;
+            float d[4], i[4], a;
 
-            if (pp->pi != bp->pi)
-            {
-                v_sub(w, pq->p, pp->p);
-                v_nrm(w, w);
-                v_scl(w, w, (1.0f / pp->t) * 2 * V_PI);
-            }
-            else
+            /*
+             * a * d = b
+             * d = b / a
+             * d = b * (1 / a)
+             */
+
+            i[0] =  pp->e[0];
+            i[1] = -pp->e[1];
+            i[2] = -pp->e[2];
+            i[3] = -pp->e[3];
+
+            q_mul(d, pq->e, i);
+            q_nrm(d, d);
+
+            /* Match slerp by using the short path. */
+
+            if (d[0] < 0)
             {
-                w[0] = 0.0f;
-                w[1] = (1.0f / pp->t) * 2 * V_PI;
-                w[2] = 0.0f;
+                d[0] = -d[0];
+                d[1] = -d[1];
+                d[2] = -d[2];
+                d[3] = -d[3];
             }
+
+            q_as_axisangle(d, w, &a);
+            v_scl(w, w, a / pp->t);
+            return;
         }
-        else
-        {
-            w[0] = 0.0f;
-            w[1] = 0.0f;
-            w[2] = 0.0f;
-        }
-    }
-    else
-    {
-        w[0] = 0.0f;
-        w[1] = 0.0f;
-        w[2] = 0.0f;
     }
+
+    w[0] = 0.0f;
+    w[1] = 0.0f;
+    w[2] = 0.0f;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -266,41 +298,22 @@ void sol_body_step(struct s_file *fp, float dt)
 
         if (bp->pi >= 0 && pp->f)
         {
-            if (bp->fl & P_ROTATING)
-            {
-                float d[4], e[4], w[3];
-
-                sol_body_w(w, fp, bp);
-
-                q_by_axisangle(d, w, v_len(w) * dt);
-
-                q_mul(e, bp->e, d);
-                q_nrm(bp->e, e);
+            bp->t = (t += dt);
 
-                cmd.type          = CMD_BODY_ORIENTATION;
-                cmd.bodyorient.bi = i;
-                q_cpy(cmd.bodyorient.e, bp->e);
-                sol_cmd_enq(&cmd);
-            }
-            else
+            if (t >= pp->t)
             {
-                bp->t = (t += dt);
-
-                if (t >= pp->t)
-                {
-                    bp->t  = 0;
-                    bp->pi = pp->pi;
+                bp->t  = 0;
+                bp->pi = pp->pi;
 
-                    cmd.type        = CMD_BODY_TIME;
-                    cmd.bodytime.bi = i;
-                    cmd.bodytime.t  = bp->t;
-                    sol_cmd_enq(&cmd);
+                cmd.type        = CMD_BODY_TIME;
+                cmd.bodytime.bi = i;
+                cmd.bodytime.t  = bp->t;
+                sol_cmd_enq(&cmd);
 
-                    cmd.type        = CMD_BODY_PATH;
-                    cmd.bodypath.bi = i;
-                    cmd.bodypath.pi = bp->pi;
-                    sol_cmd_enq(&cmd);
-                }
+                cmd.type        = CMD_BODY_PATH;
+                cmd.bodypath.bi = i;
+                cmd.bodypath.pi = bp->pi;
+                sol_cmd_enq(&cmd);
             }
         }
     }
index 0f2e871..3784385 100644 (file)
@@ -5,6 +5,7 @@
 
 void sol_body_p(float p[3], const struct s_file *fp, int pi, float t);
 void sol_body_v(float v[3], const struct s_file *fp, int pi, float t, float dt);
+void sol_body_e(float e[3], const struct s_file *fp, const struct s_body *bp);
 void sol_body_w(float w[3], const struct s_file *fp, const struct s_body *bp);
 
 void sol_rotate(float e[3][3], const float w[3], float dt);
index 5ab85b7..59ba367 100644 (file)
@@ -348,11 +348,12 @@ static const struct s_mtrl *sol_draw_body(const struct s_file *fp,
 static void sol_draw_list(const struct s_file *fp,
                           const struct s_body *bp, GLuint list)
 {
-    float p[3], u[3], a;
+    float p[3], e[4], u[3], a;
 
     sol_body_p(p, fp, bp->pi, bp->t);
+    sol_body_e(e, fp, bp);
 
-    q_as_axisangle(bp->e, u, &a);
+    q_as_axisangle(e, u, &a);
     a = V_DEG(a);
 
     glPushMatrix();
@@ -512,11 +513,12 @@ static void sol_shad_body(const struct s_file *fp,
 static void sol_shad_list(const struct s_file *fp,
                           const struct s_body *bp, GLuint list)
 {
-    float p[3], u[3], a;
+    float p[3], e[4], u[3], a;
 
     sol_body_p(p, fp, bp->pi, bp->t);
+    sol_body_e(e, fp, bp);
 
-    q_as_axisangle(bp->e, u, &a);
+    q_as_axisangle(e, u, &a);
     a = V_DEG(a);
 
     glPushMatrix();
index 4f90711..50fead0 100644 (file)
@@ -515,12 +515,13 @@ static float sol_test_body(float dt,
                            const struct s_file *fp,
                            const struct s_body *bp)
 {
-    float U[3], O[3], W[3], A[3], u, t = dt;
+    float U[3], O[3], E[4], W[3], A[3], u, t = dt;
 
     const struct s_node *np = fp->nv + bp->ni;
 
     sol_body_p(O, fp, bp->pi, bp->t);
     sol_body_v(W, fp, bp->pi, bp->t, dt);
+    sol_body_e(E, fp, bp);
     sol_body_w(A, fp, bp);
 
     /*
@@ -534,15 +535,17 @@ static float sol_test_body(float dt,
      * v = w x p
      */
 
-    if (bp->fl & P_ROTATING)
+    if (E[0] != 1.0f || v_dot(A, A))
     {
+        /* The body has a non-identity orientation or it is rotating. */
+
         struct s_ball ball = *up;
         float e[4], w[3], v[3];
 
-        e[0] =  bp->e[0];
-        e[1] = -bp->e[1];
-        e[2] = -bp->e[2];
-        e[3] = -bp->e[3];
+        e[0] =  E[0];
+        e[1] = -E[1];
+        e[2] = -E[2];
+        e[3] = -E[3];
 
         w[0] = -A[0];
         w[1] = -A[1];
@@ -555,7 +558,8 @@ static float sol_test_body(float dt,
 
         /* Transform velocity. */
 
-        q_rot(ball.v, e, up->v);
+        v_sub(v, up->v, W);
+        q_rot(ball.v, e, v);
 
         /* Also add the velocity from rotation. */
 
@@ -577,12 +581,16 @@ static float sol_test_body(float dt,
             float d[4];
 
             q_by_axisangle(d, A, v_len(A) * u);
-            q_mul(e, bp->e, d);
+            q_mul(e, E, d);
             q_nrm(e, e);
 
             q_rot(T, e, U);
+
             v_crs(V, A, T);
+            v_add(V, V, W);
+
             v_add(T, O, T);
+            v_mad(O, T, W, u);
 
             t = u;
         }