From e87ac53bb04df47a26f0b87fb67886886ab44260 Mon Sep 17 00:00:00 2001 From: Roman Fomin Date: Mon, 16 Sep 2024 07:45:06 +0700 Subject: [PATCH] interpolation of wipe melt animation, adapted from R&R (#1903) * no need to skip DRS --- src/d_main.c | 23 ++--- src/f_wipe.c | 237 ++++++++++++++++++++++++++++++++------------------ src/m_fixed.h | 4 + 3 files changed, 164 insertions(+), 100 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index bff54908..3c7f0666 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -292,7 +292,7 @@ void D_Display (void) if (gamestate != wipegamestate && (strictmode || screen_melt)) { wipe = true; - wipe_StartScreen(0, 0, video.unscaledw, SCREENHEIGHT); + wipe_StartScreen(0, 0, video.width, video.height); } if (!wipe) @@ -432,29 +432,24 @@ void D_Display (void) } // wipe update - wipe_EndScreen(0, 0, video.unscaledw, SCREENHEIGHT); + wipe_EndScreen(0, 0, video.width, video.height); wipestart = I_GetTime () - 1; do { - int nowtime, tics; - do - { - I_Sleep(1); - nowtime = I_GetTime(); - tics = nowtime - wipestart; - } - while (!tics); - wipestart = nowtime; + int nowtime = I_GetTime(); + int tics = nowtime - wipestart; + + fractionaltic = I_GetFracTime(); + done = wipe_ScreenWipe(strictmode ? wipe_Melt : screen_melt, - 0, 0, video.unscaledw, SCREENHEIGHT, tics); + 0, 0, video.width, video.height, tics); + wipestart = nowtime; M_Drawer(); // menu is drawn even on top of wipes I_FinishUpdate(); // page flip or blit buffer } while (!done); - - drs_skip_frame = true; // skip DRS after wipe } // diff --git a/src/f_wipe.c b/src/f_wipe.c index 0f4d2115..73ac8417 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -23,6 +23,7 @@ #include "f_wipe.h" #include "i_video.h" #include "m_random.h" +#include "r_main.h" #include "v_flextran.h" #include "v_video.h" #include "z_zone.h" @@ -33,10 +34,10 @@ // when they try to scale up the original logic to higher resolutions. // Number of "falling columns" on the screen. -static int num_columns; +static int wipe_columns; // Distance a column falls before it reaches the bottom of the screen. -#define COLUMN_MAX_Y 200 +#define WIPE_ROWS 200 // // SCREEN WIPE PACKAGE @@ -46,18 +47,6 @@ static byte *wipe_scr_start; static byte *wipe_scr_end; static byte *wipe_scr; -static void wipe_shittyColMajorXform(byte *array, int width, int height) -{ - byte *dest = Z_Malloc(width*height, PU_STATIC, 0); - int x, y; - - for(y=0;y not ready to scroll yet) - col_y[0] = -(M_Random()%16); - for (i=1;i not ready to scroll yet) + curry[0] = -(M_Random() % 16); + for (int i = 1; i < wipe_columns; i++) { - int r = (M_Random()%3) - 1; - col_y[i] = col_y[i-1] + r; - if (col_y[i] > 0) - col_y[i] = 0; - else - if (col_y[i] == -16) - col_y[i] = -15; + int r = (M_Random() % 3) - 1; + curry[i] = curry[i - 1] + r; + if (curry[i] > 0) + { + curry[i] = 0; + } + else if (curry[i] == -16) + { + curry[i] = -15; + } } - return 0; + + memcpy(prevy, curry, sizeof(int) * wipe_columns); + + return 0; } static int wipe_doMelt(int width, int height, int ticks) { - boolean done = true; - int x, y, xfactor, yfactor; + boolean done = true; - while (ticks--) - for (x=0;x 0) + { + while (ticks--) { - col_y[x]++; - done = false; + int *temp = prevy; + prevy = curry; + curry = temp; + + for (int col = 0; col < wipe_columns; ++col) + { + if (prevy[col] < 0) + { + curry[col] = prevy[col] + 1; + done = false; + } + else if (prevy[col] < WIPE_ROWS) + { + int dy = (prevy[col] < 16) ? prevy[col] + 1 : 8; + curry[col] = MIN(prevy[col] + dy, WIPE_ROWS); + + done = false; + } + else + { + curry[col] = WIPE_ROWS; + } + } } - else if (col_y[x] < COLUMN_MAX_Y) + } + else + { + for (int col = 0; col < wipe_columns; ++col) { - int dy = (col_y[x] < 16) ? col_y[x]+1 : 8; - if (col_y[x]+dy >= COLUMN_MAX_Y) - dy = COLUMN_MAX_Y - col_y[x]; - col_y[x] += dy; - done = false; + done &= curry[col] >= WIPE_ROWS; + } + } + + return done; +} + +int wipe_renderMelt(int width, int height, int ticks) +{ + boolean done = true; + + // Scale up and then down to handle arbitrary dimensions with integer math + int vertblocksize = height * 100 / WIPE_ROWS; + int horizblocksize = width * 100 / wipe_columns; + int currcol; + int currcolend; + int currrow; + + V_UseBuffer(wipe_scr); + V_PutBlock(0, 0, width, height, wipe_scr_end); + V_RestoreBuffer(); + + for (int col = 0; col < wipe_columns; ++col) + { + int current; + if (uncapped) + { + current = FixedToInt( + LerpFixed(IntToFixed(prevy[col]), IntToFixed(curry[col]))); + } + else + { + current = curry[col]; } - xfactor = (width + num_columns - 1) / num_columns; - yfactor = (height + COLUMN_MAX_Y - 1) / COLUMN_MAX_Y; + if (current < 0) + { + currcol = col * horizblocksize / 100; + currcolend = (col + 1) * horizblocksize / 100; + for (; currcol < currcolend; ++currcol) + { + pixel_t *source = wipe_scr_start + currcol; + pixel_t *dest = wipe_scr + currcol; - for (x = 0; x < width; x++) - { - byte *s, *d; - int scroff = col_y[x / xfactor] * yfactor; - if (scroff > height) - scroff = height; + for (int i = 0; i < height; ++i) + { + *dest = *source; + dest += video.pitch; + source += width; + } + } + } + else if (current < WIPE_ROWS) + { + currcol = col * horizblocksize / 100; + currcolend = (col + 1) * horizblocksize / 100; - d = wipe_scr + x; - s = wipe_scr_end + x * height; - for (y = 0; y < scroff; ++y) - { - *d = *s; - d += video.pitch; - s++; + currrow = current * vertblocksize / 100; + + for (; currcol < currcolend; ++currcol) + { + pixel_t *source = wipe_scr_start + currcol; + pixel_t *dest = wipe_scr + currcol + (currrow * video.pitch); + + for (int i = 0; i < height - currrow; ++i) + { + *dest = *source; + dest += video.pitch; + source += width; + } + } + + done = false; + } } - s = wipe_scr_start + x * height; - for (; y < height; ++y) - { - *d = *s; - d += video.pitch; - s++; - } - } - return done; + + return done; } static int wipe_exitMelt(int width, int height, int ticks) { - Z_Free(col_y); + Z_Free(ybuff1); + Z_Free(ybuff2); wipe_exit(width, height, ticks); return 0; } int wipe_StartScreen(int x, int y, int width, int height) { - int size = video.width * video.height; + int size = width * height; wipe_scr_start = Z_Malloc(size * sizeof(*wipe_scr_start), PU_STATIC, NULL); I_ReadScreen(wipe_scr_start); return 0; @@ -202,14 +262,14 @@ int wipe_StartScreen(int x, int y, int width, int height) int wipe_EndScreen(int x, int y, int width, int height) { - int size = video.width * video.height; + int size = width * height; wipe_scr_end = Z_Malloc(size * sizeof(*wipe_scr_end), PU_STATIC, NULL); I_ReadScreen(wipe_scr_end); V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr. return 0; } -static int wipe_NOP(int x, int y, int t) +static int wipe_NOP(int width, int height, int tics) { return 0; } @@ -266,7 +326,7 @@ static unsigned int lastrndval; static int wipe_initFizzle(int width, int height, int ticks) { int rndbits_x = log2_ceil(video.unscaledw); - rndbits_y = log2_ceil(COLUMN_MAX_Y); + rndbits_y = log2_ceil(WIPE_ROWS); int rndbits = rndbits_x + rndbits_y; if (rndbits < 17) @@ -285,7 +345,7 @@ static int wipe_initFizzle(int width, int height, int ticks) static int wipe_doFizzle(int width, int height, int ticks) { - const int pixperframe = (video.unscaledw * COLUMN_MAX_Y) >> 5; + const int pixperframe = (video.unscaledw * WIPE_ROWS) >> 5; unsigned int rndval = lastrndval; for (unsigned p = 0; p < pixperframe; p++) @@ -299,7 +359,7 @@ static int wipe_doFizzle(int width, int height, int ticks) rndval = (rndval >> 1) ^ (rndval & 1 ? 0 : rndmask); - if (x >= video.unscaledw || y >= COLUMN_MAX_Y) + if (x >= video.unscaledw || y >= WIPE_ROWS) { if (rndval == 0) // entire sequence has been completed { @@ -336,17 +396,21 @@ static int wipe_doFizzle(int width, int height, int ticks) } static int (*const wipes[])(int, int, int) = { + wipe_NOP, wipe_NOP, wipe_NOP, wipe_exit, wipe_initMelt, wipe_doMelt, + wipe_renderMelt, wipe_exitMelt, wipe_initColorXForm, wipe_doColorXForm, + wipe_NOP, wipe_exit, wipe_initFizzle, wipe_doFizzle, + wipe_NOP, wipe_exit, }; @@ -355,18 +419,19 @@ int wipe_ScreenWipe(int wipeno, int x, int y, int width, int height, int ticks) { static boolean go; // when zero, stop the wipe - width = video.width; - height = video.height; - if (!go) // initial stuff { go = 1; wipe_scr = I_VideoBuffer; - wipes[wipeno*3](width, height, ticks); + wipes[wipeno*4](width, height, ticks); } - if (wipes[wipeno*3+1](width, height, ticks)) // final stuff + + int rc = wipes[wipeno*4+1](width, height, ticks); + wipes[wipeno*4+2](width, height, ticks); + + if (rc) // final stuff { - wipes[wipeno*3+2](width, height, ticks); + wipes[wipeno*4+3](width, height, ticks); go = 0; } return !go; diff --git a/src/m_fixed.h b/src/m_fixed.h index e8cfa0f3..9e740a62 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -44,6 +44,10 @@ #define FRACUNIT (1<> FRACBITS, (x)) typedef int fixed_t;