diff --git a/src/r_bsp.c b/src/r_bsp.c index 62970520f..d606d7a27 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -52,66 +52,164 @@ void R_ClearDrawSegs(void) ds_p = drawsegs; } -// CPhipps - -// Instead of clipsegs, let's try using an array with one entry for each column, -// indicating whether it's blocked by a solid wall yet or not. -UINT8 solidcol[MAXVIDWIDTH]; +// Fix from boom. +#define MAXSEGS (MAXVIDWIDTH/2+1) + +// newend is one past the last valid seg +static cliprange_t *newend; +static cliprange_t solidsegs[MAXSEGS]; -// CPhipps - -// R_ClipWallSegment // -// Replaces the old R_Clip*WallSegment functions. It draws bits of walls in those -// columns which aren't solid, and updates the solidcol[] array appropriately -static void R_ClipWallSegment(INT32 first, INT32 last, boolean solid) +// R_ClipSolidWallSegment +// Does handle solid walls, +// e.g. single sided LineDefs (middle texture) +// that entirely block the view. +// +static void R_ClipSolidWallSegment(INT32 first, INT32 last) { - while (first < last) + cliprange_t *next; + cliprange_t *start; + + // Find the first range that touches the range (adjacent pixels are touching). + start = solidsegs; + while (start->last < first - 1) + start++; + + if (first < start->first) { - UINT8 *p; - - if (solidcol[first]) + if (last < start->first - 1) { - p = memchr(solidcol+first, 0, last-first); - if (!p) - return; // All solid + // Post is entirely visible (above start), so insert a new clippost. + R_StoreWallRange(first, last); + next = newend; + newend++; + // NO MORE CRASHING! + if (newend - solidsegs > MAXSEGS) + I_Error("R_ClipSolidWallSegment: Solid Segs overflow!\n"); - first = p - solidcol; + while (next != start) + { + *next = *(next-1); + next--; + } + next->first = first; + next->last = last; + return; } - else + + // There is a fragment above *start. + R_StoreWallRange(first, start->first - 1); + // Now adjust the clip size. + start->first = first; + } + + // Bottom contained in start? + if (last <= start->last) + return; + + next = start; + while (last >= (next+1)->first - 1) + { + // There is a fragment between two posts. + R_StoreWallRange(next->last + 1, (next+1)->first - 1); + next++; + + if (last <= next->last) { - p = memchr(solidcol+first, 1, last-first); - - int to; - if (!p) - to = last; - else - to = p - solidcol; - - R_StoreWallRange(first, to-1); - - if (solid) - memset(solidcol+first, 1, to-first); - - first = to; + // Bottom is contained in next. + // Adjust the clip size. + start->last = next->last; + goto crunch; } } + + // There is a fragment after *next. + R_StoreWallRange(next->last + 1, last); + // Adjust the clip size. + start->last = last; + + // Remove start+1 to next from the clip list, because start now covers their area. +crunch: + if (next == start) + return; // Post just extended past the bottom of one post. + + while (next++ != newend) + *++start = *next; // Remove a post. + + newend = start + 1; + + // NO MORE CRASHING! + if (newend - solidsegs > MAXSEGS) + I_Error("R_ClipSolidWallSegment: Solid Segs overflow!\n"); } +// +// R_ClipPassWallSegment +// Clips the given range of columns, but does not include it in the clip list. +// Does handle windows, e.g. LineDefs with upper and lower texture. +// +static inline void R_ClipPassWallSegment(INT32 first, INT32 last) +{ + cliprange_t *start; + + // Find the first range that touches the range + // (adjacent pixels are touching). + start = solidsegs; + while (start->last < first - 1) + start++; + + if (first < start->first) + { + if (last < start->first - 1) + { + // Post is entirely visible (above start). + R_StoreWallRange(first, last); + return; + } + + // There is a fragment above *start. + R_StoreWallRange(first, start->first - 1); + } + + // Bottom contained in start? + if (last <= start->last) + return; + + while (last >= (start+1)->first - 1) + { + // There is a fragment between two posts. + R_StoreWallRange(start->last + 1, (start+1)->first - 1); + start++; + + if (last <= start->last) + return; + } + + // There is a fragment after *next. + R_StoreWallRange(start->last + 1, last); +} + +// +// R_ClearClipSegs +// void R_ClearClipSegs(void) { - memset(solidcol, 0, viewwidth); + solidsegs[0].first = -0x7fffffff; + solidsegs[0].last = -1; + solidsegs[1].first = viewwidth; + solidsegs[1].last = 0x7fffffff; + newend = solidsegs + 2; } - void R_PortalClearClipSegs(INT32 start, INT32 end) { - R_ClearClipSegs(); - - for (INT32 x = 0; x < start; x++) - solidcol[x] = 1; - - for (INT32 x = end; x < viewwidth; x++) - solidcol[x] = 1; + solidsegs[0].first = -0x7fffffff; + solidsegs[0].last = start-1; + solidsegs[1].first = end; + solidsegs[1].last = 0x7fffffff; + newend = solidsegs + 2; } + // R_DoorClosed // // This function is used to fix the automap bug which @@ -517,11 +615,11 @@ static void R_AddLine(seg_t *line) return; clippass: - R_ClipWallSegment(x1, x2, false); + R_ClipPassWallSegment(x1, x2 - 1); return; clipsolid: - R_ClipWallSegment(x1, x2, true); + R_ClipSolidWallSegment(x1, x2 - 1); } // @@ -554,23 +652,10 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) angle_t angle1, angle2; INT32 sx1, sx2, boxpos; const INT32* check; + cliprange_t *start; // Find the corners of the box that define the edges from current viewpoint. - if (viewx <= bspcoord[BOXLEFT]) - boxpos = 0; - else if (viewx < bspcoord[BOXRIGHT]) - boxpos = 1; - else - boxpos = 2; - - if (viewy >= bspcoord[BOXTOP]) - boxpos |= 0; - else if (viewy > bspcoord[BOXBOTTOM]) - boxpos |= 1<<2; - else - boxpos |= 2<<2; - - if (boxpos == 5) + if ((boxpos = (viewx <= bspcoord[BOXLEFT] ? 0 : viewx < bspcoord[BOXRIGHT] ? 1 : 2) + (viewy >= bspcoord[BOXTOP] ? 0 : viewy > bspcoord[BOXBOTTOM] ? 4 : 8)) == 5) return true; check = checkcoord[boxpos]; @@ -599,14 +684,14 @@ static boolean R_CheckBBox(const fixed_t *bspcoord) sx2 = viewangletox[angle2]; // Does not cross a pixel. - if (sx1 >= sx2) - return false; + if (sx1 >= sx2) return false; - if (!memchr(solidcol+sx1, 0, sx2-sx1)) - { - // All columns it covers are already solidly covered - return false; - } + start = solidsegs; + while (start->last < sx2) + start++; + + if (sx1 >= start->first && sx2 <= start->last) + return false; // The clippost contains the new span. return true; } @@ -1313,7 +1398,7 @@ void R_RenderPortalHorizonLine(sector_t *sector) firstseg = NULL; curline = &segs[0]; - R_ClipWallSegment(portalclipstart, portalclipend, true); + R_ClipSolidWallSegment(portalclipstart, portalclipend); curline = NULL; } diff --git a/src/r_bsp.h b/src/r_bsp.h index d08769755..44ddd0b1b 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -38,8 +38,6 @@ extern boolean horizonline; extern INT32 doorclosed; -extern UINT8 solidcol[MAXVIDWIDTH]; - // BSP? void R_ClearClipSegs(void); void R_PortalClearClipSegs(INT32 start, INT32 end); diff --git a/src/r_defs.h b/src/r_defs.h index 227a98d12..da4dd2d70 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -31,6 +31,17 @@ #include "taglist.h" +// +// ClipWallSegment +// Clips the given range of columns +// and includes it in the new clip list. +// +typedef struct +{ + INT32 first; + INT32 last; +} cliprange_t; + // Silhouette, needed for clipping segs (mainly) and sprites representing things. #define SIL_NONE 0 #define SIL_BOTTOM 1 diff --git a/src/r_segs.c b/src/r_segs.c index dbbbf126b..285ef658e 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -994,8 +994,6 @@ static boolean R_FFloorCanClip(visffloor_t *pfloor) return (cv_ffloorclip.value && !R_IsFFloorTranslucent(pfloor) && !pfloor->polyobj); } -static boolean didsolidcol; // True if at least one column was marked solid - // // R_RenderSegLoop // Draws zero, one, or two textures (and possibly a masked @@ -1437,12 +1435,6 @@ static void R_RenderSegLoop (void) floorclip[rw_x] = bottomclip; } - if ((markceiling || markfloor) && (floorclip[rw_x] <= ceilingclip[rw_x] + 1)) - { - solidcol[rw_x] = 1; - didsolidcol = true; - } - if (maskedtexturecol) maskedtexturecol[rw_x] = texturecolumn + rw_offsetx; @@ -1565,12 +1557,6 @@ static void R_MarkSegBounds(void) if (markfloor) // no bottom wall floorclip[rw_x] = bottomclip; - if (floorclip[rw_x] <= ceilingclip[rw_x] + 1) - { - solidcol[rw_x] = 1; - didsolidcol = true; - } - rw_scale += rw_scalestep; topfrac += topstep; bottomfrac += bottomstep; @@ -2954,8 +2940,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) } } - didsolidcol = false; - if (!segtextured && !numffloors && !numbackffloors) { if (markfloor || markceiling) @@ -2985,21 +2969,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) else ds_p->portalpass = 0; - // cph - if a column was made solid by this wall, we _must_ save full clipping info - if (backsector && didsolidcol) - { - if (!(ds_p->silhouette & SIL_BOTTOM)) - { - ds_p->silhouette |= SIL_BOTTOM; - ds_p->bsilheight = backsector->f_slope ? INT32_MAX : backsector->floorheight; - } - if (!(ds_p->silhouette & SIL_TOP)) - { - ds_p->silhouette |= SIL_TOP; - ds_p->tsilheight = backsector->c_slope ? INT32_MIN : backsector->ceilingheight; - } - } - // save sprite clipping info if (maskedtexture || (ds_p->silhouette & (SIL_TOP | SIL_BOTTOM))) {