diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 3279a61689a1907c998c4e5b42e9849a8363af82..0ca6ac4895d40cd5554c83cafd9442b6eb43995e 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 85a31cf8982114068b0da41c7a59971d011929ba..4e2d84766d937b8499186263868d62d53adced29 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 4c7b959270993a7117c58d83f71c86348206937e..1197f5f49be3ae5a9c5d35aa0c4e52c4213a9d21 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 fef6713a4b9c10de3286373411362562ab0eb83e..eb383723b28c677f6317b1f40840ba96b886d14f 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 d8e4e5d67c06b8d3bb9df58d53ad495458c3818d..27b8730c22312ffdff73f0c37eb1ecd683b9b3b6 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 39afb4e7faac6852903968a9b6c8a4bf984d0bc9..e20db2ab46a2ac72c141fbf38e80c43deb541c59 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 52fc16e643b38ae98ef8a3d9350c5d0118b7d210..9691567d859cb27ddcf28fd328ed3432d0eac59d 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 3ad20fccde4304fcbc4e0a68fe6eeca04843e799..5ba3fca0afe179fb30b71aa8cefbce6390ed4e78 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 6fffa4f5c4e284086eb55045396207cc5eef448f..476a8348b2b577d9085f559f57faef236074ae96 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 6f80a4e87e70215dd3da02a5a764d07640346b96..552d6e6927836224846db8f667157c8e9c964872 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 43817e25d3ed6ab78e695e8c8512fb6cb1ea61d7..74975c7573f54bd46b72cefd8e2f32fc5dccd5f5 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