Draw full-screen backgrounds without loading them

This commit is contained in:
Lephenixnoir 2021-09-17 17:33:26 +02:00
parent fe2519fc57
commit ac6f730bed
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
9 changed files with 171 additions and 13 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
build-cg/
build-sdl2/
wad/
wad-edited/

66
cgdoom/cgdoom-frag.c Normal file
View File

@ -0,0 +1,66 @@
#include "cgdoom-frag.h"
#include "os.h"
#include "w_wad.h"
int CGD_Frag_Map(const char *lumpname, CGD_Frag *frag)
{
int lump = W_CheckNumForName(lumpname);
if(lump < 0)
return 1;
lumpinfo_t *l = &lumpinfo[lump];
int size = l->size;
int position = l->position;
int f = 0;
while(f < CGD_FRAG_ESTIMATE && size > 0) {
int found = FindInFlash(&frag->data[f], size, position);
frag->size[f] = found;
size -= found;
position += found;
f++;
}
if(size) {
I_Error("CGD_Frag_Map: failed on '%s' (size=%d, offset=%d), could only"
" obtain %d", lumpname, l->size, l->position, l->size - size);
return 1;
}
frag->size[f] = 0;
return 0;
}
byte CGD_Frag_u8(CGD_Frag const *frag, int offset)
{
int f = 0;
while(frag->size[f] != 0 && offset >= frag->size[f]) {
offset -= frag->size[f];
f++;
}
if(frag->size[f] == 0)
return 0; /* read out-of-bounds */
const byte *data = frag->data[f];
return data[offset];
}
short CGD_Frag_i16LE(CGD_Frag const *frag, int offset)
{
byte b1 = CGD_Frag_u8(frag, offset);
byte b2 = CGD_Frag_u8(frag, offset + 1);
return (b2 << 8) | b1;
}
int CGD_Frag_i32LE(CGD_Frag const *frag, int offset)
{
byte b1 = CGD_Frag_u8(frag, offset);
byte b2 = CGD_Frag_u8(frag, offset + 1);
byte b3 = CGD_Frag_u8(frag, offset + 2);
byte b4 = CGD_Frag_u8(frag, offset + 3);
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}

44
cgdoom/cgdoom-frag.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef CGDOOM_FRAG_H
#define CGDOOM_FRAG_H
#include "doomtype.h"
/* CGDoom's abstracted access to fragmented lumps
In CGDoom, the main factor limiting compatibility is the amount of available
heap. Therefore, it is beneficial to reduce the pressure on the heap by
using lumps directly from ROM. For non-fragmented lumps it's mostly
straightforward and only involves alignment independence, but for fragmented
lumps it's quite more involved.
This header offers an interface that can be used to access fragmented lumps
in ROM by deferring every access to an intermediate function that looks up
the proper lump fragment.
This is /very/ slow, without a doubt, but speed is not always a limiting
factor. One of the main uses for this is displaying full-screen patches
without loading them, which occurs in the main menu and in the intermission
screens. The latter is the main focus, since the intermission picture needs
to be loaded on top of level data, which may leave the heap both full and
fragmented.
This interface exists just in case it is be useful for other lumps. */
/* Maximum number of fragments that we expect in a lump (+1 for terminator) */
#define CGD_FRAG_ESTIMATE 33
/* Fragmented lump lookup table */
typedef struct {
const void *data[CGD_FRAG_ESTIMATE];
int size[CGD_FRAG_ESTIMATE+1];
} CGD_Frag;
/* Compute the lookup table for a lump; if successful, returns 0 */
int CGD_Frag_Map(const char *lumpname, CGD_Frag *frag);
/* Read different types within the lump */
byte CGD_Frag_u8(CGD_Frag const *frag, int offset);
short CGD_Frag_i16LE(CGD_Frag const *frag, int offset);
int CGD_Frag_i32LE(CGD_Frag const *frag, int offset);
#endif /* CGDOOM_FRAG_H */

View File

@ -314,7 +314,8 @@ void D_PageTicker (void)
//
void D_PageDrawer (void)
{
V_DrawPatch (0,0, 0, (const patch_t *)W_CacheLumpNameConst(pagename, PU_CACHE));
// V_DrawPatch (0,0, 0, (const patch_t *)W_CacheLumpNameConst(pagename, PU_CACHE));
V_DrawFullscreenPatchFragmented(0, pagename);
}

View File

@ -654,18 +654,22 @@ void F_Drawer (void)
{
case 1:
if ( gamemode == retail )
V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("CREDIT",PU_CACHE));
// V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("CREDIT",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "CREDIT");
else
V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("HELP2",PU_CACHE));
// V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("HELP2",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "HELP2");
break;
case 2:
V_DrawPatch(0,0,0,(const patch_t*)W_CacheLumpNameConst("VICTORY2",PU_CACHE));
// V_DrawPatch(0,0,0,(const patch_t*)W_CacheLumpNameConst("VICTORY2",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "VICTORY2");
break;
case 3:
F_BunnyScroll ();
break;
case 4:
V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("ENDPIC",PU_CACHE));
// V_DrawPatch (0,0,0,(const patch_t*)W_CacheLumpNameConst("ENDPIC",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "ENDPIC");
break;
}
}

View File

@ -548,12 +548,14 @@ void M_DrawReadThis1(void)
switch ( gamemode )
{
case commercial:
V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP",PU_CACHE));
// V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "HELP");
break;
case shareware:
case registered:
case retail:
V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP1",PU_CACHE));
// V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP1",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "HELP1");
break;
default:
break;
@ -575,11 +577,13 @@ void M_DrawReadThis2(void)
case retail:
case commercial:
// This hack keeps us from having to change menus.
V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("CREDIT",PU_CACHE));
// V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("CREDIT",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "CREDIT");
break;
case shareware:
case registered:
V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP2",PU_CACHE));
// V_DrawPatchDirect (0,0,0,W_CacheLumpNamePatch("HELP2",PU_CACHE));
V_DrawFullscreenPatchFragmented(0, "HELP2");
break;
default:
break;

View File

@ -26,7 +26,7 @@
//static const char
#include "cgdoom-frag.h"
#include "i_system.h"
#include "r_local.h"
@ -39,6 +39,9 @@
#include "v_video.h"
#include "z_zone.h"
#include "w_wad.h"
// Each screen is [SCREENWIDTH*SCREENHEIGHT];
@ -239,6 +242,38 @@ void V_DrawPatch(int x,int y,int scrn,const patch_t* patch)
}
}
//
// V_DrawFullscreenPatchFragmented
// Draws a full-screen opaque patch without loading it to RAM, even if it's
// fragmented. This function is useful in avoiding loading ~66 kB as a single
// lump when full-screen images are used, which occasionally fails due to
// fragmentation.
//
void V_DrawFullscreenPatchFragmented(int scrn, const char *lumpname)
{
CGD_Frag patch;
if (CGD_Frag_Map(lumpname, &patch)) {
V_DrawPatch(0, 0, scrn, W_CacheLumpNamePatch(lumpname, PU_CACHE));
return;
}
byte *dest = screens[scrn];
short w = CGD_Frag_i16LE(&patch, offsetof(patch_t, widthLE));
short h = CGD_Frag_i16LE(&patch, offsetof(patch_t, heightLE));
if (!scrn)
V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
for (int x = 0; x < w; x++) {
int offset = CGD_Frag_i32LE(&patch, offsetof(patch_t, columnofsLE) + 4*x);
int h0 = CGD_Frag_u8(&patch, offset+1);
for (int y = 0; y < h; y++) {
dest[SCREENWIDTH * y + x] = CGD_Frag_u8(&patch, offset + y+3+3*(y>=h0));
}
}
}
//
// V_DrawPatchFlipped
// Masks a column based masked pic to the screen.

View File

@ -74,6 +74,8 @@ V_CopyRect
void V_DrawPatch(int x,int y, int scrn,const patch_t* patch);
#define V_DrawPatchDirect(x,y,scrn,patch ) V_DrawPatch(x,y,scrn,patch)
/* CGDoom: render opaque full-screen path without loading it */
void V_DrawFullscreenPatchFragmented(int scrn, const char *lumpname);
// Draw a linear block of pixels into the view buffer.
void V_DrawBlock( int x, int y,int scrn,int width,int height,const byte* src );

View File

@ -338,7 +338,7 @@ static int NUMCMAPS;
//
// background (map of levels).
static const patch_t* bg;
// static const patch_t* bg;
// You Are Here graphic
static const patch_t* yah[2];
@ -986,8 +986,9 @@ static void WI_loadData(void)
}
// background
bg = W_CacheLumpNamePatch(name, PU_CACHE);
V_DrawPatch(0, 0, 1, bg);
// bg = W_CacheLumpNamePatch(name, PU_CACHE);
// V_DrawPatch(0, 0, 1, bg);
V_DrawFullscreenPatchFragmented(1, name);
// UNUSED unsigned char *pic = screens[1];
// if (gamemode == commercial)