From 02527edeeaafdc8c3fafecea772b82fd770abc9b Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Wed, 22 Apr 2015 21:36:39 +0200 Subject: [PATCH] added lag prevention to door/request/envelope animations --- src/libgame/misc.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- src/libgame/misc.h | 3 ++- src/tools.c | 31 ++++++++++++++++++++-------- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/libgame/misc.c b/src/libgame/misc.c index 56978dcc..6d80620b 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -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; + } } diff --git a/src/libgame/misc.h b/src/libgame/misc.h index f73182d4..0e2be9c9 100644 --- a/src/libgame/misc.h +++ b/src/libgame/misc.h @@ -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); diff --git a/src/tools.c b/src/tools.c index f9a2472c..edc742da 100644 --- a/src/tools.c +++ b/src/tools.c @@ -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; } -- 2.34.1