added lag prevention to door/request/envelope animations
authorHolger Schemel <info@artsoft.org>
Wed, 22 Apr 2015 19:36:39 +0000 (21:36 +0200)
committerHolger Schemel <info@artsoft.org>
Wed, 22 Apr 2015 19:36:39 +0000 (21:36 +0200)
src/libgame/misc.c
src/libgame/misc.h
src/tools.c

index 56978dccc9d3831e6af989f1f1ee1eaed15f955b..6d80620b99c61c1ebad5f5c5445c153ec6e5887d 100644 (file)
@@ -362,7 +362,7 @@ static void sleep_milliseconds(unsigned int milliseconds_delay)
   if (do_busy_waiting)
   {
     /* we want to wait only a few ms -- if we assume that we have a
-       kernel timer resolution of 10 ms, we would wait far to long;
+       kernel timer resolution of 10 ms, we would wait far too long;
        therefore it's better to do a short interval of busy waiting
        to get our sleeping time more accurate */
 
@@ -411,9 +411,10 @@ boolean DelayReached(unsigned int *counter_var,
   return TRUE;
 }
 
-void WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
+int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
 {
   unsigned int actual_counter;
+  int skip_frames = 0;
 
   while (1)
   {
@@ -426,7 +427,53 @@ void WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
       break;
   }
 
+  if (*counter_var != 0 && actual_counter >= *counter_var + delay)
+  {
+    int lag = actual_counter - (*counter_var + delay);
+    int delay2 = (delay + 1) / 2;
+
+    if (lag >= delay2)
+      skip_frames = (lag + delay2) / delay;
+  }
+
   *counter_var = actual_counter;
+
+  return skip_frames;
+}
+
+void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay,
+                          int *loop_var, int last_loop_value)
+{
+  int skip_frames = WaitUntilDelayReached(counter_var, delay);
+
+#if 0
+#if DEBUG
+  printf("::: %d: %d ms", *loop_var, delay);
+  if (skip_frames)
+    printf(" -> SKIP %d FRAME(S) [%d ms]", skip_frames, skip_frames * delay);
+  printf("\n");
+#endif
+#endif
+
+  if (skip_frames == 0)
+    return;
+
+  // when skipping frames, make sure to never skip the last frame, as
+  // this may be needed for animations to reach a defined end state;
+  // furthermore, we assume that this function is called at the end
+  // of a "for" loop, which continues by incrementing the loop variable
+  // by one before checking the loop condition again; therefore we have
+  // to check against the last loop value minus one here
+
+  last_loop_value--;
+
+  if (*loop_var < last_loop_value)     // never skip the last frame
+  {
+    *loop_var += skip_frames;
+
+    if (*loop_var > last_loop_value)   // never skip the last frame
+      *loop_var = last_loop_value;
+  }
 }
 
 
index f73182d4ae53e26f3948b06206abc72af62a3982..0e2be9c931f4f0d626adf2842562309a1d232fe8 100644 (file)
@@ -133,7 +133,8 @@ unsigned int Counter(void);
 void Delay(unsigned int);
 boolean FrameReached(unsigned int *, unsigned int);
 boolean DelayReached(unsigned int *, unsigned int);
-void WaitUntilDelayReached(unsigned int *, unsigned int);
+int WaitUntilDelayReached(unsigned int *, unsigned int);
+void SkipUntilDelayReached(unsigned int *, unsigned int, int *, int);
 
 unsigned int init_random_number(int, int);
 unsigned int get_random_number(int, int);
index f9a2472c1fe45d5975bf9ee15f09b25ebcc402ca..edc742da651a1f87cce68b41723cf6fb7b2a4be1 100644 (file)
@@ -2127,7 +2127,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   boolean no_delay = (tape.warp_forward);
   unsigned int anim_delay = 0;
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
-  int anim_delay_value = (no_delay ? 0 : frame_delay_value);
+  int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
@@ -2139,10 +2139,15 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
   int xstep = (xstart < xend ? 1 : 0);
   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
-  int x, y;
+  int start = 0;
+  int end = MAX(xend - xstart, yend - ystart);
+  int i;
 
-  for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
+  for (i = start; i <= end; i++)
   {
+    int last_frame = end;      // last frame of this "for" loop
+    int x = xstart + i * xstep;
+    int y = ystart + i * ystep;
     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
@@ -2168,7 +2173,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
     BackToFront();
 
-    WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
+    SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
   }
 }
 
@@ -2319,7 +2324,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
-  int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
+  int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
   unsigned int anim_delay = 0;
 
   int width = request.width;
@@ -2336,12 +2341,15 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
   int xstep = (xstart < xend ? 1 : 0);
   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
-  int x, y;
+  int start = 0;
+  int end = MAX(xend - xstart, yend - ystart);
+  int i;
 
   if (setup.quick_doors)
   {
     xstart = xend;
     ystart = yend;
+    end = 0;
   }
   else
   {
@@ -2351,8 +2359,11 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
       PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
   }
 
-  for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
+  for (i = start; i <= end; i++)
   {
+    int last_frame = end;      // last frame of this "for" loop
+    int x = xstart + i * xstep;
+    int y = ystart + i * ystep;
     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
     int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
@@ -2394,7 +2405,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
     DoAnimation();
     BackToFront();
 
-    WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
+    SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
   }
 }
 
@@ -4207,6 +4218,8 @@ unsigned int MoveDoor(unsigned int door_state)
 
     for (k = start; k < num_move_steps; k++)
     {
+      int last_frame = num_move_steps - 1;     // last frame of this "for" loop
+
       door_part_done_all = TRUE;
 
       for (i = 0; i < NUM_DOORS; i++)
@@ -4365,7 +4378,7 @@ unsigned int MoveDoor(unsigned int door_state)
        if (game_status == GAME_MODE_MAIN)
          DoAnimation();
 
-       WaitUntilDelayReached(&door_delay, door_delay_value);
+       SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
 
        current_move_delay += max_step_delay;
       }