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))
{
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
}
//

View File

@ -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<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
static int fade_tick;
@ -102,99 +91,170 @@ static int wipe_exit(int width, int height, int ticks)
return 0;
}
static int *col_y;
static int *ybuff1, *ybuff2;
static int *curry, *prevy;
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
V_PutBlock(0, 0, width, height, wipe_scr_start);
// copy start screen to main screen
V_PutBlock(0, 0, width, height, wipe_scr_start);
// makes this wipe faster (in theory)
// to have stuff in column-major format
wipe_shittyColMajorXform(wipe_scr_start, width, height);
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++)
// setup initial column positions (y<0 => 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<num_columns;x++)
if (col_y[x]<0)
if (ticks > 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;

View File

@ -44,6 +44,10 @@
#define FRACUNIT (1<<FRACBITS)
#define FIXED2DOUBLE(x) ((x)/(double)FRACUNIT)
#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;