From ae28c9b29cdf3f88b6fc335f229aa9f4536df83c Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:09:38 -0500 Subject: [PATCH 1/3] Fix divide by 0 in new wallscan functions with 1-pixel tall textures --- src/r_segs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_segs.cpp b/src/r_segs.cpp index ae33332de..369722242 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1114,7 +1114,7 @@ WallscanSampler::WallscanSampler(int y1, float swal, double yrepeat, fixed_t xof // Draw a column with support for non-power-of-two ranges void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*draw1column)()) { - if (sampler.uv_max == 0) // power of two + if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two { int count = y2 - y1; @@ -1162,7 +1162,7 @@ void wallscan_drawcol1(int x, int y1, int y2, WallscanSampler &sampler, DWORD(*d // Draw four columns with support for non-power-of-two ranges void wallscan_drawcol4(int x, int y1, int y2, WallscanSampler *sampler, void(*draw4columns)()) { - if (sampler[0].uv_max == 0) // power of two, no wrap handling needed + if (sampler[0].uv_max == 0 || sampler[0].uv_step == 0) // power of two, no wrap handling needed { int count = y2 - y1; for (int i = 0; i < 4; i++) From dbc54fbca0d93b9b9f71f218ed3020c8a2057a9a Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:29:02 -0500 Subject: [PATCH 2/3] Fix FillSimplePoly() for 1-pixel tall or wide textures --- src/v_draw.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index bef732894..d50bea6cc 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1348,10 +1348,26 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, R_SetupSpanBits(tex); R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap); R_SetSpanSource(tex->GetPixels()); - scalex = double(1u << (32 - ds_xbits)) / scalex; - scaley = double(1u << (32 - ds_ybits)) / scaley; - ds_xstep = xs_RoundToInt(cosrot * scalex); - ds_ystep = xs_RoundToInt(sinrot * scaley); + if (ds_xbits != 0) + { + scalex = double(1u << (32 - ds_xbits)) / scalex; + ds_xstep = xs_RoundToInt(cosrot * scalex); + } + else + { // Texture is one pixel wide. + scalex = 0; + ds_xstep = 0; + } + if (ds_ybits != 0) + { + scaley = double(1u << (32 - ds_ybits)) / scaley; + ds_ystep = xs_RoundToInt(sinrot * scaley); + } + else + { // Texture is one pixel tall. + scaley = 0; + ds_ystep = 0; + } // Travel down the right edge and create an outline of that edge. pt1 = toppt; From 55ee78fc0b133c88b35bc8bde26ca2aa216032c5 Mon Sep 17 00:00:00 2001 From: Marisa Heit Date: Sat, 5 Nov 2016 22:49:33 -0500 Subject: [PATCH 3/3] Add bottomclip parameter to FillSimplePoly() for the software implementation - Polygons will be clipped to bottomclip. If this is zero or below, they will be clipped to the bottom of the screen instead. This keeps the polygons from overwriting the status bar border for sofware 2D. The hardware version ignores it, since it always draws the status bar border every frame. --- src/am_map.cpp | 3 ++- src/v_draw.cpp | 17 +++++++++++------ src/v_video.h | 2 +- src/win32/fb_d3d9.cpp | 9 +++++++-- src/win32/win32iface.h | 2 +- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/am_map.cpp b/src/am_map.cpp index 9292e81d9..d74927b68 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2046,7 +2046,8 @@ void AM_drawSubsectors() scale / scaley, rotation, colormap, - floorlight + floorlight, + f_y + f_h ); } } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index d50bea6cc..8483b9844 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1282,7 +1282,7 @@ void DCanvas::FinishSimplePolys() void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - FDynamicColormap *colormap, int lightlevel) + FDynamicColormap *colormap, int lightlevel, int bottomclip) { #ifndef NO_SWRENDER // Use an equation similar to player sprites to determine shade @@ -1300,6 +1300,11 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, return; } + if (bottomclip <= 0) + { + bottomclip = Height; + } + // Find the extents of the polygon, in particular the highest and lowest points. for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i) { @@ -1322,7 +1327,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, rightx = points[i].X; } } - if (topy >= Height || // off the bottom of the screen + if (topy >= bottomclip || // off the bottom of the screen boty <= 0 || // off the top of the screen leftx >= Width || // off the right of the screen rightx <= 0) // off the left of the screen @@ -1377,13 +1382,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, { x = FLOAT2FIXED(points[pt1].X + 0.5f); y2 = xs_RoundToInt(points[pt2].Y + 0.5f); - if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip)) { } else { fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); - int y3 = MIN(y2, Height); + int y3 = MIN(y2, bottomclip); if (y1 < 0) { x += xinc * -y1; @@ -1408,13 +1413,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, { x = FLOAT2FIXED(points[pt1].X + 0.5f); y2 = xs_RoundToInt(points[pt2].Y + 0.5f); - if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height)) + if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= bottomclip && y2 >= bottomclip)) { } else { fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y)); - int y3 = MIN(y2, Height); + int y3 = MIN(y2, bottomclip); if (y1 < 0) { x += xinc * -y1; diff --git a/src/v_video.h b/src/v_video.h index d19a3b06e..890ab6d63 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -224,7 +224,7 @@ public: // Fill a simple polygon with a texture virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, - struct FDynamicColormap *colormap, int lightlevel); + struct FDynamicColormap *colormap, int lightlevel, int bottomclip); // Set an area to a specified color virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color); diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 8bb680dbd..10ab11c72 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -3084,11 +3084,16 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo // // Here, "simple" means that a simple triangle fan can draw it. // +// Bottomclip is ignored by this implementation, since the hardware renderer +// will unconditionally draw the status bar border every frame on top of the +// polygons, so there's no need to waste time setting up a special scissor +// rectangle here and needlessly forcing separate batches. +// //========================================================================== void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel) + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) { // Use an equation similar to player sprites to determine shade double fadelevel = clamp((LIGHT2SHADE(lightlevel)/65536. - 12) / NUMCOLORMAPS, 0.0, 1.0); @@ -3109,7 +3114,7 @@ void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, } if (In2D < 2) { - Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel); + Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel, bottomclip); return; } if (!InScene) diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 9b2754eae..b5262089b 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -265,7 +265,7 @@ public: void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor); void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, - DAngle rotation, FDynamicColormap *colormap, int lightlevel); + DAngle rotation, FDynamicColormap *colormap, int lightlevel, int bottomclip) override; bool WipeStartScreen(int type); void WipeEndScreen(); bool WipeDo(int ticks);