diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d8535dc0a..ca53980cf 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); @@ -5052,9 +5053,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. @@ -5085,19 +5083,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 @@ -6315,6 +6339,10 @@ static void HWR_RenderViewpoint(player_t *player, boolean drawSkyTexture, boolea HWR_RenderBSPNode((INT32)numnodes-1); +#ifdef HWPRECIP + HWR_AddPrecipitationSprites(); +#endif + #ifndef NEWCLIP // Make a viewangle int so we can render things based on mouselook viewangle = localaiming[viewssnum]; diff --git a/src/p_local.h b/src/p_local.h index eb4633ff4..51f946572 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -510,6 +510,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 extern struct minimapinfo { diff --git a/src/p_maputl.c b/src/p_maputl.c index e1ceeb0fe..75282c9ef 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -1006,15 +1006,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 @@ -1071,24 +1101,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 @@ -1143,18 +1156,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 56c95a7c3..c084b245c 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -291,9 +291,10 @@ struct mobj_t mobjtype_t type; const mobjinfo_t *info; // &mobjinfo[mobj->type] - // More list: links in sector (if needed) - mobj_t *snext; - mobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr + // Interaction info, by BLOCKMAP. + // Links in blocks (if needed). + mobj_t *bnext; + mobj_t **bprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation @@ -347,10 +348,9 @@ struct mobj_t // 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). - mobj_t *bnext; - mobj_t **bprev; // killough 8/11/98: change to ptr-to-ptr + // More list: links in sector (if needed) + mobj_t *snext; + mobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr // Additional pointers for NiGHTS hoops mobj_t *hnext; @@ -448,9 +448,10 @@ struct precipmobj_t mobjtype_t type; const mobjinfo_t *info; // &mobjinfo[mobj->type] - // More list: links in sector (if needed) - precipmobj_t *snext; - precipmobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr + // Links in blocks (if needed). + // The blockmap is only used by precip to render. + precipmobj_t *bnext; + precipmobj_t **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 9082c2796..ba006d39d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -160,6 +160,7 @@ INT32 *blockmaplump; // Big blockmap fixed_t bmaporgx, bmaporgy; // for thing chains mobj_t **blocklinks; +precipmobj_t **precipblocklinks; // REJECT // For fast sight rejection. @@ -881,7 +882,6 @@ static void P_InitializeSector(sector_t *ss) ss->floorspeed = ss->ceilspeed = 0; - ss->preciplist = NULL; ss->touching_preciplist = NULL; ss->f_slope = NULL; @@ -3546,6 +3546,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; } @@ -3799,6 +3803,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 4e947616b..c550fc92f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -524,7 +524,6 @@ struct sector_t fixed_t floorspeed, ceilspeed; // list of precipitation mobjs in sector - precipmobj_t *preciplist; mprecipsecnode_t *touching_preciplist; // Eternity engine slope diff --git a/src/r_main.c b/src/r_main.c index 06f8113aa..e227a0dd9 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -493,6 +493,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 // @@ -1485,6 +1512,7 @@ static void R_RenderViewpoint(maskcount_t* mask) curdrawsegs = ds_p; R_RenderBSPNode((INT32)numnodes - 1); + R_AddPrecipitationSprites(); Mask_Post(mask); } @@ -1556,7 +1584,6 @@ void R_RenderPlayerView(void) ps_bsptime = I_GetPreciseTime(); R_RenderViewpoint(&masks[nummasks - 1]); 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 786b1eaf6..36d53f1b3 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -87,6 +87,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 86de5352e..4ca7b1736 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2639,7 +2639,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; @@ -2696,14 +2695,45 @@ 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) && !portalskipprecipmobjs) + if (drawdist == 0) { - for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext) + return; + } + + // do not render in skybox + if (portalskipprecipmobjs) + { + 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); + } + } } } } @@ -3641,17 +3671,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 2d82b4381..b40eb4ed4 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -67,6 +67,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); @@ -78,8 +79,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);