interpolation of wipe melt animation, adapted from R&R (#1903)

* no need to skip DRS
This commit is contained in:
Roman Fomin 2024-09-16 07:45:06 +07:00 committed by GitHub
parent 4e6ed4a1a0
commit e87ac53bb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 164 additions and 100 deletions

View File

@ -292,7 +292,7 @@ void D_Display (void)
if (gamestate != wipegamestate && (strictmode || screen_melt)) if (gamestate != wipegamestate && (strictmode || screen_melt))
{ {
wipe = true; wipe = true;
wipe_StartScreen(0, 0, video.unscaledw, SCREENHEIGHT); wipe_StartScreen(0, 0, video.width, video.height);
} }
if (!wipe) if (!wipe)
@ -432,29 +432,24 @@ void D_Display (void)
} }
// wipe update // wipe update
wipe_EndScreen(0, 0, video.unscaledw, SCREENHEIGHT); wipe_EndScreen(0, 0, video.width, video.height);
wipestart = I_GetTime () - 1; wipestart = I_GetTime () - 1;
do do
{ {
int nowtime, tics; int nowtime = I_GetTime();
do int tics = nowtime - wipestart;
{
I_Sleep(1); fractionaltic = I_GetFracTime();
nowtime = I_GetTime();
tics = nowtime - wipestart;
}
while (!tics);
wipestart = nowtime;
done = wipe_ScreenWipe(strictmode ? wipe_Melt : screen_melt, 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 M_Drawer(); // menu is drawn even on top of wipes
I_FinishUpdate(); // page flip or blit buffer I_FinishUpdate(); // page flip or blit buffer
} }
while (!done); while (!done);
drs_skip_frame = true; // skip DRS after wipe
} }
// //

View File

@ -23,6 +23,7 @@
#include "f_wipe.h" #include "f_wipe.h"
#include "i_video.h" #include "i_video.h"
#include "m_random.h" #include "m_random.h"
#include "r_main.h"
#include "v_flextran.h" #include "v_flextran.h"
#include "v_video.h" #include "v_video.h"
#include "z_zone.h" #include "z_zone.h"
@ -33,10 +34,10 @@
// when they try to scale up the original logic to higher resolutions. // when they try to scale up the original logic to higher resolutions.
// Number of "falling columns" on the screen. // 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. // Distance a column falls before it reaches the bottom of the screen.
#define COLUMN_MAX_Y 200 #define WIPE_ROWS 200
// //
// SCREEN WIPE PACKAGE // SCREEN WIPE PACKAGE
@ -46,18 +47,6 @@ static byte *wipe_scr_start;
static byte *wipe_scr_end; static byte *wipe_scr_end;
static byte *wipe_scr; 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<height;y++)
for(x=0;x<width;x++)
dest[x*height+y] = array[y*width+x];
memcpy(array, dest, width*height);
Z_Free(dest);
}
// [FG] cross-fading screen wipe implementation // [FG] cross-fading screen wipe implementation
static int fade_tick; static int fade_tick;
@ -102,99 +91,170 @@ static int wipe_exit(int width, int height, int ticks)
return 0; return 0;
} }
static int *col_y; static int *ybuff1, *ybuff2;
static int *curry, *prevy;
static int wipe_initMelt(int width, int height, int ticks) static int wipe_initMelt(int width, int height, int ticks)
{ {
int i; wipe_columns = video.unscaledw / 2;
num_columns = video.unscaledw / 2; ybuff1 = Z_Malloc(wipe_columns * sizeof(*ybuff1), PU_STATIC, NULL);
ybuff2 = Z_Malloc(wipe_columns * sizeof(*ybuff2), PU_STATIC, NULL);
col_y = Z_Malloc(num_columns * sizeof(*col_y), PU_STATIC, NULL); curry = ybuff1;
prevy = ybuff2;
// copy start screen to main screen // copy start screen to main screen
V_PutBlock(0, 0, width, height, wipe_scr_start); V_PutBlock(0, 0, width, height, wipe_scr_start);
// makes this wipe faster (in theory) // setup initial column positions (y<0 => not ready to scroll yet)
// to have stuff in column-major format curry[0] = -(M_Random() % 16);
wipe_shittyColMajorXform(wipe_scr_start, width, height); for (int i = 1; i < wipe_columns; i++)
wipe_shittyColMajorXform(wipe_scr_end, width, height);
// setup initial column positions (y<0 => not ready to scroll yet)
col_y[0] = -(M_Random()%16);
for (i=1;i<num_columns;i++)
{ {
int r = (M_Random()%3) - 1; int r = (M_Random() % 3) - 1;
col_y[i] = col_y[i-1] + r; curry[i] = curry[i - 1] + r;
if (col_y[i] > 0) if (curry[i] > 0)
col_y[i] = 0; {
else curry[i] = 0;
if (col_y[i] == -16) }
col_y[i] = -15; 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) static int wipe_doMelt(int width, int height, int ticks)
{ {
boolean done = true; boolean done = true;
int x, y, xfactor, yfactor;
while (ticks--) if (ticks > 0)
for (x=0;x<num_columns;x++) {
if (col_y[x]<0) while (ticks--)
{ {
col_y[x]++; int *temp = prevy;
done = false; 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; done &= curry[col] >= WIPE_ROWS;
if (col_y[x]+dy >= COLUMN_MAX_Y) }
dy = COLUMN_MAX_Y - col_y[x]; }
col_y[x] += dy;
done = false; 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; if (current < 0)
yfactor = (height + COLUMN_MAX_Y - 1) / COLUMN_MAX_Y; {
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++) for (int i = 0; i < height; ++i)
{ {
byte *s, *d; *dest = *source;
int scroff = col_y[x / xfactor] * yfactor; dest += video.pitch;
if (scroff > height) source += width;
scroff = height; }
}
}
else if (current < WIPE_ROWS)
{
currcol = col * horizblocksize / 100;
currcolend = (col + 1) * horizblocksize / 100;
d = wipe_scr + x; currrow = current * vertblocksize / 100;
s = wipe_scr_end + x * height;
for (y = 0; y < scroff; ++y) for (; currcol < currcolend; ++currcol)
{ {
*d = *s; pixel_t *source = wipe_scr_start + currcol;
d += video.pitch; pixel_t *dest = wipe_scr + currcol + (currrow * video.pitch);
s++;
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) return done;
{
*d = *s;
d += video.pitch;
s++;
}
}
return done;
} }
static int wipe_exitMelt(int width, int height, int ticks) 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); wipe_exit(width, height, ticks);
return 0; return 0;
} }
int wipe_StartScreen(int x, int y, int width, int height) 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); wipe_scr_start = Z_Malloc(size * sizeof(*wipe_scr_start), PU_STATIC, NULL);
I_ReadScreen(wipe_scr_start); I_ReadScreen(wipe_scr_start);
return 0; 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 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); wipe_scr_end = Z_Malloc(size * sizeof(*wipe_scr_end), PU_STATIC, NULL);
I_ReadScreen(wipe_scr_end); I_ReadScreen(wipe_scr_end);
V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr. V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
return 0; return 0;
} }
static int wipe_NOP(int x, int y, int t) static int wipe_NOP(int width, int height, int tics)
{ {
return 0; return 0;
} }
@ -266,7 +326,7 @@ static unsigned int lastrndval;
static int wipe_initFizzle(int width, int height, int ticks) static int wipe_initFizzle(int width, int height, int ticks)
{ {
int rndbits_x = log2_ceil(video.unscaledw); 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; int rndbits = rndbits_x + rndbits_y;
if (rndbits < 17) 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) 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; unsigned int rndval = lastrndval;
for (unsigned p = 0; p < pixperframe; p++) 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); 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 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) = { static int (*const wipes[])(int, int, int) = {
wipe_NOP,
wipe_NOP, wipe_NOP,
wipe_NOP, wipe_NOP,
wipe_exit, wipe_exit,
wipe_initMelt, wipe_initMelt,
wipe_doMelt, wipe_doMelt,
wipe_renderMelt,
wipe_exitMelt, wipe_exitMelt,
wipe_initColorXForm, wipe_initColorXForm,
wipe_doColorXForm, wipe_doColorXForm,
wipe_NOP,
wipe_exit, wipe_exit,
wipe_initFizzle, wipe_initFizzle,
wipe_doFizzle, wipe_doFizzle,
wipe_NOP,
wipe_exit, 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 static boolean go; // when zero, stop the wipe
width = video.width;
height = video.height;
if (!go) // initial stuff if (!go) // initial stuff
{ {
go = 1; go = 1;
wipe_scr = I_VideoBuffer; 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; go = 0;
} }
return !go; return !go;

View File

@ -44,6 +44,10 @@
#define FRACUNIT (1<<FRACBITS) #define FRACUNIT (1<<FRACBITS)
#define FIXED2DOUBLE(x) ((x)/(double)FRACUNIT) #define FIXED2DOUBLE(x) ((x)/(double)FRACUNIT)
#define FRACMASK (FRACUNIT - 1) #define FRACMASK (FRACUNIT - 1)
#define FRACFILL(x, o) ((x) | ((o) < 0 ? (FRACMASK << (32 - FRACBITS)) : 0))
#define IntToFixed(x) ((x) << FRACBITS)
#define FixedToInt(x) FRACFILL((x) >> FRACBITS, (x))
typedef int fixed_t; typedef int fixed_t;