Lots of fixes for the intermission background

* On GL, the background no longer disappears if the game is paused
* On GL, changing resolutions now draws SRB2BACK instead of a white void
* On software, changing resolutions redraws the level instead of awkwardly
  stretching the background to fill the screen
This commit is contained in:
GenericHeroGuy 2025-08-27 16:35:20 +02:00
parent 96f9c919d4
commit 423a9ee8a6
13 changed files with 104 additions and 194 deletions

View file

@ -4026,6 +4026,7 @@ void SV_StopServer(void)
if (gamestate == GS_VOTING)
Y_EndVote();
gamestate = wipegamestate = GS_NULL;
P_UnloadLevel();
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
((UINT16*)localtextcmd[i])[0] = 0;

View file

@ -275,10 +275,13 @@ void D_ProcessEvents(void)
recursioncheck = false;
}
static void D_RenderLevel(void)
boolean D_RenderLevel(void)
{
UINT8 i;
if (automapactive || dedicated || !cv_renderview.value || !levelloaded)
return false;
R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
viewwindowy = 0;
@ -387,6 +390,7 @@ static void D_RenderLevel(void)
ps_rendercalltime = I_GetPreciseTime() - ps_rendercalltime;
R_RestoreLevelInterpolators();
return true;
}
//
@ -511,12 +515,7 @@ static void D_Display(void)
// intermission background
if (lastdraw)
{
if (rendermode == render_soft && !automapactive && !dedicated && cv_renderview.value)
{
D_RenderLevel();
Y_ConsiderScreenBuffer();
usebuffer = true;
}
lastdraw = false;
}
@ -607,7 +606,6 @@ static void D_Display(void)
// see if the border needs to be initially drawn
if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction && curbghide && (!hidetitlemap)))
{
if (!automapactive && !dedicated && cv_renderview.value)
D_RenderLevel();
ps_uitime = I_GetPreciseTime();

View file

@ -61,6 +61,8 @@ extern char srb2path[256]; //Alam: SRB2's Home
// the infinite loop of D_SRB2Loop() called from win_main for windows version
void D_SRB2Loop(void) FUNCNORETURN;
boolean D_RenderLevel(void);
typedef enum
{
WIPELOOP_RUNWIPE,

View file

@ -61,6 +61,7 @@ EXPORT void HWRAPI(FlushScreenTextures) (void);
EXPORT void HWRAPI(StartScreenWipe) (void);
EXPORT void HWRAPI(EndScreenWipe) (void);
EXPORT void HWRAPI(DoScreenWipe) (void);
EXPORT void HWRAPI(MakeIntermissionBG) (void);
EXPORT void HWRAPI(DrawIntermissionBG) (void);
EXPORT void HWRAPI(MakeScreenTexture) (void);
EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize);
@ -114,6 +115,7 @@ struct hwdriver_s
StartScreenWipe pfnStartScreenWipe;
EndScreenWipe pfnEndScreenWipe;
DoScreenWipe pfnDoScreenWipe;
MakeIntermissionBG pfnMakeIntermissionBG;
DrawIntermissionBG pfnDrawIntermissionBG;
MakeScreenTexture pfnMakeScreenTexture;
RenderVhsEffect pfnRenderVhsEffect;

View file

@ -6431,7 +6431,6 @@ void HWR_DoPostProcessor(player_t *player)
}
// Capture the screen for intermission and screen waving
if(gamestate != GS_INTERMISSION)
HWD.pfnMakeScreenTexture();
if (r_splitscreen) // Not supported in splitscreen - someone want to add support?
@ -6477,10 +6476,6 @@ void HWR_DoPostProcessor(player_t *player)
}
}
HWD.pfnPostImgRedraw(v);
// Capture the screen again for screen waving on the intermission
if(gamestate != GS_INTERMISSION)
HWD.pfnMakeScreenTexture();
}
// Flipping of the screen isn't done here anymore
}
@ -6497,6 +6492,11 @@ void HWR_EndScreenWipe(void)
HWD.pfnEndScreenWipe();
}
void HWR_MakeIntermissionBG(void)
{
HWD.pfnMakeIntermissionBG();
}
void HWR_DrawIntermissionBG(void)
{
HWD.pfnDrawIntermissionBG();

View file

@ -64,6 +64,7 @@ INT32 HWR_GetTextureUsed(void);
void HWR_DoPostProcessor(player_t *player);
void HWR_StartScreenWipe(void);
void HWR_EndScreenWipe(void);
void HWR_MakeIntermissionBG(void);
void HWR_DrawIntermissionBG(void);
void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum);
void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum);

View file

@ -94,6 +94,7 @@ static GLint viewport[4];
// These need to start at 0 and be set to their number, and be reset to 0 when deleted so that intel GPUs
// can know when the textures aren't there, as textures are always considered resident in their virtual memory
static GLuint screentexture = 0;
static GLuint intermissionbg = 0;
static GLuint startScreenWipe = 0;
static GLuint endScreenWipe = 0;
static GLuint finalScreenTexture = 0;
@ -3264,24 +3265,25 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2])
EXPORT void HWRAPI(FlushScreenTextures) (void)
{
pglDeleteTextures(1, &screentexture);
pglDeleteTextures(1, &intermissionbg);
pglDeleteTextures(1, &startScreenWipe);
pglDeleteTextures(1, &endScreenWipe);
pglDeleteTextures(1, &finalScreenTexture);
screentexture = 0;
intermissionbg = 0;
startScreenWipe = 0;
endScreenWipe = 0;
finalScreenTexture = 0;
}
// Create Screen to fade from
EXPORT void HWRAPI(StartScreenWipe) (void)
static void GetScreenTexture(GLuint *texnum)
{
boolean firstTime = (startScreenWipe == 0);
boolean firstTime = (*texnum == 0);
// Create screen texture
if (firstTime)
pglGenTextures(1, &startScreenWipe);
pglBindTexture(GL_TEXTURE_2D, startScreenWipe);
pglGenTextures(1, texnum);
pglBindTexture(GL_TEXTURE_2D, *texnum);
if (firstTime)
{
@ -3294,33 +3296,25 @@ EXPORT void HWRAPI(StartScreenWipe) (void)
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = startScreenWipe;
tex_downloaded = *texnum;
}
// Create Screen to fade from
EXPORT void HWRAPI(StartScreenWipe) (void)
{
GetScreenTexture(&startScreenWipe);
}
// Create Screen to fade to
EXPORT void HWRAPI(EndScreenWipe)(void)
{
boolean firstTime = (endScreenWipe == 0);
GetScreenTexture(&endScreenWipe);
}
// Create screen texture
if (firstTime)
pglGenTextures(1, &endScreenWipe);
pglBindTexture(GL_TEXTURE_2D, endScreenWipe);
if (firstTime)
EXPORT void HWRAPI(MakeIntermissionBG) (void)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
GetScreenTexture(&intermissionbg);
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = endScreenWipe;
}
// Draw the last scene under the intermission
EXPORT void HWRAPI(DrawIntermissionBG)(void)
@ -3354,14 +3348,14 @@ EXPORT void HWRAPI(DrawIntermissionBG)(void)
pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
pglBindTexture(GL_TEXTURE_2D, screentexture);
pglBindTexture(GL_TEXTURE_2D, intermissionbg);
pglColor4ubv(white);
pglTexCoordPointer(2, GL_FLOAT, 0, fix);
pglVertexPointer(3, GL_FLOAT, 0, screenVerts);
pglDrawArrays(GL_TRIANGLE_FAN, 0, 4);
tex_downloaded = screentexture;
tex_downloaded = intermissionbg;
}
// Do screen fades!
@ -3451,25 +3445,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void)
// Create a texture from the screen.
EXPORT void HWRAPI(MakeScreenTexture) (void)
{
boolean firstTime = (screentexture == 0);
// Create screen texture
if (firstTime)
pglGenTextures(1, &screentexture);
pglBindTexture(GL_TEXTURE_2D, screentexture);
if (firstTime)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = screentexture;
GetScreenTexture(&screentexture);
}
EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize)
@ -3554,25 +3530,7 @@ EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updisto
EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
{
boolean firstTime = (finalScreenTexture == 0);
// Create screen texture
if (firstTime)
pglGenTextures(1, &finalScreenTexture);
pglBindTexture(GL_TEXTURE_2D, finalScreenTexture);
if (firstTime)
{
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Clamp2D(GL_TEXTURE_WRAP_S);
Clamp2D(GL_TEXTURE_WRAP_T);
pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
}
else
pglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
tex_downloaded = finalScreenTexture;
GetScreenTexture(&finalScreenTexture);
}
EXPORT void HWRAPI(DrawScreenFinalTexture)(int width, int height)

View file

@ -156,6 +156,7 @@ boolean draftingactive;
UINT16 bossdisabled;
boolean stoppedclock;
boolean levelloading;
boolean levelloaded = false;
UINT8 levelfadecol;
virtres_t *curmapvirt;
@ -9016,6 +9017,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
levelloading = false;
}
// the level is THOROUGHLY loaded now...
// set this before starting the titlecard though
levelloaded = true;
if (reloadinggamestate == false)
{
if (rendermode != render_none)
@ -9109,6 +9114,12 @@ void P_PostLoadLevel(void)
TracyCZoneEnd(__zone);
}
void P_UnloadLevel(void)
{
// this doesn't actually free any memory. i'm not messing with that...
// just clear the level loaded flag
levelloaded = false;
}
//
// P_RunSOC

View file

@ -33,6 +33,8 @@ extern mapthing_t *deathmatchstarts[MAX_DM_STARTS];
extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
extern boolean levelloading;
extern boolean levelloaded; // is there an actual level loaded? for intermission
// (i.e. is it safe to call D_RenderLevel?)
extern UINT8 levelfadecol;
extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame
@ -85,6 +87,7 @@ void P_PostLoadLevel(void);
#ifdef HWRENDER
void HWR_LoadLevel(void);
#endif
void P_UnloadLevel(void);
boolean P_AddWadFile(const char *wadfilename, wadcompat_t compat);
#define MAPRET_ADDED (1)

View file

@ -328,6 +328,9 @@ void SCR_SetMode(void)
SCR_SetDrawFuncs();
// Shoot! The screen texture was flushed!
Y_CleanupScreenBuffer();
// set the apprpriate drawer for the sky (tall or INT16)
setmodeneeded = 0;
setrenderneeded = 0;
@ -382,12 +385,6 @@ void SCR_Recalc(void)
// vid.recalc lasts only for the next refresh...
con_recalc = true;
am_recalc = true;
#ifdef HWRENDER
// Shoot! The screen texture was flushed!
if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION))
usebuffer = false;
#endif
}
// Check for screen cmd-line parms: to force a resolution.

View file

@ -100,6 +100,7 @@ void *hwSym(const char *funcName,void *handle)
GETFUNC(StartScreenWipe);
GETFUNC(EndScreenWipe);
GETFUNC(DoScreenWipe);
GETFUNC(MakeIntermissionBG);
GETFUNC(DrawIntermissionBG);
GETFUNC(MakeScreenTexture);
GETFUNC(RenderVhsEffect);

View file

@ -1784,6 +1784,7 @@ static void Impl_InitOpenGL(void)
*(void**)&HWD.pfnEndScreenWipe = hwSym("EndScreenWipe",NULL);
*(void**)&HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL);
*(void**)&HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL);
*(void**)&HWD.pfnMakeIntermissionBG=hwSym("MakeIntermissionBG",NULL);
*(void**)&HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL);
*(void**)&HWD.pfnRenderVhsEffect = hwSym("RenderVhsEffect",NULL);
*(void**)&HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL);

View file

@ -86,25 +86,13 @@ static y_data data;
// graphics
static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK
static patch_t *interpic = NULL; // custom picture defined in map header
static boolean usetile;
static INT32 timer;
typedef struct
{
INT32 source_width, source_height;
INT32 source_bpp, source_rowbytes;
UINT8 *source_picture;
INT32 target_width, target_height;
INT32 target_bpp, target_rowbytes;
UINT8 *target_picture;
} y_buffer_t;
boolean usebuffer = false;
static boolean useinterpic;
static INT32 powertype = PWRLV_DISABLED;
static y_buffer_t *y_buffer;
static UINT8 *y_screenbuffer;
static INT32 intertic;
static INT32 endtic = -1;
@ -118,7 +106,6 @@ static huddrawlist_h luahuddrawlist_vote;
static void Y_FollowIntermission(void);
static void Y_RescaleScreenBuffer(void);
static void Y_UnloadData(void);
// SRB2Kart: voting stuff
@ -346,63 +333,27 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
//
// Y_ConsiderScreenBuffer
//
// Can we copy the current screen to a buffer?
// G: Yes we can, because now D_Display forces a redraw for the sake of the intermission background
// Draw a frame, and save it for the intermission background.
//
void Y_ConsiderScreenBuffer(void)
{
if (y_buffer == NULL)
y_buffer = Z_Calloc(sizeof(y_buffer_t), PU_STATIC, NULL);
else
return;
Y_CleanupScreenBuffer();
y_buffer->source_width = vid.width;
y_buffer->source_height = vid.height;
y_buffer->source_bpp = vid.bpp;
y_buffer->source_rowbytes = vid.rowbytes;
y_buffer->source_picture = ZZ_Alloc(y_buffer->source_width*vid.bpp * y_buffer->source_height);
VID_BlitLinearScreen(screens[0], y_buffer->source_picture, vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
if (!D_RenderLevel())
return; // we need a frame to copy!
// Make the rescaled screen buffer
Y_RescaleScreenBuffer();
}
//
// Y_RescaleScreenBuffer
//
// Write the rescaled source picture, to the destination picture that has the current screen's resolutions.
//
static void Y_RescaleScreenBuffer(void)
if (rendermode == render_soft)
{
INT32 sx, sy; // source
INT32 dx, dy; // dest
fixed_t scalefac, yscalefac;
fixed_t rowfrac, colfrac;
UINT8 *dest;
// Who knows?
if (y_buffer == NULL)
return;
if (y_buffer->target_picture)
Z_Free(y_buffer->target_picture);
y_buffer->target_width = vid.width;
y_buffer->target_height = vid.height;
y_buffer->target_rowbytes = vid.rowbytes;
y_buffer->target_bpp = vid.bpp;
y_buffer->target_picture = ZZ_Alloc(y_buffer->target_width*vid.bpp * y_buffer->target_height);
dest = y_buffer->target_picture;
scalefac = FixedDiv(y_buffer->target_width*FRACUNIT, y_buffer->source_width*FRACUNIT);
yscalefac = FixedDiv(y_buffer->target_height*FRACUNIT, y_buffer->source_height*FRACUNIT);
rowfrac = FixedDiv(FRACUNIT, yscalefac);
colfrac = FixedDiv(FRACUNIT, scalefac);
for (sy = 0, dy = 0; sy < (y_buffer->source_height << FRACBITS) && dy < y_buffer->target_height; sy += rowfrac, dy++)
for (sx = 0, dx = 0; sx < (y_buffer->source_width << FRACBITS) && dx < y_buffer->target_width; sx += colfrac, dx += y_buffer->target_bpp)
dest[(dy * y_buffer->target_rowbytes) + dx] = y_buffer->source_picture[((sy>>FRACBITS) * y_buffer->source_width) + (sx>>FRACBITS)];
y_screenbuffer = Z_Malloc(vid.width*vid.bpp * vid.height, PU_STATIC, NULL);
VID_BlitLinearScreen(screens[0], y_screenbuffer, vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
}
#ifdef HWRENDER
else if (rendermode == render_opengl)
{
y_screenbuffer = Z_Malloc(0, PU_STATIC, NULL);
HWR_MakeIntermissionBG();
}
#endif
}
//
@ -413,17 +364,11 @@ static void Y_RescaleScreenBuffer(void)
void Y_CleanupScreenBuffer(void)
{
// Who knows?
if (y_buffer == NULL)
if (y_screenbuffer == NULL)
return;
if (y_buffer->target_picture)
Z_Free(y_buffer->target_picture);
if (y_buffer->source_picture)
Z_Free(y_buffer->source_picture);
Z_Free(y_buffer);
y_buffer = NULL;
Z_Free(y_screenbuffer);
y_screenbuffer = NULL;
}
//
@ -439,37 +384,32 @@ void Y_IntermissionDrawer(void)
if (intertype == int_none || rendermode == render_none)
return;
if (!useinterpic && y_screenbuffer == NULL
#ifdef HWRENDER
// TODO resolution changes breaks the screentexture capture, I have no clue why
&& rendermode != render_opengl
#endif
)
Y_ConsiderScreenBuffer();
if (useinterpic)
V_DrawScaledPatch(0, 0, 0, interpic);
else if (!usetile)
else if (y_screenbuffer != NULL)
{
if (rendermode == render_soft && usebuffer)
{
// no y_buffer
if (y_buffer == NULL)
V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
else
{
// Maybe the resolution changed?
if ((y_buffer->target_width != vid.width) || (y_buffer->target_height != vid.height))
Y_RescaleScreenBuffer();
// Blit the already-scaled screen buffer to the current screen
VID_BlitLinearScreen(y_buffer->target_picture, screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
}
}
if (rendermode == render_soft)
VID_BlitLinearScreen(y_screenbuffer, screens[0], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes);
#ifdef HWRENDER
else if (rendermode != render_soft && usebuffer)
else if (rendermode == render_opengl)
HWR_DrawIntermissionBG();
#endif
}
else if (VoteScreen.bgpatch)
{
fixed_t hs = vid.width * FRACUNIT / BASEVIDWIDTH;
fixed_t vs = vid.height * FRACUNIT / BASEVIDHEIGHT;
V_DrawStretchyFixedPatch(0, 0, hs, vs, V_NOSCALEPATCH, VoteScreen.bgpatch, NULL);
}
}
else if (bgtile)
else // in case nothing else works...
V_DrawPatchFill(bgtile);
if (renderisnewtic)
@ -482,7 +422,7 @@ void Y_IntermissionDrawer(void)
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
if (usebuffer) // Fade everything out
// Fade everything out
V_DrawFadeScreen(0xFF00, 22);
if (!r_splitscreen)
@ -1011,12 +951,8 @@ void Y_StartIntermission(void)
K_CashInPowerLevels();
}
//if (intertype == int_race || intertype == int_battle)
{
//bgtile = W_CachePatchName("SRB2BACK", PU_STATIC);
usetile = useinterpic = false;
usebuffer = true;
}
bgtile = W_CachePatchName("SRB2BACK", PU_STATIC);
useinterpic = false;
Automate_Run(AEV_INTERMISSIONSTART);
}
@ -1038,7 +974,6 @@ void Y_EndIntermission(void)
endtic = -1;
sorttic = -1;
intertype = int_none;
usebuffer = false;
}
//