From ab4509123d8c57127fa1d0d63a71e5de5504b4d3 Mon Sep 17 00:00:00 2001 From: chromaticpipe2 <chromaticpipe@gmail.com> Date: Tue, 25 Mar 2025 10:23:36 -0500 Subject: [PATCH] Render precip through blockmap instead of BSP --- src/hardware/hw_main.c | 40 ++++++++++++++++++++++++++++----- src/p_local.h | 1 + src/p_maputl.c | 51 ++++++++++++++++++++++++++++++++---------- src/p_mobj.h | 5 +++++ src/p_setup.c | 10 ++++++++- src/r_defs.h | 1 - src/r_main.c | 30 +++++++++++++++++++++++++ src/r_main.h | 2 ++ src/r_things.c | 45 +++++++++++++++++++++++++++---------- src/r_things.h | 4 ++-- src/tables.h | 5 +++++ 11 files changed, 161 insertions(+), 33 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3279a6168..0ca6ac489 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -55,6 +55,7 @@ struct hwdriver_s hwdriver; // ========================================================================== static void HWR_AddSprites(sector_t *sec); +static void HWR_AddPrecipitationSprites(void); static void HWR_ProjectSprite(mobj_t *thing); static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); static void HWR_ProjectBoundingBox(mobj_t *thing); @@ -4318,7 +4319,6 @@ static UINT8 sectorlight; static void HWR_AddSprites(sector_t *sec) { mobj_t *thing; - precipmobj_t *precipthing; fixed_t limit_dist, hoop_limit_dist; // BSP is traversed by subsector. @@ -4350,18 +4350,45 @@ static void HWR_AddSprites(sector_t *sec) HWR_ProjectBoundingBox(thing); } } +} + +// -------------------------------------------------------------------------- +// HWR_AddPrecipitationSprites +// This renders through the blockmap instead of BSP to avoid +// iterating a huge amount of precipitation sprites in sectors +// that are beyond drawdist. +// -------------------------------------------------------------------------- +static void HWR_AddPrecipitationSprites(void) +{ + const fixed_t drawdist = ((fixed_t)cv_drawdist_precip.value << FRACBITS); + + INT32 xl, xh, yl, yh, bx, by; + precipmobj_t *th; // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off - if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) + if (drawdist == 0) + { + return; + } + + R_GetRenderBlockMapDimensions(drawdist, &xl, &xh, &yl, &yh); + + for (bx = xl; bx <= xh; bx++) { - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) + for (by = yl; by <= yh; by++) { - if (R_PrecipThingVisible(precipthing, limit_dist)) - HWR_ProjectPrecipitationSprite(precipthing); + for (th = precipblocklinks[(by * bmapwidth) + bx]; th; th = th->bnext) + { + if (R_PrecipThingVisible(th)) + { + HWR_ProjectPrecipitationSprite(th); + } + } } } } + // -------------------------------------------------------------------------- // HWR_ProjectSprite // Generates a vissprite for a thing if it might be visible. @@ -5612,8 +5639,11 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWR_RenderBSPNode((INT32)numnodes-1); + HWR_AddPrecipitationSprites(); + PS_STOP_TIMING(ps_bsptime); + if (cv_glbatching.value) HWR_RenderBatches(); diff --git a/src/p_local.h b/src/p_local.h index 85a31cf89..4e2d84766 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -460,6 +460,7 @@ extern INT32 bmapheight; // in mapblocks extern fixed_t bmaporgx; extern fixed_t bmaporgy; // origin of block map extern blocknode_t **blocklinks; // for thing chains +extern precipmobj_t **precipblocklinks; // special blockmap for precip rendering // // P_INTER diff --git a/src/p_maputl.c b/src/p_maputl.c index 4c7b95927..1197f5f49 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -804,15 +804,48 @@ void P_UnsetThingPosition(mobj_t *thing) void P_UnsetPrecipThingPosition(precipmobj_t *thing) { - precipmobj_t **sprev = thing->sprev; - precipmobj_t *snext = thing->snext; - if ((*sprev = snext) != NULL) // unlink from sector list - snext->sprev = sprev; + precipmobj_t **bprev = thing->bprev; + precipmobj_t *bnext = thing->bnext; + if (bprev && (*bprev = bnext) != NULL) // unlink from block map + bnext->bprev = bprev; + precipsector_list = thing->touching_sectorlist; thing->touching_sectorlist = NULL; //to be restored by P_SetPrecipThingPosition } +static void P_LinkToPrecipBlockMap(precipmobj_t *thing, precipmobj_t **bmap) +{ + const INT32 blockx = (unsigned)(thing->x - bmaporgx) >> MAPBLOCKSHIFT; + const INT32 blocky = (unsigned)(thing->y - bmaporgy) >> MAPBLOCKSHIFT; + + if (blockx >= 0 && blockx < bmapwidth + && blocky >= 0 && blocky < bmapheight) + { + // killough 8/11/98: simpler scheme using + // pointer-to-pointer prev pointers -- + // allows head nodes to be treated like everything else + + precipmobj_t **link = &bmap[(blocky * bmapwidth) + blockx]; + precipmobj_t *bnext = *link; + + thing->bnext = bnext; + + if (bnext != NULL) + bnext->bprev = &thing->bnext; + + thing->bprev = link; + *link = thing; + } + else // thing is off the map + { + thing->bnext = NULL, thing->bprev = NULL; + } +} + + + + // // P_SetThingPosition // Links a thing into both a block and a subsector @@ -962,18 +995,12 @@ void P_SetUnderlayPosition(mobj_t *thing) void P_SetPrecipitationThingPosition(precipmobj_t *thing) { - subsector_t *ss = thing->subsector = R_PointInSubsector(thing->x, thing->y); - - precipmobj_t **link = &ss->sector->preciplist; - precipmobj_t *snext = *link; - if ((thing->snext = snext) != NULL) - snext->sprev = &thing->snext; - thing->sprev = link; - *link = thing; + thing->subsector = R_PointInSubsector(thing->x, thing->y); P_CreatePrecipSecNodeList(thing, thing->x, thing->y); thing->touching_sectorlist = precipsector_list; // Attach to Thing's precipmobj_t precipsector_list = NULL; // clear for next time + P_LinkToPrecipBlockMap(thing, precipblocklinks); } // diff --git a/src/p_mobj.h b/src/p_mobj.h index fef6713a4..eb383723b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -468,6 +468,11 @@ typedef struct precipmobj_s struct subsector_s *subsector; // Subsector the mobj resides in. + // Links in blocks (if needed). + // The blockmap is only used by precip to render. + struct precipmobj_s *bnext; + struct precipmobj_s **bprev; // killough 8/11/98: change to ptr-to-ptr + // The closest interval over all contacted sectors (or things). fixed_t floorz; // Nearest floor below. fixed_t ceilingz; // Nearest ceiling above. diff --git a/src/p_setup.c b/src/p_setup.c index d8e4e5d67..27b8730c2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -139,6 +139,7 @@ INT32 *blockmaplump; // Big blockmap fixed_t bmaporgx, bmaporgy; // for thing chains blocknode_t **blocklinks; +precipmobj_t **precipblocklinks; // REJECT // For fast sight rejection. @@ -1024,7 +1025,7 @@ static void P_InitializeSector(sector_t *ss) ss->floorspeed = ss->ceilspeed = 0; - ss->preciplist = NULL; + ss->touching_preciplist = NULL; ss->f_slope = NULL; @@ -3875,6 +3876,10 @@ static boolean P_LoadBlockMap(UINT8 *data, size_t count) // haleyjd 2/22/06: setup polyobject blockmap count = sizeof(*polyblocklinks) * bmapwidth * bmapheight; polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL); + + count = sizeof (*precipblocklinks)* bmapwidth*bmapheight; + precipblocklinks = Z_Calloc(count, PU_LEVEL, NULL); + return true; } @@ -4128,6 +4133,9 @@ static void P_CreateBlockMap(void) // haleyjd 2/22/06: setup polyobject blockmap count = sizeof(*polyblocklinks) * bmapwidth * bmapheight; polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL); + + count = sizeof (*precipblocklinks)* bmapwidth*bmapheight; + precipblocklinks = Z_Calloc(count, PU_LEVEL, NULL); } } diff --git a/src/r_defs.h b/src/r_defs.h index 39afb4e7f..e20db2ab4 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -528,7 +528,6 @@ typedef struct sector_s fixed_t floorspeed, ceilspeed; // list of precipitation mobjs in sector - precipmobj_t *preciplist; struct mprecipsecnode_s *touching_preciplist; // Eternity engine slope diff --git a/src/r_main.c b/src/r_main.c index 52fc16e64..9691567d8 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -455,6 +455,35 @@ boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixe return false; } + +// Returns search dimensions within a blockmap, in the direction of viewangle and out to a certain distance. +void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh) +{ + const angle_t left = viewangle - clipangle; + const angle_t right = viewangle + clipangle; + + const fixed_t vxleft = viewx + FixedMul(drawdist, FCOS(left)); + const fixed_t vyleft = viewy + FixedMul(drawdist, FSIN(left)); + + const fixed_t vxright = viewx + FixedMul(drawdist, FCOS(right)); + const fixed_t vyright = viewy + FixedMul(drawdist, FSIN(right)); + + // Try to narrow the search to within only the field of view + *xl = (unsigned)(min(viewx, min(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; + *xh = (unsigned)(max(viewx, max(vxleft, vxright)) - bmaporgx)>>MAPBLOCKSHIFT; + *yl = (unsigned)(min(viewy, min(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; + *yh = (unsigned)(max(viewy, max(vyleft, vyright)) - bmaporgy)>>MAPBLOCKSHIFT; + + if (*xh >= bmapwidth) + *xh = bmapwidth - 1; + + if (*yh >= bmapheight) + *yh = bmapheight - 1; + + BMBOUNDFIX(*xl, *xh, *yl, *yh); +} + + // // R_InitTextureMapping // @@ -1590,6 +1619,7 @@ void R_RenderPlayerView(player_t *player) PS_START_TIMING(ps_bsptime); R_RenderBSPNode((INT32)numnodes - 1); PS_STOP_TIMING(ps_bsptime); + R_AddPrecipitationSprites(); Mask_Post(&masks[nummasks - 1]); PS_START_TIMING(ps_sw_spritecliptime); diff --git a/src/r_main.h b/src/r_main.h index 3ad20fccd..5ba3fca0a 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -107,6 +107,8 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y); boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); +void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh); + line_t *R_GetFFloorLine(const line_t *line, const ffloor_t *pfloor, const sector_t *sector); side_t *R_GetFFloorSide(const line_t *line, const ffloor_t *pfloor, const sector_t *sector); diff --git a/src/r_things.c b/src/r_things.c index 6fffa4f5c..476a8348b 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2711,7 +2711,6 @@ weatherthink: void R_AddSprites(sector_t *sec, INT32 lightlevel) { mobj_t *thing; - precipmobj_t *precipthing; // Tails 08-25-2002 INT32 lightnum; fixed_t limit_dist, hoop_limit_dist; @@ -2769,18 +2768,44 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel) } } } +} + +// R_AddPrecipitationSprites +// This renders through the blockmap instead of BSP to avoid +// iterating a huge amount of precipitation sprites in sectors +// that are beyond drawdist. +// +void R_AddPrecipitationSprites(void) +{ + const fixed_t drawdist = ((fixed_t)cv_drawdist_precip.value << FRACBITS); + + INT32 xl, xh, yl, yh, bx, by; + precipmobj_t *th; // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off - if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS)) + if (drawdist == 0) + { + return; + } + + R_GetRenderBlockMapDimensions(drawdist, &xl, &xh, &yl, &yh); + + for (bx = xl; bx <= xh; bx++) { - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) + for (by = yl; by <= yh; by++) { - if (R_PrecipThingVisible(precipthing, limit_dist)) - R_ProjectPrecipitationSprite(precipthing); + for (th = precipblocklinks[(by * bmapwidth) + bx]; th; th = th->bnext) + { + if (R_PrecipThingVisible(th)) + { + R_ProjectPrecipitationSprite(th); + } + } } } } + static boolean R_SortVisSpriteFunc(vissprite_t *ds, fixed_t bestscale, INT32 bestdispoffset) { if (ds->sortscale < bestscale) @@ -3738,19 +3763,15 @@ boolean R_ThingWithinDist (mobj_t *thing, } /* Check if precipitation may be drawn from our current view. */ -boolean R_PrecipThingVisible (precipmobj_t *precipthing, - fixed_t limit_dist) +boolean R_PrecipThingVisible (precipmobj_t *precipthing) { - fixed_t approx_dist; - if (( precipthing->precipflags & PCF_INVISIBLE )) return false; - approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y); - - return ( approx_dist <= limit_dist ); + return true; } + boolean R_ThingHorizontallyFlipped(mobj_t *thing) { return (thing->frame & FF_HORIZONTALFLIP || thing->renderflags & RF_HORIZONTALFLIP); diff --git a/src/r_things.h b/src/r_things.h index 6f80a4e87..552d6e692 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -65,6 +65,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope); //SoM: 6/5/2000: Light sprites correctly! void R_AddSprites(sector_t *sec, INT32 lightlevel); +void R_AddPrecipitationSprites(void); void R_InitSprites(void); void R_ClearSprites(void); @@ -77,8 +78,7 @@ boolean R_ThingWithinDist (mobj_t *thing, fixed_t draw_dist, fixed_t nights_draw_dist); -boolean R_PrecipThingVisible (precipmobj_t *precipthing, - fixed_t precip_draw_dist); +boolean R_PrecipThingVisible (precipmobj_t *precipthing); boolean R_ThingHorizontallyFlipped (mobj_t *thing); boolean R_ThingVerticallyFlipped (mobj_t *thing); diff --git a/src/tables.h b/src/tables.h index 43817e25d..74975c757 100644 --- a/src/tables.h +++ b/src/tables.h @@ -25,6 +25,7 @@ #define TANMASK 4095 #define ANGLETOFINESHIFT 19 // 0x100000000 to 0x2000 #define FINEANGLE_C(x) ((FixedAngle((x)*FRACUNIT)>>ANGLETOFINESHIFT) & FINEMASK) // ((x*(ANGLE_45/45))>>ANGLETOFINESHIFT) & FINEMASK +#define ANGLETOFINE(x) (((x)>>ANGLETOFINESHIFT) & FINEMASK) // Effective size is 10240. extern fixed_t finesine[5*FINEANGLES/4]; @@ -121,4 +122,8 @@ matrix_t *FM_RotateZ(matrix_t *dest, angle_t rad); #define FINECOSINE(n) (finecosine[n]>>(FINE_FRACBITS-FRACBITS)) #define FINETANGENT(n) (finetangent[n]>>(FINE_FRACBITS-FRACBITS)) +// FSIN(ANGLE_90) = FRACUNIT +#define FSIN(n) FINESINE(ANGLETOFINE(n)) +#define FCOS(n) FINECOSINE(ANGLETOFINE(n)) + #endif -- GitLab