Decouple world rotations from view basis
authorparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Fri, 10 Jul 2009 11:17:25 +0000 (11:17 +0000)
committerparasti <parasti@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Fri, 10 Jul 2009 11:17:25 +0000 (11:17 +0000)
Rather than rotate world directly around the view axes, in this patch
suitable tilt axes are computed from the view basis, which are then
used for gravity computation and visual rotations.  This should
prevent arbitrary view basis from interfering with tilting.

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

ball/game_client.c
ball/game_common.c
ball/game_common.h
ball/game_server.c
share/cmd.c
share/cmd.h

index 1243535..db78cc9 100644 (file)
@@ -52,8 +52,7 @@ static float timer      = 0.f;          /* Clock time                        */
 
 static int status = GAME_NONE;          /* Outcome of the game               */
 
-static float game_rx;                   /* Floor rotation about X axis       */
-static float game_rz;                   /* Floor rotation about Z axis       */
+static struct game_tilt tilt;           /* Floor rotation                    */
 
 static float view_a;                    /* Ideal view rotation about Y axis  */
 static float view_fov;                  /* Field of view                     */
@@ -89,6 +88,14 @@ static void game_run_cmd(const union cmd *cmd)
     static const float gup[] = { 0.0f, +9.8f, 0.0f };
     static const float gdn[] = { 0.0f, -9.8f, 0.0f };
 
+    /*
+     * Neverball <= 1.5.1 does not send explicit tilt axes, rotation
+     * happens directly around view vectors.  So for compatibility if
+     * at the time of receiving tilt angles we have not yet received
+     * the tilt axes, we use the view vectors.
+     */
+    static int got_tilt_axes;
+
     float f[3];
 
     if (client_state)
@@ -102,6 +109,9 @@ static void game_run_cmd(const union cmd *cmd)
         switch (cmd->type)
         {
         case CMD_END_OF_UPDATE:
+
+            got_tilt_axes = 0;
+
             if (first_update)
             {
                 first_update = 0;
@@ -111,9 +121,9 @@ static void game_run_cmd(const union cmd *cmd)
             /* Compute gravity for particle effects. */
 
             if (status == GAME_GOAL)
-                game_comp_grav(f, gup, view_a, game_rx, game_rz);
+                game_comp_grav(f, gup, &tilt);
             else
-                game_comp_grav(f, gdn, view_a, game_rx, game_rz);
+                game_comp_grav(f, gdn, &tilt);
 
             /* Step particle, goal and jump effects. */
 
@@ -182,8 +192,11 @@ static void game_run_cmd(const union cmd *cmd)
             break;
 
         case CMD_TILT_ANGLES:
-            game_rx = cmd->tiltangles.x;
-            game_rz = cmd->tiltangles.z;
+            if (!got_tilt_axes)
+                game_tilt_axes(&tilt, view_e);
+
+            tilt.rx = cmd->tiltangles.x;
+            tilt.rz = cmd->tiltangles.z;
             break;
 
         case CMD_SOUND:
@@ -368,6 +381,12 @@ static void game_run_cmd(const union cmd *cmd)
             game_compat_map = version.x == cmd->map.version.x;
             break;
 
+        case CMD_TILT_AXES:
+            got_tilt_axes = 1;
+            v_cpy(tilt.x, cmd->tiltaxes.x);
+            v_cpy(tilt.z, cmd->tiltaxes.z);
+            break;
+
         case CMD_NONE:
         case CMD_MAX:
             break;
@@ -417,8 +436,7 @@ int  game_client_init(const char *file_name)
 
     client_state = 1;
 
-    game_rx = 0.0f;
-    game_rz = 0.0f;
+    game_tilt_init(&tilt);
 
     /* Initialize jump and goal states. */
 
@@ -712,21 +730,11 @@ static void game_draw_tilt(int d)
 {
     const float *ball_p = file.uv->p;
 
-    const float Y[3] = { 0.0f, 1.0f, 0.0f };
-    float z[3];
-
-    v_cpy(z, view_e[2]);
-
-    /* Handle possible top-down view. */
-
-    if (fabsf(v_dot(view_e[1], Y)) < fabsf(v_dot(view_e[2], Y)))
-        v_inv(z, view_e[1]);
-
     /* Rotate the environment about the position of the ball. */
 
     glTranslatef(+ball_p[0], +ball_p[1] * d, +ball_p[2]);
-    glRotatef(-game_rz * d, z[0],         z[1],         z[2]);
-    glRotatef(-game_rx * d, view_e[0][0], view_e[0][1], view_e[0][2]);
+    glRotatef(-tilt.rz * d, tilt.z[0], tilt.z[1], tilt.z[2]);
+    glRotatef(-tilt.rx * d, tilt.x[0], tilt.x[1], tilt.x[2]);
     glTranslatef(-ball_p[0], -ball_p[1] * d, -ball_p[2]);
 }
 
@@ -778,8 +786,8 @@ static void game_draw_back(int pose, int d, float t)
     {
         if (d < 0)
         {
-            glRotatef(game_rz * 2, view_e[2][0], view_e[2][1], view_e[2][2]);
-            glRotatef(game_rx * 2, view_e[0][0], view_e[0][1], view_e[0][2]);
+            glRotatef(tilt.rz * 2, tilt.z[0], tilt.z[1], tilt.z[2]);
+            glRotatef(tilt.rx * 2, tilt.x[0], tilt.x[1], tilt.x[2]);
         }
 
         glTranslatef(view_p[0], view_p[1] * d, view_p[2]);
index 8ea0c83..a27e5ef 100644 (file)
@@ -25,31 +25,51 @@ const char *view_to_str(int v)
     }
 }
 
-void game_comp_grav(float h[3], const float g[3],
-                    float view_a,
-                    float game_rx,
-                    float game_rz)
+/*---------------------------------------------------------------------------*/
+
+void game_tilt_init(struct game_tilt *tilt)
+{
+    tilt->x[0] = 1.0f;
+    tilt->x[1] = 0.0f;
+    tilt->x[2] = 0.0f;
+
+    tilt->rx = 0.0f;
+
+    tilt->z[0] = 0.0f;
+    tilt->z[1] = 0.0f;
+    tilt->z[2] = 1.0f;
+
+    tilt->rz = 0.0f;
+}
+
+/*
+ * Compute appropriate tilt axes from the view basis.
+ */
+void game_tilt_axes(struct game_tilt *tilt, float view_e[3][3])
+{
+    const float Y[3] = { 0.0f, 1.0f, 0.0f };
+
+    v_cpy(tilt->x, view_e[0]);
+    v_cpy(tilt->z, view_e[2]);
+
+    /* Handle possible top-down view. */
+
+    if (fabsf(v_dot(view_e[1], Y)) < fabsf(v_dot(view_e[2], Y)))
+        v_inv(tilt->z, view_e[1]);
+}
+
+void game_comp_grav(float h[3], const float g[3], const struct game_tilt *tilt)
 {
-    float x[3];
-    float y[3] = { 0.0f, 1.0f, 0.0f };
-    float z[3];
     float X[16];
     float Z[16];
     float M[16];
 
     /* Compute the gravity vector from the given world rotations. */
 
-    z[0] = fsinf(V_RAD(view_a));
-    z[1] = 0.0f;
-    z[2] = fcosf(V_RAD(view_a));
-
-    v_crs(x, y, z);
-    v_crs(z, x, y);
-    v_nrm(x, x);
-    v_nrm(z, z);
-
-    m_rot (Z, z, V_RAD(game_rz));
-    m_rot (X, x, V_RAD(game_rx));
+    m_rot (Z, tilt->z, V_RAD(tilt->rz));
+    m_rot (X, tilt->x, V_RAD(tilt->rx));
     m_mult(M, Z, X);
     m_vxfm(h, M, g);
 }
+
+/*---------------------------------------------------------------------------*/
index 90c14c2..d0254da 100644 (file)
@@ -54,10 +54,15 @@ const char *view_to_str(int);
 
 /*---------------------------------------------------------------------------*/
 
-void game_comp_grav(float h[3], const float g[3],
-                    float view_a,
-                    float game_rx,
-                    float game_rz);
+struct game_tilt
+{
+    float x[3], rx;
+    float z[3], rz;
+};
+
+void game_tilt_init(struct game_tilt *);
+void game_tilt_axes(struct game_tilt *, float view_e[3][3]);
+void game_comp_grav(float h[3], const float g[3], const struct game_tilt *);
 
 /*---------------------------------------------------------------------------*/
 
index acc7e85..a2b1ad3 100644 (file)
@@ -40,8 +40,7 @@ static int   timer_down = 1;            /* Timer go up or down?              */
 
 static int status = GAME_NONE;          /* Outcome of the game               */
 
-static float game_rx;                   /* Floor rotation about X axis       */
-static float game_rz;                   /* Floor rotation about Z axis       */
+static struct game_tilt tilt;           /* Floor rotation                    */
 
 static float view_a;                    /* Ideal view rotation about Y axis  */
 static float view_dc;                   /* Ideal view distance above ball    */
@@ -315,8 +314,18 @@ static void game_cmd_tiltangles(void)
 {
     cmd.type = CMD_TILT_ANGLES;
 
-    cmd.tiltangles.x = game_rx;
-    cmd.tiltangles.z = game_rz;
+    cmd.tiltangles.x = tilt.rx;
+    cmd.tiltangles.z = tilt.rz;
+
+    game_proxy_enq(&cmd);
+}
+
+static void game_cmd_tiltaxes(void)
+{
+    cmd.type = CMD_TILT_AXES;
+
+    v_cpy(cmd.tiltaxes.x, tilt.x);
+    v_cpy(cmd.tiltaxes.z, tilt.z);
 
     game_proxy_enq(&cmd);
 }
@@ -514,8 +523,7 @@ int game_server_init(const char *file_name, int t, int e)
 
     input_init();
 
-    game_rx = 0.0f;
-    game_rz = 0.0f;
+    game_tilt_init(&tilt);
 
     /* Initialize jump and goal states. */
 
@@ -784,14 +792,17 @@ static int game_step(const float g[3], float dt, int bt)
 
         /* Smooth jittery or discontinuous input. */
 
-        game_rx += (input_get_x() - game_rx) * dt / RESPONSE;
-        game_rz += (input_get_z() - game_rz) * dt / RESPONSE;
+        tilt.rx += (input_get_x() - tilt.rx) * dt / RESPONSE;
+        tilt.rz += (input_get_z() - tilt.rz) * dt / RESPONSE;
+
+        game_tilt_axes(&tilt, view_e);
 
+        game_cmd_tiltaxes();
         game_cmd_tiltangles();
 
         grow_step(fp, dt);
 
-        game_comp_grav(h, g, view_a, game_rx, game_rz);
+        game_comp_grav(h, g, &tilt);
 
         if (jump_b)
         {
index 7517cda..59fc262 100644 (file)
@@ -572,6 +572,25 @@ END_FUNC;
 
 /*---------------------------------------------------------------------------*/
 
+#undef BYTES
+#define BYTES ARRAY_BYTES(3) * 2
+
+PUT_FUNC(CMD_TILT_AXES)
+{
+    put_array(fp, cmd->tiltaxes.x, 3);
+    put_array(fp, cmd->tiltaxes.z, 3);
+}
+END_FUNC;
+
+GET_FUNC(CMD_TILT_AXES)
+{
+    get_array(fp, cmd->tiltaxes.x, 3);
+    get_array(fp, cmd->tiltaxes.z, 3);
+}
+END_FUNC;
+
+/*---------------------------------------------------------------------------*/
+
 #define PUT_CASE(t) case t: cmd_put_ ## t(fp, cmd); break
 #define GET_CASE(t) case t: cmd_get_ ## t(fp, cmd); break
 
@@ -617,6 +636,7 @@ int cmd_put(fs_file fp, const union cmd *cmd)
         PUT_CASE(CMD_PATH_FLAG);
         PUT_CASE(CMD_STEP_SIMULATION);
         PUT_CASE(CMD_MAP);
+        PUT_CASE(CMD_TILT_AXES);
 
     case CMD_NONE:
     case CMD_MAX:
@@ -681,6 +701,7 @@ int cmd_get(fs_file fp, union cmd *cmd)
             GET_CASE(CMD_PATH_FLAG);
             GET_CASE(CMD_STEP_SIMULATION);
             GET_CASE(CMD_MAP);
+            GET_CASE(CMD_TILT_AXES);
 
         case CMD_NONE:
         case CMD_MAX:
index 136145e..cfd4812 100644 (file)
@@ -64,6 +64,7 @@ enum cmd_type
     CMD_PATH_FLAG,
     CMD_STEP_SIMULATION,
     CMD_MAP,
+    CMD_TILT_AXES,
 
     CMD_MAX
 };
@@ -268,6 +269,12 @@ struct cmd_map
     } version;
 };
 
+struct cmd_tilt_axes
+{
+    HEADER;
+    float x[3], z[3];
+};
+
 union cmd
 {
     HEADER;
@@ -302,6 +309,7 @@ union cmd
     struct cmd_path_flag          pathflag;
     struct cmd_step_simulation    stepsim;
     struct cmd_map                map;
+    struct cmd_tilt_axes          tiltaxes;
 };
 
 /* No module should see this. */