diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 88963049e..800f0b188 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -69,6 +69,7 @@ struct hwdriver_s hwdriver; static void HWR_AddSprites(sector_t *sec); static void HWR_ProjectSprite(mobj_t *thing); #ifdef HWPRECIP +static void HWR_AddPrecipitationSprites(void); static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing); #endif static void HWR_ProjectBoundingBox(mobj_t *thing); @@ -5101,9 +5102,6 @@ static UINT8 sectorlight; static void HWR_AddSprites(sector_t *sec) { mobj_t *thing; -#ifdef HWPRECIP - precipmobj_t *precipthing; -#endif fixed_t limit_dist; // BSP is traversed by subsector. @@ -5134,19 +5132,45 @@ static void HWR_AddSprites(sector_t *sec) HWR_ProjectBoundingBox(thing); } } +} #ifdef HWPRECIP +// -------------------------------------------------------------------------- +// 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 = cv_drawdist_precip.value * mapobjectscale; + + 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 * mapobjectscale)) + if (drawdist == 0) { - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) + return; + } + + R_GetRenderBlockMapDimensions(drawdist, &xl, &xh, &yl, &yh); + + for (bx = xl; bx <= xh; bx++) + { + 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); + } + } } } -#endif } +#endif // -------------------------------------------------------------------------- // HWR_ProjectSprite @@ -6344,6 +6368,10 @@ void HWR_RenderSkyboxView(player_t *player) if (cv_glbatching.value) HWR_StartBatching(); + +#ifdef HWPRECIP + HWR_AddPrecipitationSprites(); +#endif HWR_RenderBSPNode((INT32)numnodes-1); @@ -6565,6 +6593,10 @@ void HWR_RenderPlayerView(void) if (cv_glbatching.value) HWR_StartBatching(); + +#ifdef HWPRECIP + HWR_AddPrecipitationSprites(); +#endif HWR_RenderBSPNode((INT32)numnodes-1); diff --git a/src/p_local.h b/src/p_local.h index 0e857e027..5c7de48fb 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -462,6 +462,7 @@ extern INT32 bmapheight; // in mapblocks extern fixed_t bmaporgx; extern fixed_t bmaporgy; // origin of block map extern mobj_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 09e5cdd5d..b4ae2f3ed 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -971,15 +971,45 @@ 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_LinkToBlockMap(mobj_t *thing, mobj_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 + + mobj_t **link = &bmap[(blocky * bmapwidth) + blockx]; + mobj_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 @@ -1036,24 +1066,7 @@ void P_SetThingPosition(mobj_t *thing) if (!(thing->flags & MF_NOBLOCKMAP)) { // inert things don't need to be in blockmap - 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 - - mobj_t **link = &blocklinks[blocky*bmapwidth + blockx]; - mobj_t *bnext = *link; - if ((thing->bnext = bnext) != NULL) - bnext->bprev = &thing->bnext; - thing->bprev = link; - *link = thing; - } - else // thing is off the map - thing->bnext = NULL, thing->bprev = NULL; + P_LinkToBlockMap(thing, blocklinks); } // Allows you to 'step' on a new linedef exec when the previous @@ -1108,18 +1121,15 @@ 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 + + // NOTE: this works because bnext/bprev are at the same + // offsets in precipmobj_t and mobj_t + P_LinkToBlockMap((mobj_t*)thing, (mobj_t**)precipblocklinks); } // diff --git a/src/p_mobj.h b/src/p_mobj.h index 2a0591dd4..3173ac9f8 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -281,9 +281,10 @@ typedef struct mobj_s fixed_t old_x, old_y, old_z; // position interpolation fixed_t old_x2, old_y2, old_z2; - // More list: links in sector (if needed) - struct mobj_s *snext; - struct mobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr + // Interaction info, by BLOCKMAP. + // Links in blocks (if needed). + struct mobj_s *bnext; + struct mobj_s **bprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation @@ -333,10 +334,9 @@ typedef struct mobj_s // using an internal color lookup table for re-indexing. UINT16 color; // This replaces MF_TRANSLATION. Use 0 for default (no translation). - // Interaction info, by BLOCKMAP. - // Links in blocks (if needed). - struct mobj_s *bnext; - struct mobj_s **bprev; // killough 8/11/98: change to ptr-to-ptr + // More list: links in sector (if needed) + struct mobj_s *snext; + struct mobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr // Additional pointers for NiGHTS hoops struct mobj_s *hnext; @@ -431,9 +431,10 @@ typedef struct precipmobj_s fixed_t old_x, old_y, old_z; // position interpolation fixed_t old_x2, old_y2, old_z2; - // More list: links in sector (if needed) - struct precipmobj_s *snext; - struct precipmobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr + // 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 // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation diff --git a/src/p_setup.c b/src/p_setup.c index 1eecffbbb..ba6e533e6 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -152,6 +152,7 @@ INT32 *blockmaplump; // Big blockmap fixed_t bmaporgx, bmaporgy; // for thing chains mobj_t **blocklinks; +precipmobj_t **precipblocklinks; // REJECT // For fast sight rejection. @@ -986,7 +987,6 @@ static void P_InitializeSector(sector_t *ss) ss->floorspeed = ss->ceilspeed = 0; - ss->preciplist = NULL; ss->touching_preciplist = NULL; ss->f_slope = NULL; @@ -2764,6 +2764,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; } @@ -3017,6 +3021,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 62085889b..9e50c4fdb 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -362,7 +362,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 d6cad900e..bedd565b1 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -500,6 +500,33 @@ 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[viewssnum]; + const angle_t right = viewangle + clipangle[viewssnum]; + + 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 // @@ -1564,8 +1591,8 @@ void R_RenderPlayerView(void) ps_numbspcalls = ps_numpolyobjects = ps_numdrawnodes = 0; ps_bsptime = I_GetPreciseTime(); R_RenderBSPNode((INT32)numnodes - 1); + R_AddPrecipitationSprites(); ps_bsptime = I_GetPreciseTime() - ps_bsptime; - ps_numsprites = visspritecount; #ifdef TIMING RDMSR(0x10, &mycount); mytotal += mycount; // 64bit add diff --git a/src/r_main.h b/src/r_main.h index e7f5b9d4c..6634c9b09 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -83,6 +83,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); + // Render stats extern precise_t ps_prevframetime;// time when previous frame was rendered diff --git a/src/r_things.c b/src/r_things.c index 6c6549124..8f8d28f47 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2501,7 +2501,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; @@ -2558,14 +2557,39 @@ 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 = cv_drawdist_precip.value * mapobjectscale; + + 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 * mapobjectscale)) + if (drawdist == 0) { - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) + return; + } + + R_GetRenderBlockMapDimensions(drawdist, &xl, &xh, &yl, &yh); + + for (bx = xl; bx <= xh; bx++) + { + 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); + } + } } } } @@ -3448,17 +3472,12 @@ boolean R_ThingWithinDist (mobj_t *thing, fixed_t limit_dist) } /* 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) diff --git a/src/r_things.h b/src/r_things.h index 1d8bde5bd..ba44acecd 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -63,6 +63,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); @@ -74,8 +75,7 @@ boolean R_ThingVisible (mobj_t *thing); boolean R_ThingWithinDist (mobj_t *thing, fixed_t 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 e122975e1..42e5ed899 100644 --- a/src/tables.h +++ b/src/tables.h @@ -24,6 +24,7 @@ #define FINEMASK (FINEANGLES - 1) #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]; @@ -132,4 +133,7 @@ void FM_Rotate(matrix_t *dest, angle_t angle, fixed_t x, fixed_t y, fixed_t z); #define FINECOSINE(n) (finecosine[n]>>(FINE_FRACBITS-FRACBITS)) #define FINETANGENT(n) (finetangent[n]>>(FINE_FRACBITS-FRACBITS)) +#define FSIN(n) FINESINE(ANGLETOFINE(n)) +#define FCOS(n) FINECOSINE(ANGLETOFINE(n)) + #endif