Merged lockstep branch.
authorroot <root@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Tue, 1 Jan 2008 15:57:08 +0000 (15:57 +0000)
committerroot <root@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Tue, 1 Jan 2008 15:57:08 +0000 (15:57 +0000)
git-svn-id: https://s.snth.net/svn/neverball/trunk@1351 78b8d119-cf0a-0410-b17c-f493084dd1d7

26 files changed:
Makefile
ball/demo.c
ball/demo.h
ball/game.c
ball/game.h
ball/hud.c
ball/main.c
ball/st_demo.c
ball/st_fall_out.c
ball/st_goal.c
ball/st_help.c
ball/st_play.c
ball/st_title.c
scripts/neverball.nsi
share/base_config.h
share/binary.c
share/binary.h
share/config.c
share/config.h
share/part.c
share/sync.c [new file with mode: 0644]
share/sync.h [new file with mode: 0644]
tools/Makefile
tools/README [deleted file]
tools/convert-replays.bat [deleted file]
tools/src/democonv.c [deleted file]

index 36980a9..ff99150 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -119,6 +119,7 @@ BALL_OBJS := \
        share/state.o       \
        share/audio.o       \
        share/text.o        \
+       share/sync.o        \
        ball/hud.o          \
        ball/mode.o         \
        ball/game.o         \
@@ -164,6 +165,7 @@ PUTT_OBJS := \
        share/state.o       \
        share/gui.o         \
        share/text.o        \
+       share/sync.o        \
        putt/hud.o          \
        putt/game.o         \
        putt/hole.o         \
index 9368943..2903b7f 100644 (file)
@@ -28,7 +28,7 @@
 /*---------------------------------------------------------------------------*/
 
 #define MAGIC           0x52424EAF
-#define DEMO_VERSION    4
+#define DEMO_VERSION    5
 
 #define DATELEN 20
 
@@ -370,13 +370,10 @@ int demo_play_init(const char *name,
     return 0;
 }
 
-void demo_play_step(float dt)
+void demo_play_step()
 {
     if (demo_fp)
-    {
-        put_float(demo_fp, &dt);
-        put_game_state(demo_fp);
-    }
+        input_put(demo_fp);
 }
 
 void demo_play_stat(const struct level_game *lg)
@@ -471,11 +468,11 @@ int demo_replay_init(const char *name, struct level_game *lg)
 
         if (lg)
         {
-            lg->mode = demo_replay.mode;
+            lg->mode  = demo_replay.mode;
             lg->score = demo_replay.score;
             lg->times = demo_replay.times;
-            lg->time = demo_replay.time;
-            lg->goal = demo_replay.goal;
+            lg->time  = demo_replay.time;
+            lg->goal  = demo_replay.goal;
 
             /* A normal replay demo */
             audio_music_fade_to(0.5f, demo_level_replay.song);
@@ -488,27 +485,28 @@ int demo_replay_init(const char *name, struct level_game *lg)
     return 0;
 }
 
-int demo_replay_step(float *dt)
+int demo_replay_step(float dt)
 {
-    const float g[3] = { 0.0f, -9.8f, 0.0f };
+    const float gdn[3] = { 0.0f, -9.8f, 0.0f };
+    const float gup[3] = { 0.0f, +9.8f, 0.0f };
 
     if (demo_fp)
     {
-        get_float(demo_fp, dt);
-
-        if (feof(demo_fp) == 0)
+        if (input_get(demo_fp))
         {
-            /* Play out current game state for particles, clock, etc. */
-
-            if (demo_status == GAME_NONE)
-                demo_status = game_step(g, *dt, 1);
-            else
-                game_step(g, *dt, 0);
-
-            /* Load real current game state from file. */
-
-            if (get_game_state(demo_fp))
-                return 1;
+            /* Play out current game state. */
+
+            switch (demo_status)
+            {
+            case GAME_NONE:
+                demo_status = game_step(gdn, dt, 1); break;
+            case GAME_GOAL:
+                (void)        game_step(gup, dt, 0); break;
+            default:
+                (void)        game_step(gdn, dt, 0); break;
+            }
+
+            return 1;
         }
     }
     return 0;
index 762e2c0..ee7ee1f 100644 (file)
@@ -47,7 +47,7 @@ void demo_unique(char *);
 
 int  demo_play_init(const char *, const struct level *,
                     const struct level_game *);
-void demo_play_step(float);
+void demo_play_step(void);
 void demo_play_stat(const struct level_game *);
 void demo_play_stop(void);
 
@@ -57,7 +57,7 @@ void demo_rename(const char *);
 /*---------------------------------------------------------------------------*/
 
 int  demo_replay_init(const char *, struct level_game *);
-int  demo_replay_step(float *);
+int  demo_replay_step(float);
 void demo_replay_stop(int);
 void demo_replay_dump_info(void);
 
index bca262f..8e1d452 100644 (file)
@@ -38,13 +38,10 @@ static struct s_file back;
 static float clock      = 0.f;          /* Clock time                        */
 static int   clock_down = 1;            /* Clock go up or down?              */
 
-static float game_ix;                   /* Input rotation about X axis       */
-static float game_iz;                   /* Input rotation about Z axis       */
 static float game_rx;                   /* Floor rotation about X axis       */
 static float game_rz;                   /* Floor rotation about Z axis       */
 
 static float view_a;                    /* Ideal view rotation about Y axis  */
-static float view_ry;                   /* Angular velocity about Y axis     */
 static float view_dc;                   /* Ideal view distance above ball    */
 static float view_dp;                   /* Ideal view distance above ball    */
 static float view_dz;                   /* Ideal view distance behind ball   */
@@ -68,6 +65,119 @@ static float fade_d = 0.0;              /* Fade in/out direction             */
 
 /*---------------------------------------------------------------------------*/
 
+/*
+ * This is an abstraction of the game's input state.  All input is
+ * encapsulated here, and all references to the input by the game are made
+ * here.  This has the effect of homogenizing input for use in replay
+ * recording and playback.
+ *
+ * x and z:
+ *     -32767 = -ANGLE_BOUND
+ *     +32767 = +ANGLE_BOUND
+ *
+ * r:
+ *     -32767 = -VIEWR_BOUND
+ *     +32767 = +VIEWR_BOUND
+ *     
+ */
+
+struct input
+{
+    short x;
+    short z;
+    short r;
+    short c;
+};
+
+static struct input input_current;
+
+static void input_init(void)
+{
+    input_current.x = 0;
+    input_current.z = 0;
+    input_current.r = 0;
+    input_current.c = 0;
+}
+
+static void input_set_x(float x)
+{
+    if (x < -ANGLE_BOUND) x = -ANGLE_BOUND;
+    if (x >  ANGLE_BOUND) x =  ANGLE_BOUND;
+
+    input_current.x = (short) (32767.0f * x / ANGLE_BOUND);
+}
+
+static void input_set_z(float z)
+{
+    if (z < -ANGLE_BOUND) z = -ANGLE_BOUND;
+    if (z >  ANGLE_BOUND) z =  ANGLE_BOUND;
+
+    input_current.z = (short) (32767.0f * z / ANGLE_BOUND);
+}
+
+static void input_set_r(float r)
+{
+    if (r < -VIEWR_BOUND) r = -VIEWR_BOUND;
+    if (r >  VIEWR_BOUND) r =  VIEWR_BOUND;
+
+    input_current.r = (short) (32767.0f * r / VIEWR_BOUND);
+}
+
+static void input_set_c(int c)
+{
+    input_current.c = (short) c;
+}
+
+static float input_get_x(void)
+{
+    return ANGLE_BOUND * (float) input_current.x / 32767.0f;
+}
+
+static float input_get_z(void)
+{
+    return ANGLE_BOUND * (float) input_current.z / 32767.0f;
+}
+
+static float input_get_r(void)
+{
+    return VIEWR_BOUND * (float) input_current.r / 32767.0f;
+}
+
+static int input_get_c(void)
+{
+    return (int) input_current.c;
+}
+
+int input_put(FILE *fout)
+{
+    if (game_state)
+    {
+        put_short(fout, &input_current.x);
+        put_short(fout, &input_current.z);
+        put_short(fout, &input_current.r);
+        put_short(fout, &input_current.c);
+        
+        return 1;
+    }
+    return 0;
+}
+
+int input_get(FILE *fin)
+{
+    if (game_state)
+    {
+        get_short(fin, &input_current.x);
+        get_short(fin, &input_current.z);
+        get_short(fin, &input_current.r);
+        get_short(fin, &input_current.c);
+
+        return (feof(fin) ? 0 : 1);
+    }
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
 static int   grow = 0;                  /* Should the ball be changing size? */
 static float grow_orig = 0;             /* the original ball size            */
 static float grow_goal = 0;             /* how big or small to get!          */
@@ -175,14 +285,12 @@ static void grow_step(const struct s_file *fp, float dt)
 
 static void view_init(void)
 {
-    view_a  = 0.f;
-    view_ry = 0.f;
-
     view_fov = (float) config_get_d(CONFIG_VIEW_FOV);
     view_dp  = (float) config_get_d(CONFIG_VIEW_DP) / 100.0f;
     view_dc  = (float) config_get_d(CONFIG_VIEW_DC) / 100.0f;
     view_dz  = (float) config_get_d(CONFIG_VIEW_DZ) / 100.0f;
     view_k   = 1.0f;
+    view_a   = 0.0f;
 
     view_c[0] = 0.f;
     view_c[1] = view_dc;
@@ -219,10 +327,10 @@ int game_init(const struct level *level, int t, int g)
 
     game_state = 1;
 
-    game_ix = 0.f;
-    game_iz = 0.f;
-    game_rx = 0.f;
-    game_rz = 0.f;
+    input_init();
+
+    game_rx = 0.0f;
+    game_rz = 0.0f;
 
     /* Initialize jump and goal states. */
 
@@ -721,8 +829,6 @@ void game_draw(int pose, float st)
 
 static void game_update_grav(float h[3], const float g[3])
 {
-    struct s_file *fp = &file;
-
     float x[3];
     float y[3] = { 0.f, 1.f, 0.f };
     float z[3];
@@ -732,7 +838,10 @@ static void game_update_grav(float h[3], const float g[3])
 
     /* Compute the gravity vector from the given world rotations. */
 
-    v_sub(z, view_p, fp->uv->p);
+    z[0] = fsinf(V_RAD(view_a));
+    z[1] = 0.0;
+    z[2] = fcosf(V_RAD(view_a));
+
     v_crs(x, y, z);
     v_crs(z, x, y);
     v_nrm(x, x);
@@ -747,39 +856,37 @@ static void game_update_grav(float h[3], const float g[3])
 static void game_update_view(float dt)
 {
     float dc = view_dc * (jump_b ? 2.0f * fabsf(jump_dt - 0.5f) : 1.0f);
-    float dx = view_ry * dt * 5.0f;
+    float da = input_get_r() * dt * 90.0f;
     float k;
 
-    view_a += view_ry * dt * 90.f;
+    float M[16], v[3], Y[3] = { 0.0f, 1.0f, 0.0f };
+
+    view_a += da;
 
     /* Center the view about the ball. */
 
     v_cpy(view_c, file.uv->p);
     v_inv(view_v, file.uv->v);
 
-    switch (config_get_d(CONFIG_CAMERA))
+    view_e[2][0] = fsinf(V_RAD(view_a));
+    view_e[2][1] = 0.0;
+    view_e[2][2] = fcosf(V_RAD(view_a));
+
+    switch (input_get_c())
     {
-    case 1: /* Camera 1:  Viewpoint chases the ball position. */
+    case 1: /* Camera 1: Viewpoint chases the ball position. */
+
+        /* TODO: This camera no longer exists. */
 
-        v_sub(view_e[2], view_p, view_c);
         break;
 
     case 2: /* Camera 2: View vector is given by view angle. */
 
-        view_e[2][0] = fsinf(V_RAD(view_a));
-        view_e[2][1] = 0.f;
-        view_e[2][2] = fcosf(V_RAD(view_a));
-
-        dx = 0.0f;
-
         break;
 
     default: /* Default: View vector approaches the ball velocity vector. */
 
-        k = v_dot(view_v, view_v);
-
-        v_sub(view_e[2], view_p, view_c);
-        v_mad(view_e[2], view_e[2], view_v, k * dt / 4);
+        v_mad(view_e[2], view_e[2], view_v, v_dot(view_v, view_v) * dt / 4);
 
         break;
     }
@@ -799,10 +906,11 @@ static void game_update_view(float dt)
 
     if (view_k < 0.5) view_k = 0.5;
 
-    v_cpy(view_p, file.uv->p);
-    v_mad(view_p, view_p, view_e[0], dx      * view_k);
-    v_mad(view_p, view_p, view_e[1], view_dp * view_k);
-    v_mad(view_p, view_p, view_e[2], view_dz * view_k);
+    v_scl(v,    view_e[1], view_dp * view_k);
+    v_mad(v, v, view_e[2], view_dz * view_k);
+    m_rot(M, Y, V_RAD(da));
+    m_vxfm(view_p, M, v);
+    v_add(view_p, view_p, file.uv->p);
 
     /* Compute the new view center. */
 
@@ -844,6 +952,7 @@ static int game_update_state(int bt)
     float c[3];
 
     /* Test for an item. */
+
     if (bt && (hp = sol_item_test(fp, p, COIN_RADIUS)))
     {
         const char *sound = AUD_COIN;
@@ -858,6 +967,7 @@ static int game_update_state(int bt)
             coins += hp->n;
 
             /* Check for goal open. */
+
             if (goal_c > 0)
             {
                 goal_c -= hp->n;
@@ -871,10 +981,12 @@ static int game_update_state(int bt)
         audio_play(sound, 1.f);
 
         /* Reset item type. */
+
         hp->t = ITEM_NONE;
     }
 
     /* Test for a switch. */
+
     if (sol_swch_test(fp, 0))
         audio_play(AUD_SWITCH, 1.f);
 
@@ -918,85 +1030,48 @@ static int game_update_state(int bt)
     return GAME_NONE;
 }
 
-/*
- * On  most  hardware, rendering  requires  much  more  computing power  than
- * physics.  Since  physics takes less time  than graphics, it  make sense to
- * detach  the physics update  time step  from the  graphics frame  rate.  By
- * performing multiple physics updates for  each graphics update, we get away
- * with higher quality physics with little impact on overall performance.
- *
- * Toward this  end, we establish a  baseline maximum physics  time step.  If
- * the measured  frame time  exceeds this  maximum, we cut  the time  step in
- * half, and  do two updates.  If THIS  time step exceeds the  maximum, we do
- * four updates.  And  so on.  In this way, the physics  system is allowed to
- * seek an optimal update rate independent of, yet in integral sync with, the
- * graphics frame rate.
- */
-
 int game_step(const float g[3], float dt, int bt)
 {
-    struct s_file *fp = &file;
-
-    float h[3];
-    float d = 0.f;
-    float b = 0.f;
-    float t;
-    int i, n = 1;
-
     if (game_state)
     {
-        t = dt;
+        struct s_file *fp = &file;
+
+        float h[3];
 
         /* Smooth jittery or discontinuous input. */
 
-        if (t < RESPONSE)
-        {
-            game_rx += (game_ix - game_rx) * t / RESPONSE;
-            game_rz += (game_iz - game_rz) * t / RESPONSE;
-        }
-        else
-        {
-            game_rx = game_ix;
-            game_rz = game_iz;
-        }
+        game_rx += (input_get_x() - game_rx) * dt / RESPONSE;
+        game_rz += (input_get_z() - game_rz) * dt / RESPONSE;
 
         grow_step(fp, dt);
 
         game_update_grav(h, g);
-        part_step(h, t);
+        part_step(h, dt);
 
         if (jump_b)
         {
-            jump_dt += t;
+            jump_dt += dt;
 
             /* Handle a jump. */
 
-            if (0.5 < jump_dt)
+            if (0.5f < jump_dt)
             {
                 fp->uv[0].p[0] = jump_p[0];
                 fp->uv[0].p[1] = jump_p[1];
                 fp->uv[0].p[2] = jump_p[2];
             }
-            if (1.f < jump_dt)
+            if (1.0f < jump_dt)
                 jump_b = 0;
         }
         else
         {
             /* Run the sim. */
 
-            while (t > MAX_DT && n < MAX_DN)
-            {
-                t /= 2;
-                n *= 2;
-            }
-
-            for (i = 0; i < n; i++)
-                if (b < (d = sol_step(fp, h, t, 0, NULL)))
-                    b = d;
+            float b = sol_step(fp, h, dt, 0, NULL);
 
             /* Mix the sound of a ball bounce. */
 
-            if (b > 0.5)
+            if (b > 0.5f)
             {
                 float k = (b - 0.5f) * 2.0f;
 
@@ -1021,51 +1096,30 @@ int game_step(const float g[3], float dt, int bt)
 
 /*---------------------------------------------------------------------------*/
 
-void game_no_aa(void)
-{
-    float max = game_ix * game_ix + game_iz * game_iz;
-    if (max > ANGLE_BOUND * ANGLE_BOUND)
-    {
-        max = ANGLE_BOUND / sqrt(max);
-        game_ix *= max;
-        game_iz *= max;
-    }
-}
-
 void game_set_x(int k)
 {
-    game_ix = -(ANGLE_BOUND) * k / JOY_MAX;
-#if NO_AA
-    game_no_aa();
-#endif
+    input_set_x(-ANGLE_BOUND * k / JOY_MAX);
 }
 
 void game_set_z(int k)
 {
-    game_iz = +ANGLE_BOUND * k / JOY_MAX;
-#if NO_AA
-    game_no_aa();
-#endif
+    input_set_z(+ANGLE_BOUND * k / JOY_MAX);
 }
 
 void game_set_pos(int x, int y)
 {
-    game_ix += 40.f * y / config_get_d(CONFIG_MOUSE_SENSE);
-    game_iz += 40.f * x / config_get_d(CONFIG_MOUSE_SENSE);
-
-#if NO_AA
-    game_no_aa();
-#else
-    if (game_ix > +ANGLE_BOUND) game_ix = +ANGLE_BOUND;
-    if (game_ix < -ANGLE_BOUND) game_ix = -ANGLE_BOUND;
-    if (game_iz > +ANGLE_BOUND) game_iz = +ANGLE_BOUND;
-    if (game_iz < -ANGLE_BOUND) game_iz = -ANGLE_BOUND;
-#endif
+    input_set_x(input_get_x() + 40.0f * y / config_get_d(CONFIG_MOUSE_SENSE));
+    input_set_z(input_get_z() + 40.0f * x / config_get_d(CONFIG_MOUSE_SENSE));
+}
+
+void game_set_cam(int c)
+{
+    input_set_c(c);
 }
 
 void game_set_rot(float r)
 {
-    view_ry = r;
+    input_set_r(r);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -1174,45 +1228,3 @@ void game_fade(float d)
 }
 
 /*---------------------------------------------------------------------------*/
-
-int put_game_state(FILE *fout)
-{
-    if (game_state)
-    {
-        /* Write the view and tilt state. */
-
-        put_float(fout, &game_rx);
-        put_float(fout, &game_rz);
-        put_array(fout,  view_c, 3);
-        put_array(fout,  view_p, 3);
-
-        /* Write the game simulation state. */
-
-        put_file_state(fout, &file);
-
-        return 1;
-    }
-    return 0;
-}
-
-int get_game_state(FILE *fin)
-{
-    if (game_state)
-    {
-        /* Read the view and tilt state. */
-
-        get_float(fin, &game_rx);
-        get_float(fin, &game_rz);
-        get_array(fin,  view_c, 3);
-        get_array(fin,  view_p, 3);
-
-        /* Read the game simulation state. */
-
-        get_file_state(fin, &file);
-
-        return (feof(fin) ? 0 : 1);
-    }
-    return 0;
-}
-
-/*---------------------------------------------------------------------------*/
index 41b2581..73013fa 100644 (file)
 
 /*---------------------------------------------------------------------------*/
 
-#define MAX_DT      0.01666666         /* Maximum physics update cycle       */
-#define MAX_DN      16                 /* Maximum subdivisions of dt         */
 #define RESPONSE    0.05f              /* Input smoothing time               */
-
-#define ANGLE_BOUND 20.f               /* Angle limit of floor tilting       */
+#define ANGLE_BOUND 20.0f              /* Angle limit of floor tilting       */
+#define VIEWR_BOUND 10.0f              /* Maximum rate of view rotation      */
 #define NO_AA       0                  /* Disable Angle Acceleration         */
 
 /*---------------------------------------------------------------------------*/
@@ -54,6 +52,7 @@ int   game_step(const float[3], float, int);
 void  game_set_pos(int, int);
 void  game_set_x  (int);
 void  game_set_z  (int);
+void  game_set_cam(int);
 void  game_set_rot(float);
 void  game_set_fly(float);
 
@@ -63,8 +62,10 @@ void  game_kill_fade(void);
 void  game_step_fade(float);
 void  game_fade(float);
 
-int   put_game_state(FILE *);
-int   get_game_state(FILE *);
+/*---------------------------------------------------------------------------*/
+
+int input_put(FILE *);
+int input_get(FILE *);
 
 /*---------------------------------------------------------------------------*/
 
index 13da0cd..d218db7 100644 (file)
@@ -43,24 +43,7 @@ static float view_timer;
 
 static void hud_fps(void)
 {
-    static int fps   = 0;
-    static int then  = 0;
-    static int count = 0;
-
-    int now = SDL_GetTicks();
-
-    if (now - then > 250)
-    {
-        if (count && config_get_d(CONFIG_STATS))
-            fprintf(stdout, "%f\n", (float) (now - then) / count);
-
-        fps   = count * 1000 / (now - then);
-        then  = now;
-        count = 0;
-
-        gui_set_count(fps_id, fps);
-    }
-    else count++;
+    gui_set_count(fps_id, config_perf());
 }
 
 void hud_init(void)
index 6eab0d7..67cadff 100644 (file)
@@ -398,19 +398,28 @@ int main(int argc, char *argv[])
     /* Run the main game loop. */
 
     t0 = SDL_GetTicks();
+
     while (loop())
-        if ((t1 = SDL_GetTicks()) > t0)
-        {
-            st_timer((t1 - t0) / 1000.f);
-            st_paint();
-            SDL_GL_SwapBuffers();
+    {
+        t1 = SDL_GetTicks();
 
-            t0 = t1;
+        /* Step the game state at least up to the current time. */
 
-            if (config_get_d(CONFIG_NICE))
-                SDL_Delay(1);
+        while (t1 > t0)
+        {
+            st_timer(DT);
+            t0 += (int) (DT * 1000);
         }
 
+        /* Render. */
+
+        st_paint();
+        config_swap();
+
+        if (config_get_d(CONFIG_NICE))
+            SDL_Delay(1);
+    }
+
     /* Gracefully close the game */
 
     if (SDL_JoystickOpened(0))
index a876053..88a9e41 100644 (file)
@@ -37,9 +37,6 @@
 static int first = 0;
 static int total = 0;
 
-static float replay_time;
-static float global_time;
-
 /*---------------------------------------------------------------------------*/
 
 static int demo_action(int i)
@@ -337,9 +334,6 @@ static int demo_play_enter(void)
         gui_pulse(id, 1.2f);
     }
 
-    global_time = -1.f;
-    replay_time =  0.f;
-
     hud_update(0);
 
     game_set_fly(0.f);
@@ -358,27 +352,17 @@ static void demo_play_paint(int id, float st)
 
 static void demo_play_timer(int id, float dt)
 {
-    float t;
-
     game_step_fade(dt);
     gui_timer(id, dt);
-
-    global_time += dt;
     hud_timer(dt);
 
     /* Spin or skip depending on how fast the demo wants to run. */
 
-    while (replay_time < global_time)
-        if (demo_replay_step(&t))
-        {
-            replay_time += t;
-        }
-        else
-        {
-            demo_paused = 0;
-            goto_state(&st_demo_end);
-            break;
-        }
+    if (!demo_replay_step(dt))
+    {
+        demo_paused = 0;
+        goto_state(&st_demo_end);
+    }
 }
 
 static int demo_play_keybd(int c, int d)
index ec3b177..866b145 100644 (file)
@@ -130,8 +130,8 @@ static void fall_out_timer(int id, float dt)
 
     if (time_state() < 2.f)
     {
+        demo_play_step();
         game_step(g, dt, 0);
-        demo_play_step(dt);
     }
 
     gui_timer(id, dt);
index c636369..2572771 100644 (file)
@@ -239,18 +239,18 @@ static int goal_enter(void)
 
 static void goal_timer(int id, float dt)
 {
-    static float DT = 0.0f;
+    static float t = 0.0f;
 
     float g[3] = { 0.0f, 9.8f, 0.0f };
 
-    DT += dt;
+    t += dt;
 
     if (time_state() < 1.f)
     {
+        demo_play_step();
         game_step(g, dt, 0);
-        demo_play_step(dt);
     }
-    else if (DT > 0.05f && coins_id)
+    else if (t > 0.05f && coins_id)
     {
         int coins = gui_value(coins_id);
 
@@ -272,7 +272,7 @@ static void goal_timer(int id, float dt)
                 audio_play(AUD_BALL, 1.0f);
             }
         }
-        DT = 0.0f;
+        t = 0.0f;
     }
 
     gui_timer(id, dt);
index adb0813..10d0edd 100644 (file)
@@ -374,14 +374,8 @@ static int help_buttn(int b, int d)
 
 /*---------------------------------------------------------------------------*/
 
-static float real_time;
-static float demo_time;
-
 static int help_demo_enter(void)
 {
-    real_time = -1.f;
-    demo_time =  0.f;
-
     game_set_fly(0.f);
 
     return 0;
@@ -399,20 +393,10 @@ static void help_demo_paint(int id, float st)
 
 static void help_demo_timer(int id, float dt)
 {
-    float t;
-
-    real_time += dt;
-
     game_step_fade(dt);
 
-    while (demo_time < real_time)
-        if (demo_replay_step(&t))
-            demo_time += t;
-        else
-        {
-            goto_state(&st_help);
-            break;
-        }
+    if (!demo_replay_step(dt))
+        goto_state(&st_help);
 }
 
 static int help_demo_buttn(int b, int d)
index 6c2c212..2c3bd7d 100644 (file)
@@ -212,20 +212,20 @@ static void play_loop_paint(int id, float st)
 static void play_loop_timer(int id, float dt)
 {
     float k = ((SDL_GetModState() & KMOD_SHIFT) ?
-               (float) config_get_d(CONFIG_ROTATE_FAST) / 100.f:
-               (float) config_get_d(CONFIG_ROTATE_SLOW) / 100.f);
-
-    static float at = 0;
+               (float) config_get_d(CONFIG_ROTATE_FAST) / 100.0f :
+               (float) config_get_d(CONFIG_ROTATE_SLOW) / 100.0f);
 
     float g[3] = { 0.0f, -9.8f, 0.0f };
 
-    at = (7 * at + dt) / 8;
-
-    gui_timer(id, at);
-    hud_timer(at);
+    gui_timer(id, dt);
+    hud_timer(dt);
     game_set_rot(view_rotate * k);
+    game_set_cam(config_get_d(CONFIG_CAMERA));
 
-    switch (game_step(g, at, 1))
+    game_step_fade(dt);
+    demo_play_step();
+
+    switch (game_step(g, dt, 1))
     {
     case GAME_GOAL:
         level_stat(GAME_GOAL, curr_clock(), curr_coins());
@@ -248,9 +248,6 @@ static void play_loop_timer(int id, float dt)
     default:
         break;
     }
-
-    game_step_fade(dt);
-    demo_play_step(at);
 }
 
 static void play_loop_point(int id, int x, int y, int dx, int dy)
index 0473f3b..779e4fb 100644 (file)
@@ -30,7 +30,6 @@
 /*---------------------------------------------------------------------------*/
 
 static float real_time = 0.0f;
-static float demo_time = 0.0f;
 static int   mode      = 0;
 
 static int play_id = 0;
@@ -156,7 +155,6 @@ static int title_enter(void)
     game_init(&title_level, 0, 0);
 
     real_time = 0.0f;
-    demo_time = 0.0f;
     mode = 0;
 
     SDL_EnableUNICODE(1);
@@ -174,7 +172,6 @@ static void title_leave(int id)
 static void title_timer(int id, float dt)
 {
     static const char *demo = NULL;
-    float t;
 
     real_time += dt;
 
@@ -199,7 +196,7 @@ static void title_timer(int id, float dt)
             if ((demo = demo_pick()))
             {
                 demo_replay_init(demo, NULL);
-                demo_time = 0.0f;
+                game_set_fly(0.0f);
                 real_time = 0.0f;
                 mode = 2;
             }
@@ -214,16 +211,13 @@ static void title_timer(int id, float dt)
 
     case 2: /* Mode 2: Run demo. */
 
-        while (demo_time < real_time)
-            if (demo_replay_step(&t))
-                demo_time += t;
-            else
-            {
-                demo_replay_stop(0);
-                game_fade(+1.0f);
-                real_time = 0.0f;
-                mode = 3;
-            }
+        if (!demo_replay_step(dt))
+        {
+            demo_replay_stop(0);
+            game_fade(+1.0f);
+            real_time = 0.0f;
+            mode = 3;
+        }
         break;
 
     case 3: /* Mode 3: Fade out.  Load title level. */
index 2f7da71..8381b1c 100644 (file)
@@ -62,8 +62,6 @@ Section "Neverball/Neverputt"
 
     File scripts\neverball.bat
     File scripts\neverputt.bat
-    File tools\democonv.exe
-    File tools\convert-replays.bat
 
     # http://nsis.sourceforge.net/\
     # Add_uninstall_information_to_Add/Remove_Programs
index c69e186..1b3db18 100644 (file)
 #define MAXNAM 9
 
 #define GUI_FACE                    _("ttf/DejaVuSans-Bold.ttf")
+/*
+#define DT 0.0166666f
+*/
+#define DT 0.01111111f
 
 /*---------------------------------------------------------------------------*/
 
index 9cb383f..1ada5ed 100644 (file)
@@ -54,6 +54,19 @@ void put_index(FILE *fout, const int *i)
 #endif
 }
 
+void put_short(FILE *fout, const short *s)
+{
+    const unsigned char *p = (const unsigned char *) s;
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    fputc((int) p[1], fout);
+    fputc((int) p[0], fout);
+#else
+    fputc((int) p[0], fout);
+    fputc((int) p[1], fout);
+#endif
+}
+
 void put_array(FILE *fout, const float *v, size_t n)
 {
     size_t i;
@@ -98,6 +111,19 @@ void get_index(FILE *fin, int *i)
 #endif
 }
 
+void get_short(FILE *fin, short *s)
+{
+    unsigned char *p = (unsigned char *) s;
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    p[1] = (unsigned char) fgetc(fin);
+    p[0] = (unsigned char) fgetc(fin);
+#else
+    p[0] = (unsigned char) fgetc(fin);
+    p[1] = (unsigned char) fgetc(fin);
+#endif
+}
+
 void get_array(FILE *fin, float *v, size_t n)
 {
     size_t i;
index 3b0cf63..7122d12 100644 (file)
@@ -8,10 +8,12 @@
 
 void put_float(FILE *, const float *);
 void put_index(FILE *, const int   *);
+void put_short(FILE *, const short *);
 void put_array(FILE *, const float *, size_t);
 
 void get_float(FILE *, float *);
 void get_index(FILE *, int   *);
+void get_short(FILE *, short *);
 void get_array(FILE *, float *, size_t);
 
 void put_string(FILE *fout, const char *);
index de08926..ba176f7 100644 (file)
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "glext.h"
 #include "vec3.h"
+#include "sync.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -79,6 +80,7 @@ void config_init(void)
     config_set_d(CONFIG_AUDIO_BUFF,           DEFAULT_AUDIO_BUFF);
     config_set_d(CONFIG_MOUSE_SENSE,          DEFAULT_MOUSE_SENSE);
     config_set_d(CONFIG_MOUSE_INVERT,         DEFAULT_MOUSE_INVERT);
+    config_set_d(CONFIG_VSYNC,                DEFAULT_VSYNC);
     config_set_d(CONFIG_NICE,                 DEFAULT_NICE);
     config_set_d(CONFIG_FPS,                  DEFAULT_FPS);
     config_set_d(CONFIG_SOUND_VOLUME,         DEFAULT_SOUND_VOLUME);
@@ -163,6 +165,8 @@ void config_load(void)
                     config_set_d(CONFIG_MOUSE_SENSE,          atoi(val));
                 else if (strcmp(key, "mouse_invert")          == 0)
                     config_set_d(CONFIG_MOUSE_INVERT,         atoi(val));
+                else if (strcmp(key, "vsync")                 == 0)
+                    config_set_d(CONFIG_VSYNC,                atoi(val));
                 else if (strcmp(key, "nice")                  == 0)
                     config_set_d(CONFIG_NICE,                 atoi(val));
                 else if (strcmp(key, "fps")                   == 0)
@@ -288,6 +292,8 @@ void config_save(void)
                 option_d[CONFIG_MOUSE_SENSE]);
         fprintf(fp, "mouse_invert         %d\n",
                 option_d[CONFIG_MOUSE_INVERT]);
+        fprintf(fp, "vsync                %d\n",
+                option_d[CONFIG_VSYNC]);
         fprintf(fp, "nice                 %d\n",
                 option_d[CONFIG_NICE]);
         fprintf(fp, "fps                  %d\n",
@@ -410,8 +416,8 @@ int config_mode(int f, int w, int h)
     if (SDL_SetVideoMode(w, h, 0, SDL_OPENGL | (f ? SDL_FULLSCREEN : 0)))
     {
         config_set_d(CONFIG_FULLSCREEN, f);
-        config_set_d(CONFIG_WIDTH, w);
-        config_set_d(CONFIG_HEIGHT, h);
+        config_set_d(CONFIG_WIDTH,      w);
+        config_set_d(CONFIG_HEIGHT,     h);
 
         glViewport(0, 0, w, h);
         glClearColor(0.0f, 0.0f, 0.1f, 0.0f);
@@ -426,6 +432,9 @@ int config_mode(int f, int w, int h)
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
         glDepthFunc(GL_LEQUAL);
 
+        if (config_get_d(CONFIG_VSYNC))
+            sync_init();
+
         /* If GL supports multisample, and SDL got a multisample buffer... */
 
 #ifdef GL_ARB_multisample
@@ -471,6 +480,60 @@ int config_mode(int f, int w, int h)
 
 /*---------------------------------------------------------------------------*/
 
+static float ms     = 0;
+static int   fps    = 0;
+static int   last   = 0;
+static int   ticks  = 0;
+static int   frames = 0;
+
+int  config_perf(void)
+{
+    return fps;
+}
+
+void config_swap(void)
+{
+    int dt;
+
+    SDL_GL_SwapBuffers();
+
+    /* Accumulate time passed and frames rendered. */
+
+    dt = (int) SDL_GetTicks() - last;
+
+    frames +=  1;
+    ticks  += dt;
+    last   += dt;
+
+    /* Average over 250ms. */
+
+    if (ticks > 1000)
+    {
+        /* Round the frames-per-second value to the nearest integer. */
+
+        double k = 1000.0 * frames / ticks;
+        double f = floor(k);
+        double c = ceil (k);
+
+        /* Compute frame time and frames-per-second stats. */
+
+        fps = (int) ((c - k < k - f) ? c : f);
+        ms  = (float) ticks / (float) frames;
+
+        /* Reset the counters for the next update. */
+
+        frames = 0;
+        ticks  = 0;
+
+        /* Output statistics if configured. */
+
+        if (option_d[CONFIG_STATS])
+            fprintf(stdout, "%4d %8.4f\n", fps, ms);
+    }
+}
+
+/*---------------------------------------------------------------------------*/
+
 void config_set_d(int i, int d)
 {
     option_d[i] = d;
index 64e83da..79d88cf 100644 (file)
@@ -47,6 +47,7 @@ enum {
     CONFIG_AUDIO_BUFF,
     CONFIG_MOUSE_SENSE,
     CONFIG_MOUSE_INVERT,
+    CONFIG_VSYNC,
     CONFIG_NICE,
     CONFIG_FPS,
     CONFIG_SOUND_VOLUME,
@@ -111,7 +112,8 @@ enum {
 #define DEFAULT_AUDIO_BUFF           AUDIO_BUFF_HI
 #define DEFAULT_MOUSE_SENSE          300
 #define DEFAULT_MOUSE_INVERT         0
-#define DEFAULT_NICE                 1
+#define DEFAULT_VSYNC                1
+#define DEFAULT_NICE                 0
 #define DEFAULT_FPS                  0
 #define DEFAULT_SOUND_VOLUME         10
 #define DEFAULT_MUSIC_VOLUME         6
@@ -156,6 +158,10 @@ void config_load(void);
 void config_save(void);
 int  config_mode(int, int, int);
 
+int  config_perf(void);
+void config_sync(void);
+void config_swap(void);
+
 /*---------------------------------------------------------------------------*/
 
 void config_set_d(int, int);
index ef4ccef..fdda51d 100644 (file)
@@ -219,7 +219,7 @@ static void part_draw(const float p[3], const float c[3],
 
 void part_draw_coin(float rx, float ry)
 {
-    float r = (float) SDL_GetTicks() / 1000.f;
+    float r = (float) SDL_GetTicks() / 1000.0f;
     int i;
 
     glBindTexture(GL_TEXTURE_2D, part_text);
@@ -234,7 +234,7 @@ void part_draw_coin(float rx, float ry)
 
 void part_draw_goal(float rx, float ry, float radius, float a)
 {
-    float r = (float) SDL_GetTicks() / 1000.f;
+    float r = (float) SDL_GetTicks() / 1000.0f;
     int i;
 
     glBindTexture(GL_TEXTURE_2D, part_text);
diff --git a/share/sync.c b/share/sync.c
new file mode 100644 (file)
index 0000000..847d74d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2003 Robert Kooima
+ *
+ * NEVERBALL is  free software; you can redistribute  it and/or modify
+ * it under the  terms of the GNU General  Public License as published
+ * by the Free  Software Foundation; either version 2  of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
+ * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
+ * General Public License for more details.
+ */
+
+#include "glext.h"
+
+/*---------------------------------------------------------------------------*/
+#ifndef __APPLE__
+
+static int search(const char *haystack, const char *needle)
+{
+    const char *c;
+
+    for (; *haystack; haystack++)
+    {
+        for (c = needle; *c && *haystack; c++, haystack++)
+            if (*c != *haystack)
+                break;
+
+        if ((*c == 0) && (*haystack == ' ' || *haystack == '\0'))
+            return 1;
+    }
+
+    return 0;
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+#ifdef __linux__
+
+#include <GL/glx.h>
+
+void sync_init(void)
+{
+    Display *dpy = glXGetCurrentDisplay();
+    int      scr = DefaultScreen(dpy);
+
+    PFNGLXSWAPINTERVALSGIPROC _glXSwapInvervalSGI = NULL;
+
+    if (search(glXQueryExtensionsString(dpy, scr), "GLX_SGI_swap_control"))
+    {
+        if ((_glXSwapInvervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
+             glXGetProcAddress((const GLubyte *) "glXSwapIntervalSGI")))
+            _glXSwapInvervalSGI(1);
+    }
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+#ifdef _WIN32
+
+void sync_init(void)
+{
+/* TODO: Sit down at a Windows machine and make this work.
+    PFNWGLSWAPINTERVALEXTPROC _wglSwapInvervalEXT = NULL;
+
+    if (search(wglGetExtensionsString(), "WGL_EXT_swap_control"))
+    {
+        if ((_wglSwapInvervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
+             wglGetProcAddress((const GLubyte *) "wglSwapIntervalEXT")))
+            _wglSwapInvervalEXT(1);
+    }
+*/
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
+#ifdef __APPLE__
+
+#include <OpenGL/OpenGL.h>
+
+void sync_init(void)
+{
+    long swap = 1;
+    CGLSetParameter(CGLGetCurrentContext(),  kCGLCPSwapInterval, &swap);
+}
+
+#endif
+/*---------------------------------------------------------------------------*/
diff --git a/share/sync.h b/share/sync.h
new file mode 100644 (file)
index 0000000..4afee01
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2003 Robert Kooima
+ *
+ * NEVERBALL is  free software; you can redistribute  it and/or modify
+ * it under the  terms of the GNU General  Public License as published
+ * by the Free  Software Foundation; either version 2  of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
+ * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef SYNC_H
+#define SYNC_H
+
+/*---------------------------------------------------------------------------*/
+
+void sync_init(void);
+
+/*---------------------------------------------------------------------------*/
+
+#endif
index 0d3884f..842eb11 100644 (file)
@@ -4,22 +4,9 @@ CFLAGS := -Wall -g -pedantic
 
 #------------------------------------------------------------------------------
 
-DEMOCONV := democonv$(EXT)
-DEMOCONV_CPPFLAGS := \
-    -I../ball -I../share $(shell sdl-config --cflags) -Umain
-DEMOCONV_OBJS := ../share/binary.o src/democonv.o
-
-#------------------------------------------------------------------------------
-
-all: $(DEMOCONV)
-
-$(DEMOCONV): $(DEMOCONV_OBJS)
-       $(CC) $(CFLAGS) $(DEMOCONV_OBJS) $(LDFLAGS) -o $(DEMOCONV)
-
-$(DEMOCONV): CPPFLAGS := $(DEMOCONV_CPPFLAGS) $(CPPFLAGS)
+all:
 
 clean:
-       $(RM) $(DEMOCONV) $(DEMOCONV_OBJS)
 
 #------------------------------------------------------------------------------
 
diff --git a/tools/README b/tools/README
deleted file mode 100644 (file)
index 91b570a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-
-The tools subdirectory contains various Neverball-related utilities.
-Currently it only contains the replay converter and a wrapper Windows NT
-command shell script.
-
-  * democonv
-
-    A bare-bones Neverball 1.4.0 to v4 (Neverball 1.5.0) format replay
-    converter.  Reads a replay from standard input and writes a
-    converted replay to standard output.  See below for examples.
-
-    democonv recognizes several command line options.  Default values
-    are used when an option is not present (these are noted below).
-    Unrecognized options are silently ignored.  Multiple options of the
-    same kind may be given, but only the last one will be used.  These
-    options are recognized:
-
-        --help
-
-            Request a usage message.  A short list of options and their
-            meanings is printed to standard error and democonv exits
-            with a non-zero exit code.
-
-        --goal
-        --time-out
-        --fall-out
-            
-            Specify the outcome of the replay.  By default none of these
-            values is used, resulting in a "status:  aborted" message at
-            the replay selection screen.
-
-        --best-time
-        --most-coins
-        --freestyle
-
-            Specify the type of the record.  Although promising, these
-            options only influence what game mode to set for the replay.
-            The practice mode is used for Best Time replays and the
-            normal mode is used for Most Coins replays.  A custom value
-            is used for Freestyle replays which is also the default when
-            none of these options is present.  This results in an "mode:
-            unknown" message at the replay selection screen.
-
-        --player <name>
-
-            Specify name of the player.  Name of any length may be used
-            here, but only the first 8 bytes are meaningful.  Using
-            characters not in ASCII is discouraged.  It will work but it
-            won't make sense.  The default value is "Player".
-
-        --date <datetime>
-
-            Specify the date and time of creation.  These are treated as
-            local date/time and are used to calculate the actual UTC
-            time to store in the replay.  datetime should be in the
-            following format:  YYYY-mm-ddTHH:MM:SS.  "T" is literally
-            the character T.  The default value is 2003-07-16T00:00:00
-            (UTC).  (Trivia:  it is the date of posting of Super Empty
-            Ball on flipcode.)
-
-    A few examples:
-
-        $ democonv --goal --most-coins --player parasti \
-          --date 2006-10-10T15:30:00 < cE01para > cE01para.nbr
-
-        $ wget -O - http://lots.of.replays.org/fM25mym | democonv \
-          --fall-out --player mym > fM25mym.nbr
-
-    Windows users, note that cmd.exe supports input redirection and
-    pipes the same way Unix shells do, so these examples should work in
-    Windows NT command shell.  Substitute '>' for the prompt sign and
-    '^' for the line continuation symbol.
-
-  * convert-replays.bat
-
-    A convenience wrapper script around democonv for Windows users.
-    This script takes a list of files on its command line and saves
-    sucessfully converted files to the current working directory.
-    Wildcards are supported.  Original filenames with the '.nbr'
-    extension appended are used for converted files.
-
-    convert-replays.bat recognizes all of democonv's command line
-    options.  In addition, a --prefix option is recognized.
-
-        --prefix <pref>
-
-            Specify a prefix to use for filenames of converted files.
-            Useful if you want to save converted files to a directory
-            other than CWD.
-
-    Examples:
-
-        > convert-replays --player Dave --most-coins c*dav
-        > convert-replays --goal --player parasti ^
-          --prefix ..\new-replays\ ..\old-replays\*
-
diff --git a/tools/convert-replays.bat b/tools/convert-replays.bat
deleted file mode 100644 (file)
index 2d13c4f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-@echo off\r
-\r
-setlocal enableextensions\r
-\r
-    set DCEXEC=democonv\r
-    set DCCMD=%DCEXEC%\r
-\r
-    if (%1) == () (\r
-    :usage\r
-        echo Usage: %0 [options] [file-list]\r
-        %DCEXEC% --help 2>&1 | more +1\r
-        echo   --prefix ^<pref^>\r
-        echo            Add this prefix before filenames of converted\r
-        echo            replays.  Useful for saving replays to a directory\r
-        echo            other than CWD.\r
-\r
-        exit /b 1\r
-    )\r
-\r
-    rem do .. while ..\r
-    :args\r
-        if (%1) == (-h) (\r
-            goto usage\r
-        ) else if (%1) == (--help) (\r
-            goto usage\r
-        ) else if (%1) == (--goal) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--fall-out) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--time-out) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--best-time) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--most-coins) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--freestyle) (\r
-            set DCCMD=%DCCMD% %1\r
-        ) else if (%1) == (--player) (\r
-            set DCCMD=%DCCMD% %1 %2\r
-            shift\r
-        ) else if (%1) == (--date) (\r
-            set DCCMD=%DCCMD% %1 %2\r
-            shift\r
-        ) else if (%1) == (--prefix) (\r
-            set PREFIX=%2\r
-            shift\r
-        )\r
-        shift\r
-    if not (%1) == () goto args\r
-\r
-    for %%d in (%*) do (\r
-        rem This ugly test tries to make sure we're not processing command\r
-        rem line options and directories (weird errors pop up).\r
-\r
-        if exist %%d if not exist %%dnul (\r
-            %DCCMD% < %%d > %PREFIX%%%~nxd.nbr\r
-            if errorlevel 1 del %PREFIX%%%~nxd.nbr\r
-        )\r
-    )\r
-    exit /b 0\r
-\r
-endlocal\r
-\r
-rem vim:set sts=4 sw=4 et:\r
diff --git a/tools/src/democonv.c b/tools/src/democonv.c
deleted file mode 100644 (file)
index a1db1c8..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * democonv -- Neverball 1.4.0 to v4 format replay converter.
- *
- * Copyright (C) 2006 Jānis Rūcis
- *
- * Part of the Neverball project.
- *
- * Copyright (C) 2003 Robert Kooima
- *
- * NEVERBALL is  free software; you can redistribute  it and/or modify
- * it under the  terms of the GNU General  Public License as published
- * by the Free  Software Foundation; either version 2  of the License,
- * or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
- * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
- * General Public License for more details.
- */
-
-/*---------------------------------------------------------------------------*/
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef _WIN32
-#include <io.h>     /* _setmode() */
-#include <fcntl.h>  /* _O_BINARY  */
-#endif
-
-#include <SDL_endian.h>
-
-#include "base_config.h"
-#include "binary.h"
-#include "level.h"
-#include "mode.h"
-
-/*----------------------------------------------------------------------------*/
-
-#define DATELEN 20
-
-static void get_short(FILE *fin, short *s)
-{
-    unsigned char *p = (unsigned char *) s;
-
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-    p[1] = (unsigned char) fgetc(fin);
-    p[0] = (unsigned char) fgetc(fin);
-#else
-    p[0] = (unsigned char) fgetc(fin);
-    p[1] = (unsigned char) fgetc(fin);
-#endif
-}
-
-/*---------------------------------------------------------------------------*/
-
-#define MAG_OLD     0x4E425250
-
-#define MAG_NEW     0x52424EAF
-#define VER_NEW     4
-
-/*---------------------------------------------------------------------------*/
-
-static int read_demo(FILE *fin, int *timer, int *coins,
-                     int *time, int *goal, int *score, int *balls,
-                     char *file, char *shot)
-{
-    short t, c;
-    short zero;
-
-    short st, sg, ss, sb;
-
-    char none[PATHMAX];
-
-    get_short(fin, &t);
-    get_short(fin, &c);
-
-    fread(shot, 1, PATHMAX, fin);
-    fread(file, 1, PATHMAX, fin);
-    fread(none, 1, PATHMAX, fin);
-    fread(none, 1, PATHMAX, fin);
-    fread(none, 1, PATHMAX, fin);
-
-    get_short(fin, &st);
-    get_short(fin, &sg);
-    get_short(fin, &ss);
-    get_short(fin, &zero);
-    get_short(fin, &sb);
-
-    if (!feof(fin))
-    {
-        *timer = (int) t;
-        *coins = (int) c;
-
-        *time  = (int) st;
-        *goal  = (int) sg;
-        *score = (int) ss;
-        *balls = (int) sb;
-
-        return 1;
-    }
-    return 0;
-}
-
-static int parse_args(int argc, char *argv[],
-                      int  *state,
-                      int  *mode,
-                      char *player,
-                      char *date)
-{
-    int i;
-
-    const char *usage =
-        "Usage:  %s [options]\n"
-        "Options:\n"
-        "  --help   Print this message.\n"
-        "  --goal, --time-out, --fall-out\n"
-        "           Outcome of the replay.  Default:  none.\n"
-        "  --best-time, --most-coins, --freestyle\n"
-        "           Type of record.  Default:  unknown.\n"
-        "  --player <name>\n"
-        "           Player name.  Max 8 characters.  Default:  \"Player\".\n"
-        "  --date <datetime>\n"
-        "           Date/time (local) when the replay was made.  Format is\n"
-        "           YYYY-mm-ddTHH:MM:SS.  \"T\" is literally T.  Default:\n"
-        "           \"2003-07-16T00:00:00\" (UTC).\n";
-
-    for (i = 1; i < argc; i++)
-    {
-        if (strcmp(argv[i], "-h") == 0 ||
-            strcmp(argv[i], "--help") == 0)
-        {
-            fprintf(stderr, usage, argv[0]);
-            return 0;
-        }
-
-        else if (strcmp(argv[i], "--goal") == 0)
-            *state = GAME_GOAL;
-        else if (strcmp(argv[i], "--time-out") == 0)
-            *state = GAME_TIME;
-        else if (strcmp(argv[i], "--fall-out") == 0)
-            *state = GAME_FALL;
-
-        else if (strcmp(argv[i], "--best-time") == 0)
-            *mode  = MODE_PRACTICE;
-        else if (strcmp(argv[i], "--most-coins") == 0)
-            *mode  = MODE_NORMAL;
-        else if (strcmp(argv[i], "--freestyle") == 0)
-            *mode  = 0;
-
-        else if (strcmp(argv[i], "--player") == 0)
-            strncpy(player, argv[++i], MAXNAM);
-        else if (strcmp(argv[i], "--date") == 0)
-        {
-            struct tm dt;
-
-            if (sscanf(argv[++i], "%4d-%2d-%2dT%2d:%2d:%2d",
-                       &dt.tm_year,
-                       &dt.tm_mon,
-                       &dt.tm_mday,
-                       &dt.tm_hour,
-                       &dt.tm_min,
-                       &dt.tm_sec) == 6)
-            {
-                time_t t;
-
-                dt.tm_year -= 1900;
-                dt.tm_mon  -= 1;
-                dt.tm_isdst = -1;
-
-                t = mktime(&dt);
-
-                strftime(date, DATELEN, "%Y-%m-%dT%H:%M:%S", gmtime(&t));
-            }
-            else
-            {
-                fprintf(stderr, "ERROR:  incorrect date format.  "
-                                "Try '%s --help'.\n", argv[0]);
-                return 0;
-            }
-        }
-    }
-    return 1;
-}
-
-/*---------------------------------------------------------------------------*/
-
-int main(int argc, char *argv[])
-{
-    FILE *fin, *fout;
-
-    int magic;
-    int version = VER_NEW;
-
-    int  state          = GAME_NONE;
-    int  mode           = 0;
-    char player[MAXNAM] = "Player";
-    char date[DATELEN]  = "2003-07-16T00:00:00";
-
-    if (!parse_args(argc, argv, &state, &mode, player, date))
-        return 1;
-
-#ifdef _WIN32
-    _setmode(_fileno(stdin),  _O_BINARY);
-    _setmode(_fileno(stdout), _O_BINARY);
-#endif
-
-    fin  = stdin;
-    fout = stdout;
-
-    get_index(fin, &magic);
-
-    if (magic == MAG_OLD)
-    {
-        int timer;
-        int coins;
-
-        int time, goal, score, balls;
-
-        char file[PATHMAX];
-        char shot[PATHMAX];
-
-        int zero = 0;
-
-        if (read_demo(fin, &timer, &coins,
-                      &time, &goal, &score, &balls,
-                      file, shot))
-        {
-            char step[MAXSTR];
-            size_t c;
-
-            magic = MAG_NEW;
-
-            put_index(fout, &magic);
-            put_index(fout, &version);
-
-            put_index(fout, &timer);
-            put_index(fout, &coins);
-            put_index(fout, &state);
-            put_index(fout, &mode);
-
-            put_string(fout, player);
-            put_string(fout, date);
-
-            put_string(fout, shot);
-            put_string(fout, file);
-
-            put_index(fout, &time);
-            put_index(fout, &goal);
-            put_index(fout, &score);
-            put_index(fout, &balls);
-            put_index(fout, &zero);
-
-            while ((c = fread(step, 1, sizeof (step), fin)) > 0)
-                fwrite(step, 1, c, fout);
-
-            return 0;
-        }
-    }
-    return 1;
-}
-
-/*---------------------------------------------------------------------------*/