Merge branch 'clip-sprites-optimize' into 'master'

Drawseg clipping optimized, from prboom-plus

See merge request KartKrew/Kart-Public!304
This commit is contained in:
Sal 2022-08-28 09:22:49 +00:00
commit 4555f3240e
2 changed files with 223 additions and 99 deletions

View file

@ -80,6 +80,33 @@ static spriteframe_t sprtemp[64];
static size_t maxframe;
static const char *spritename;
//
// Clipping against drawsegs optimization, from prboom-plus
//
// TODO: This should be done with proper subsector pass through
// sprites which would ideally remove the need to do it at all.
// Unfortunately, SRB2's drawing loop has lots of annoying
// changes from Doom for portals, which make it hard to implement.
typedef struct drawseg_xrange_item_s
{
INT16 x1, x2;
drawseg_t *user;
} drawseg_xrange_item_t;
typedef struct drawsegs_xrange_s
{
drawseg_xrange_item_t *items;
INT32 count;
} drawsegs_xrange_t;
#define DS_RANGES_COUNT 3
static drawsegs_xrange_t drawsegs_xranges[DS_RANGES_COUNT];
static drawseg_xrange_item_t *drawsegs_xrange;
static size_t drawsegs_xrange_size = 0;
static INT32 drawsegs_xrange_count = 0;
// ==========================================================================
//
// Sprite loading routines: support sprites in pwad, dehacked sprite renaming,
@ -548,7 +575,7 @@ void R_DelSpriteDefs(UINT16 wadnum)
//
// GAME FUNCTIONS
//
static UINT32 visspritecount;
UINT32 visspritecount;
static UINT32 clippedvissprites;
static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
@ -2274,10 +2301,7 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr)
// R_ClipSprites
// Clips vissprites without drawing, so that portals can work. -Red
void R_ClipSprites(void)
{
vissprite_t *spr;
for (;clippedvissprites < visspritecount; clippedvissprites++)
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2)
{
drawseg_t *ds;
INT32 x;
@ -2287,10 +2311,10 @@ void R_ClipSprites(void)
fixed_t lowscale;
INT32 silhouette;
spr = R_GetVisSprite(clippedvissprites);
for (x = spr->x1; x <= spr->x2; x++)
for (x = x1; x <= x2; x++)
{
spr->clipbot[x] = spr->cliptop[x] = -2;
}
// Scan drawsegs from end to start for obscuring segs.
// The first drawseg that has a greater scale
@ -2299,19 +2323,23 @@ void R_ClipSprites(void)
// Pointer check was originally nonportable
// and buggy, by going past LEFT end of array:
// for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code
for (ds = ds_p; ds-- > drawsegs ;)
// e6y: optimization
if (drawsegs_xrange_size)
{
const drawseg_xrange_item_t *last = &drawsegs_xrange[drawsegs_xrange_count - 1];
drawseg_xrange_item_t *curr = &drawsegs_xrange[-1];
while (++curr <= last)
{
// determine if the drawseg obscures the sprite
if (ds->x1 > spr->x2 ||
ds->x2 < spr->x1 ||
(!ds->silhouette
&& !ds->maskedtexturecol))
if (curr->x1 > spr->x2 || curr->x2 < spr->x1)
{
// does not cover sprite
continue;
}
ds = curr->user;
if (ds->portalpass > 0 && ds->portalpass <= portalrender)
continue; // is a portal
@ -2375,6 +2403,7 @@ void R_ClipSprites(void)
}
}
}
}
//SoM: 3/17/2000: Clip sprites in water.
if (spr->heightsec != -1) // only things in specially marked sectors
{
@ -2457,6 +2486,91 @@ void R_ClipSprites(void)
spr->cliptop[x] = (INT16)con_clipviewtop;
}
}
void R_ClipSprites(void)
{
const size_t maxdrawsegs = ds_p - drawsegs;
const INT32 cx = viewwidth / 2;
drawseg_t* ds;
INT32 i;
// e6y
// Reducing of cache misses in the following R_DrawSprite()
// Makes sense for scenes with huge amount of drawsegs.
// ~12% of speed improvement on epic.wad map05
for (i = 0; i < DS_RANGES_COUNT; i++)
{
drawsegs_xranges[i].count = 0;
}
if (visspritecount - clippedvissprites <= 0)
{
return;
}
if (drawsegs_xrange_size < maxdrawsegs)
{
drawsegs_xrange_size = 2 * maxdrawsegs;
for (i = 0; i < DS_RANGES_COUNT; i++)
{
drawsegs_xranges[i].items = Z_Realloc(
drawsegs_xranges[i].items,
drawsegs_xrange_size * sizeof(drawsegs_xranges[i].items[0]),
PU_STATIC, NULL
);
}
}
for (ds = ds_p; ds-- > drawsegs;)
{
if (ds->silhouette || ds->maskedtexturecol)
{
drawsegs_xranges[0].items[drawsegs_xranges[0].count].x1 = ds->x1;
drawsegs_xranges[0].items[drawsegs_xranges[0].count].x2 = ds->x2;
drawsegs_xranges[0].items[drawsegs_xranges[0].count].user = ds;
// e6y: ~13% of speed improvement on sunder.wad map10
if (ds->x1 < cx)
{
drawsegs_xranges[1].items[drawsegs_xranges[1].count] =
drawsegs_xranges[0].items[drawsegs_xranges[0].count];
drawsegs_xranges[1].count++;
}
if (ds->x2 >= cx)
{
drawsegs_xranges[2].items[drawsegs_xranges[2].count] =
drawsegs_xranges[0].items[drawsegs_xranges[0].count];
drawsegs_xranges[2].count++;
}
drawsegs_xranges[0].count++;
}
}
for (; clippedvissprites < visspritecount; clippedvissprites++)
{
vissprite_t *spr = R_GetVisSprite(clippedvissprites);
if (spr->x2 < cx)
{
drawsegs_xrange = drawsegs_xranges[1].items;
drawsegs_xrange_count = drawsegs_xranges[1].count;
}
else if (spr->x1 >= cx)
{
drawsegs_xrange = drawsegs_xranges[2].items;
drawsegs_xrange_count = drawsegs_xranges[2].count;
}
else
{
drawsegs_xrange = drawsegs_xranges[0].items;
drawsegs_xrange_count = drawsegs_xranges[0].count;
}
R_ClipVisSprite(spr, spr->x1, spr->x2);
}
}
//

View file

@ -58,7 +58,6 @@ void R_DelSpriteDefs(UINT16 wadnum);
void R_AddSprites(sector_t *sec, INT32 lightlevel);
void R_InitSprites(void);
void R_ClearSprites(void);
void R_ClipSprites(void);
void R_DrawMasked(void);
// -----------
@ -163,6 +162,17 @@ typedef struct vissprite_s
fixed_t thingscale;
} vissprite_t;
extern UINT32 visspritecount;
void R_ClipSprites(void);
void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2);
UINT8 *R_GetSpriteTranslation(vissprite_t *vis);
// ----------
// DRAW NODES
// ----------
// A drawnode is something that points to a 3D floor, 3D side, or masked
// middle texture. This is used for sorting with sprites.
typedef struct drawnode_s