diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e7e819626..f914f7996 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -769,6 +769,7 @@ file( GLOB HEADER_FILES swrenderer/drawers/*.h swrenderer/scene/*.h swrenderer/segments/*.h + swrenderer/line/*.h swrenderer/plane/*.h swrenderer/things/*.h polyrenderer/*.h @@ -821,8 +822,10 @@ set( FASTMATH_PCH_SOURCES swrenderer/scene/r_bsp.cpp swrenderer/scene/r_segs.cpp swrenderer/scene/r_things.cpp - swrenderer/scene/r_walldraw.cpp swrenderer/scene/r_portal.cpp + swrenderer/line/r_line.cpp + swrenderer/line/r_walldraw.cpp + swrenderer/line/r_wallsetup.cpp swrenderer/segments/r_clipsegment.cpp swrenderer/segments/r_drawsegment.cpp swrenderer/segments/r_portalsegment.cpp @@ -1474,6 +1477,7 @@ source_group("Software Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR source_group("Software Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/drawers/.+") source_group("Software Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/scene/.+") source_group("Software Renderer\\Segments" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/segments/.+") +source_group("Software Renderer\\Line" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/line/.+") source_group("Software Renderer\\Plane" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/plane/.+") source_group("Software Renderer\\Things" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/swrenderer/things/.+") source_group("Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/polyrenderer/.+") diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp new file mode 100644 index 000000000..4edd23cb9 --- /dev/null +++ b/src/swrenderer/line/r_line.cpp @@ -0,0 +1,126 @@ + +#include +#include +#include "templates.h" +#include "i_system.h" +#include "doomdef.h" +#include "doomstat.h" +#include "doomdata.h" +#include "p_lnspec.h" +#include "r_sky.h" +#include "v_video.h" +#include "m_swap.h" +#include "w_wad.h" +#include "stats.h" +#include "a_sharedglobal.h" +#include "d_net.h" +#include "g_level.h" +#include "r_wallsetup.h" +#include "v_palette.h" +#include "r_data/colormaps.h" +#include "swrenderer/r_main.h" +#include "swrenderer/r_memory.h" +#include "swrenderer/scene/r_bsp.h" +#include "swrenderer/line/r_line.h" + +namespace swrenderer +{ + FWallCoords WallC; + FWallTmapVals WallT; + + // Transform and clip coordinates. Returns true if it was clipped away + bool FWallCoords::Init(const DVector2 &pt1, const DVector2 &pt2, double too_close) + { + tleft.X = float(pt1.X * ViewSin - pt1.Y * ViewCos); + tright.X = float(pt2.X * ViewSin - pt2.Y * ViewCos); + + tleft.Y = float(pt1.X * ViewTanCos + pt1.Y * ViewTanSin); + tright.Y = float(pt2.X * ViewTanCos + pt2.Y * ViewTanSin); + + if (MirrorFlags & RF_XFLIP) + { + float t = -tleft.X; + tleft.X = -tright.X; + tright.X = t; + swapvalues(tleft.Y, tright.Y); + } + + if (tleft.X >= -tleft.Y) + { + if (tleft.X > tleft.Y) return true; // left edge is off the right side + if (tleft.Y == 0) return true; + sx1 = xs_RoundToInt(CenterX + tleft.X * CenterX / tleft.Y); + sz1 = tleft.Y; + } + else + { + if (tright.X < -tright.Y) return true; // wall is off the left side + float den = tleft.X - tright.X - tright.Y + tleft.Y; + if (den == 0) return true; + sx1 = 0; + sz1 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X + tleft.Y) / den; + } + + if (sz1 < too_close) + return true; + + if (tright.X <= tright.Y) + { + if (tright.X < -tright.Y) return true; // right edge is off the left side + if (tright.Y == 0) return true; + sx2 = xs_RoundToInt(CenterX + tright.X * CenterX / tright.Y); + sz2 = tright.Y; + } + else + { + if (tleft.X > tleft.Y) return true; // wall is off the right side + float den = tright.Y - tleft.Y - tright.X + tleft.X; + if (den == 0) return true; + sx2 = viewwidth; + sz2 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X - tleft.Y) / den; + } + + if (sz2 < too_close || sx2 <= sx1) + return true; + + return false; + } + + ///////////////////////////////////////////////////////////////////////// + + void FWallTmapVals::InitFromWallCoords(const FWallCoords *wallc) + { + const FVector2 *left = &wallc->tleft; + const FVector2 *right = &wallc->tright; + + if (MirrorFlags & RF_XFLIP) + { + swapvalues(left, right); + } + UoverZorg = left->X * centerx; + UoverZstep = -left->Y; + InvZorg = (left->X - right->X) * centerx; + InvZstep = right->Y - left->Y; + } + + void FWallTmapVals::InitFromLine(const DVector2 &left, const DVector2 &right) + { + // Coordinates should have already had viewx,viewy subtracted + + double fullx1 = left.X * ViewSin - left.Y * ViewCos; + double fullx2 = right.X * ViewSin - right.Y * ViewCos; + double fully1 = left.X * ViewTanCos + left.Y * ViewTanSin; + double fully2 = right.X * ViewTanCos + right.Y * ViewTanSin; + + if (MirrorFlags & RF_XFLIP) + { + fullx1 = -fullx1; + fullx2 = -fullx2; + } + + UoverZorg = float(fullx1 * centerx); + UoverZstep = float(-fully1); + InvZorg = float((fullx1 - fullx2) * centerx); + InvZstep = float(fully2 - fully1); + } +} diff --git a/src/swrenderer/line/r_line.h b/src/swrenderer/line/r_line.h new file mode 100644 index 000000000..95a931969 --- /dev/null +++ b/src/swrenderer/line/r_line.h @@ -0,0 +1,28 @@ + +#pragma once + +namespace swrenderer +{ + struct FWallCoords + { + FVector2 tleft; // coords at left of wall in view space rx1,ry1 + FVector2 tright; // coords at right of wall in view space rx2,ry2 + + float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2 + short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2 + + bool Init(const DVector2 &pt1, const DVector2 &pt2, double too_close); + }; + + struct FWallTmapVals + { + float UoverZorg, UoverZstep; + float InvZorg, InvZstep; + + void InitFromWallCoords(const FWallCoords *wallc); + void InitFromLine(const DVector2 &left, const DVector2 &right); + }; + + extern FWallCoords WallC; + extern FWallTmapVals WallT; +} diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp new file mode 100644 index 000000000..da0206eec --- /dev/null +++ b/src/swrenderer/line/r_walldraw.cpp @@ -0,0 +1,604 @@ +/* +** Wall drawing stuff +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include +#include + +#include "doomdef.h" +#include "doomstat.h" +#include "doomdata.h" + +#include "swrenderer/r_main.h" +#include "r_sky.h" +#include "v_video.h" + +#include "m_swap.h" +#include "a_sharedglobal.h" +#include "d_net.h" +#include "g_level.h" +#include "r_walldraw.h" +#include "v_palette.h" +#include "r_data/colormaps.h" +#include "gl/dynlights/gl_dynlight.h" +#include "swrenderer/drawers/r_drawers.h" +#include "swrenderer/drawers/r_draw.h" +#include "swrenderer/segments/r_drawsegment.h" +#include "swrenderer/scene/r_bsp.h" +#include "swrenderer/scene/r_segs.h" +#include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/line/r_walldraw.h" +#include "swrenderer/line/r_wallsetup.h" + +namespace swrenderer +{ + using namespace drawerargs; + + extern FTexture *rw_pic; + + static const uint8_t *R_GetColumn(FTexture *tex, int col) + { + int width; + + // If the texture's width isn't a power of 2, then we need to make it a + // positive offset for proper clamping. + if (col < 0 && (width = tex->GetWidth()) != (1 << tex->WidthBits)) + { + col = width + (col % width); + } + + if (r_swtruecolor) + return (const uint8_t *)tex->GetColumnBgra(col, nullptr); + else + return tex->GetColumn(col, nullptr); + } + + WallSampler::WallSampler(int y1, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)) + { + xoffset += FLOAT2FIXED(xmagnitude * 0.5); + + if (!r_swtruecolor) + { + height = texture->GetHeight(); + + int uv_fracbits = 32 - texture->HeightBits; + if (uv_fracbits != 32) + { + uv_max = height << uv_fracbits; + + // Find start uv in [0-base_height[ range. + // Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range. + double uv_stepd = swal * yrepeat; + double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height; + v = v - floor(v); + v *= height; + v *= (1 << uv_fracbits); + + uv_pos = (uint32_t)v; + uv_step = xs_ToFixed(uv_fracbits, uv_stepd); + if (uv_step == 0) // To prevent divide by zero elsewhere + uv_step = 1; + } + else + { // Hack for one pixel tall textures + uv_pos = 0; + uv_step = 0; + uv_max = 1; + } + + source = getcol(texture, xoffset >> FRACBITS); + source2 = nullptr; + texturefracx = 0; + } + else + { + // Normalize to 0-1 range: + double uv_stepd = swal * yrepeat; + double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / texture->GetHeight(); + v = v - floor(v); + double v_step = uv_stepd / texture->GetHeight(); + + if (isnan(v) || isnan(v_step)) // this should never happen, but it apparently does.. + { + uv_stepd = 0.0; + v = 0.0; + v_step = 0.0; + } + + // Convert to uint32: + uv_pos = (uint32_t)(v * 0x100000000LL); + uv_step = (uint32_t)(v_step * 0x100000000LL); + uv_max = 0; + + // Texture mipmap and filter selection: + if (getcol != R_GetColumn) + { + source = getcol(texture, xoffset >> FRACBITS); + source2 = nullptr; + height = texture->GetHeight(); + texturefracx = 0; + } + else + { + double ymagnitude = fabs(uv_stepd); + double magnitude = MAX(ymagnitude, xmagnitude); + double min_lod = -1000.0; + double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); + bool magnifying = lod < 0.0f; + + int mipmap_offset = 0; + int mip_width = texture->GetWidth(); + int mip_height = texture->GetHeight(); + if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1) + { + uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); + + int level = (int)lod; + while (level > 0 && mip_width > 1 && mip_height > 1) + { + mipmap_offset += mip_width * mip_height; + level--; + mip_width = MAX(mip_width >> 1, 1); + mip_height = MAX(mip_height >> 1, 1); + } + xoffset = (xpos >> FRACBITS) * mip_width; + } + + const uint32_t *pixels = texture->GetPixelsBgra() + mipmap_offset; + + bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); + if (filter_nearest) + { + int tx = (xoffset >> FRACBITS) % mip_width; + if (tx < 0) + tx += mip_width; + source = (BYTE*)(pixels + tx * mip_height); + source2 = nullptr; + height = mip_height; + texturefracx = 0; + } + else + { + xoffset -= FRACUNIT / 2; + int tx0 = (xoffset >> FRACBITS) % mip_width; + if (tx0 < 0) + tx0 += mip_width; + int tx1 = (tx0 + 1) % mip_width; + source = (BYTE*)(pixels + tx0 * mip_height); + source2 = (BYTE*)(pixels + tx1 * mip_height); + height = mip_height; + texturefracx = (xoffset >> (FRACBITS - 4)) & 15; + } + } + } + } + + // Draw a column with support for non-power-of-two ranges + static void Draw1Column(int x, int y1, int y2, WallSampler &sampler, DrawerFunc draw1column) + { + if (r_dynlights) + { + // Find column position in view space + float w1 = 1.0f / WallC.sz1; + float w2 = 1.0f / WallC.sz2; + float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1); + float wcol = w1 * (1.0f - t) + w2 * t; + float zcol = 1.0f / wcol; + dc_viewpos.X = (float)((x + 0.5 - CenterX) / CenterX * zcol); + dc_viewpos.Y = zcol; + dc_viewpos.Z = (float)((CenterY - y1 - 0.5) / InvZtoScale * zcol); + dc_viewpos_step.Z = (float)(-zcol / InvZtoScale); + + static TriLight lightbuffer[64 * 1024]; + static int nextlightindex = 0; + + // Setup lights for column + dc_num_lights = 0; + dc_lights = lightbuffer + nextlightindex; + FLightNode *cur_node = dc_light_list; + while (cur_node && nextlightindex < 64 * 1024) + { + if (!(cur_node->lightsource->flags2&MF2_DORMANT)) + { + double lightX = cur_node->lightsource->X() - ViewPos.X; + double lightY = cur_node->lightsource->Y() - ViewPos.Y; + double lightZ = cur_node->lightsource->Z() - ViewPos.Z; + + float lx = (float)(lightX * ViewSin - lightY * ViewCos) - dc_viewpos.X; + float ly = (float)(lightX * ViewTanCos + lightY * ViewTanSin) - dc_viewpos.Y; + float lz = (float)lightZ; + + // Precalculate the constant part of the dot here so the drawer doesn't have to. + float lconstant = lx * lx + ly * ly; + + // Include light only if it touches this column + float radius = cur_node->lightsource->GetRadius(); + if (radius * radius >= lconstant) + { + uint32_t red = cur_node->lightsource->GetRed(); + uint32_t green = cur_node->lightsource->GetGreen(); + uint32_t blue = cur_node->lightsource->GetBlue(); + + nextlightindex++; + auto &light = dc_lights[dc_num_lights++]; + light.x = lconstant; + light.z = lz; + light.radius = 256.0f / cur_node->lightsource->GetRadius(); + light.color = (red << 16) | (green << 8) | blue; + } + } + + cur_node = cur_node->nextLight; + } + + if (nextlightindex == 64 * 1024) + nextlightindex = 0; + } + else + { + dc_num_lights = 0; + } + + if (r_swtruecolor) + { + int count = y2 - y1; + + dc_source = sampler.source; + dc_source2 = sampler.source2; + dc_texturefracx = sampler.texturefracx; + dc_dest = (ylookup[y1] + x) * 4 + dc_destorg; + dc_count = count; + dc_iscale = sampler.uv_step; + dc_texturefrac = sampler.uv_pos; + dc_textureheight = sampler.height; + (R_Drawers()->*draw1column)(); + + uint64_t step64 = sampler.uv_step; + uint64_t pos64 = sampler.uv_pos; + sampler.uv_pos = (uint32_t)(pos64 + step64 * count); + } + else + { + if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two + { + int count = y2 - y1; + + dc_source = sampler.source; + dc_source2 = sampler.source2; + dc_texturefracx = sampler.texturefracx; + dc_dest = (ylookup[y1] + x) + dc_destorg; + dc_count = count; + dc_iscale = sampler.uv_step; + dc_texturefrac = sampler.uv_pos; + (R_Drawers()->*draw1column)(); + + uint64_t step64 = sampler.uv_step; + uint64_t pos64 = sampler.uv_pos; + sampler.uv_pos = (uint32_t)(pos64 + step64 * count); + } + else + { + uint32_t uv_pos = sampler.uv_pos; + + uint32_t left = y2 - y1; + while (left > 0) + { + uint32_t available = sampler.uv_max - uv_pos; + uint32_t next_uv_wrap = available / sampler.uv_step; + if (available % sampler.uv_step != 0) + next_uv_wrap++; + uint32_t count = MIN(left, next_uv_wrap); + + dc_source = sampler.source; + dc_source2 = sampler.source2; + dc_texturefracx = sampler.texturefracx; + dc_dest = (ylookup[y1] + x) + dc_destorg; + dc_count = count; + dc_iscale = sampler.uv_step; + dc_texturefrac = uv_pos; + (R_Drawers()->*draw1column)(); + + left -= count; + uv_pos += sampler.uv_step * count; + if (uv_pos >= sampler.uv_max) + uv_pos -= sampler.uv_max; + } + + sampler.uv_pos = uv_pos; + } + } + } + + static void ProcessWallWorker( + int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, + const BYTE *(*getcol)(FTexture *tex, int x), DrawerFunc drawcolumn) + { + if (rw_pic->UseType == FTexture::TEX_Null) + return; + + fixed_t xoffset = rw_offset; + + rw_pic->GetHeight(); // To ensure that rw_pic->HeightBits has been set + int fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } + + dc_wall_fracbits = r_swtruecolor ? FRACBITS : fracbits; + + bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0); + if (fixed) + { + dc_wall_colormap[0] = dc_colormap; + dc_wall_colormap[1] = dc_colormap; + dc_wall_colormap[2] = dc_colormap; + dc_wall_colormap[3] = dc_colormap; + dc_wall_light[0] = 0; + dc_wall_light[1] = 0; + dc_wall_light[2] = 0; + dc_wall_light[3] = 0; + } + + if (fixedcolormap) + R_SetColorMapLight(fixedcolormap, 0, 0); + else + R_SetColorMapLight(basecolormap, 0, 0); + + float light = rw_light; + + double xmagnitude = 1.0; + + for (int x = x1; x < x2; x++, light += rw_lightstep) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 <= y1) + continue; + + if (!fixed) + R_SetColorMapLight(basecolormap, light, wallshade); + + if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); + + WallSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic, getcol); + Draw1Column(x, y1, y2, sampler, drawcolumn); + } + + NetUpdate(); + } + + static void ProcessNormalWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + { + ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, &SWPixelFormatDrawers::DrawWallColumn); + } + + static void ProcessMaskedWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + { + if (!rw_pic->bMasked) // Textures that aren't masked can use the faster ProcessNormalWall. + { + ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); + } + else + { + ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, &SWPixelFormatDrawers::DrawWallMaskedColumn); + } + } + + static void ProcessTranslucentWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + { + DrawerFunc drawcol1 = R_GetTransMaskDrawer(); + if (drawcol1 == nullptr) + { + // The current translucency is unsupported, so draw with regular ProcessMaskedWall instead. + ProcessMaskedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); + } + else + { + ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, drawcol1); + } + } + + static void ProcessStripedWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade) + { + FDynamicColormap *startcolormap = basecolormap; + bool fogginess = foggy; + + short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH]; + short *up, *down; + + up = uwal; + down = most1; + + assert(WallC.sx1 <= x1); + assert(WallC.sx2 >= x2); + + // kg3D - fake floors instead of zdoom light list + for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++) + { + int j = R_CreateWallSegmentYSloped(most3, frontsector->e->XFloor.lightlist[i].plane, &WallC, curline, MirrorFlags & RF_XFLIP); + if (j != 3) + { + for (int j = x1; j < x2; ++j) + { + down[j] = clamp(most3[j], up[j], dwal[j]); + } + ProcessNormalWall(x1, x2, up, down, swal, lwal, yrepeat, wallshade); + up = down; + down = (down == most1) ? most2 : most1; + } + + lightlist_t *lit = &frontsector->e->XFloor.lightlist[i]; + basecolormap = lit->extra_colormap; + wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight); + } + + ProcessNormalWall(x1, x2, up, dwal, swal, lwal, yrepeat, wallshade); + basecolormap = startcolormap; + } + + static void ProcessWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, bool mask) + { + if (mask) + { + if (colfunc == basecolfunc) + { + ProcessMaskedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); + } + else + { + ProcessTranslucentWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); + } + } + else + { + if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size())) + { + ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); + } + else + { + ProcessStripedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); + } + } + } + + //============================================================================= + // + // ProcessWallNP2 + // + // This is a wrapper around ProcessWall that helps it tile textures whose heights + // are not powers of 2. It divides the wall into texture-sized strips and calls + // ProcessNormalWall for each of those. Since only one repetition of the texture fits + // in each strip, ProcessWall will not tile. + // + //============================================================================= + + static void ProcessWallNP2(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, double top, double bot, int wallshade, bool mask) + { + short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH]; + short *up, *down; + double texheight = rw_pic->GetHeight(); + double partition; + double scaledtexheight = texheight / yrepeat; + + if (yrepeat >= 0) + { // normal orientation: draw strips from top to bottom + partition = top - fmod(top - dc_texturemid / yrepeat - ViewPos.Z, scaledtexheight); + if (partition == top) + { + partition -= scaledtexheight; + } + up = uwal; + down = most1; + dc_texturemid = (partition - ViewPos.Z) * yrepeat + texheight; + while (partition > bot) + { + int j = R_CreateWallSegmentY(most3, partition - ViewPos.Z, &WallC); + if (j != 3) + { + for (int j = x1; j < x2; ++j) + { + down[j] = clamp(most3[j], up[j], dwal[j]); + } + ProcessWall(x1, x2, up, down, swal, lwal, yrepeat, wallshade, mask); + up = down; + down = (down == most1) ? most2 : most1; + } + partition -= scaledtexheight; + dc_texturemid -= texheight; + } + ProcessWall(x1, x2, up, dwal, swal, lwal, yrepeat, wallshade, mask); + } + else + { // upside down: draw strips from bottom to top + partition = bot - fmod(bot - dc_texturemid / yrepeat - ViewPos.Z, scaledtexheight); + up = most1; + down = dwal; + dc_texturemid = (partition - ViewPos.Z) * yrepeat + texheight; + while (partition < top) + { + int j = R_CreateWallSegmentY(most3, partition - ViewPos.Z, &WallC); + if (j != 12) + { + for (int j = x1; j < x2; ++j) + { + up[j] = clamp(most3[j], uwal[j], down[j]); + } + ProcessWall(x1, x2, up, down, swal, lwal, yrepeat, wallshade, mask); + down = up; + up = (up == most1) ? most2 : most1; + } + partition -= scaledtexheight; + dc_texturemid -= texheight; + } + ProcessWall(x1, x2, uwal, down, swal, lwal, yrepeat, wallshade, mask); + } + } + + void R_DrawDrawSeg(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade) + { + if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) + { + double frontcz1 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v1); + double frontfz1 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v1); + double frontcz2 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v2); + double frontfz2 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v2); + double top = MAX(frontcz1, frontcz2); + double bot = MIN(frontfz1, frontfz2); + if (fake3D & FAKE3D_CLIPTOP) + { + top = MIN(top, sclipTop); + } + if (fake3D & FAKE3D_CLIPBOTTOM) + { + bot = MAX(bot, sclipBottom); + } + ProcessWallNP2(x1, x2, uwal, dwal, swal, lwal, yrepeat, top, bot, wallshade, true); + } + else + { + ProcessWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, true); + } + } + + + void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, int wallshade, FLightNode *light_list) + { + dc_light_list = light_list; + if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) + { + ProcessWallNP2(x1, x2, walltop, wallbottom, swall, lwall, yscale, top, bottom, wallshade, false); + } + else + { + ProcessWall(x1, x2, walltop, wallbottom, swall, lwall, yscale, wallshade, false); + } + dc_light_list = nullptr; + } + + void R_DrawSkySegment(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x)) + { + ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); + } +} diff --git a/src/swrenderer/scene/r_walldraw.h b/src/swrenderer/line/r_walldraw.h similarity index 97% rename from src/swrenderer/scene/r_walldraw.h rename to src/swrenderer/line/r_walldraw.h index 1a1a50504..9ca312fb0 100644 --- a/src/swrenderer/scene/r_walldraw.h +++ b/src/swrenderer/line/r_walldraw.h @@ -6,6 +6,8 @@ struct FLightNode; namespace swrenderer { + struct drawseg_t; + struct WallSampler { WallSampler() { } diff --git a/src/swrenderer/line/r_wallsetup.cpp b/src/swrenderer/line/r_wallsetup.cpp new file mode 100644 index 000000000..90ba7793a --- /dev/null +++ b/src/swrenderer/line/r_wallsetup.cpp @@ -0,0 +1,227 @@ + +#include +#include +#include "templates.h" +#include "i_system.h" +#include "doomdef.h" +#include "doomstat.h" +#include "doomdata.h" +#include "p_lnspec.h" +#include "r_sky.h" +#include "v_video.h" +#include "m_swap.h" +#include "w_wad.h" +#include "stats.h" +#include "a_sharedglobal.h" +#include "d_net.h" +#include "g_level.h" +#include "r_wallsetup.h" +#include "v_palette.h" +#include "r_data/colormaps.h" +#include "r_walldraw.h" +#include "swrenderer/r_main.h" +#include "swrenderer/r_memory.h" +#include "swrenderer/line/r_line.h" + +namespace swrenderer +{ + short walltop[MAXWIDTH]; + short wallbottom[MAXWIDTH]; + short wallupper[MAXWIDTH]; + short walllower[MAXWIDTH]; + float swall[MAXWIDTH]; + fixed_t lwall[MAXWIDTH]; + double lwallscale; + + int R_CreateWallSegmentY(short *outbuf, double z, const FWallCoords *wallc) + { + return R_CreateWallSegmentY(outbuf, z, z, wallc); + } + + int R_CreateWallSegmentY(short *outbuf, double z1, double z2, const FWallCoords *wallc) + { + float y1 = (float)(CenterY - z1 * InvZtoScale / wallc->sz1); + float y2 = (float)(CenterY - z2 * InvZtoScale / wallc->sz2); + + if (y1 < 0 && y2 < 0) // entire line is above screen + { + memset(&outbuf[wallc->sx1], 0, (wallc->sx2 - wallc->sx1) * sizeof(outbuf[0])); + return 3; + } + else if (y1 > viewheight && y2 > viewheight) // entire line is below screen + { + fillshort(&outbuf[wallc->sx1], wallc->sx2 - wallc->sx1, viewheight); + return 12; + } + + if (wallc->sx2 <= wallc->sx1) + return 0; + + float rcp_delta = 1.0f / (wallc->sx2 - wallc->sx1); + if (y1 >= 0.0f && y2 >= 0.0f && xs_RoundToInt(y1) <= viewheight && xs_RoundToInt(y2) <= viewheight) + { + for (int x = wallc->sx1; x < wallc->sx2; x++) + { + float t = (x - wallc->sx1) * rcp_delta; + float y = y1 * (1.0f - t) + y2 * t; + outbuf[x] = (short)xs_RoundToInt(y); + } + } + else + { + for (int x = wallc->sx1; x < wallc->sx2; x++) + { + float t = (x - wallc->sx1) * rcp_delta; + float y = y1 * (1.0f - t) + y2 * t; + outbuf[x] = (short)clamp(xs_RoundToInt(y), 0, viewheight); + } + } + + return 0; + } + + int R_CreateWallSegmentYSloped(short *outbuf, const secplane_t &plane, const FWallCoords *wallc, seg_t *curline, bool xflip) + { + if (!plane.isSlope()) + { + return R_CreateWallSegmentY(outbuf, plane.Zat0() - ViewPos.Z, wallc); + } + else + { + // Get Z coordinates at both ends of the line + double x, y, den, z1, z2; + if (xflip) + { + x = curline->v2->fX(); + y = curline->v2->fY(); + if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) + { + double frac = (wallc->tleft.Y + wallc->tleft.X) / den; + x -= frac * (x - curline->v1->fX()); + y -= frac * (y - curline->v1->fY()); + } + z1 = plane.ZatPoint(x, y) - ViewPos.Z; + + if (wallc->sx2 > wallc->sx1 + 1) + { + x = curline->v1->fX(); + y = curline->v1->fY(); + if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) + { + double frac = (wallc->tright.Y - wallc->tright.X) / den; + x += frac * (curline->v2->fX() - x); + y += frac * (curline->v2->fY() - y); + } + z2 = plane.ZatPoint(x, y) - ViewPos.Z; + } + else + { + z2 = z1; + } + } + else + { + x = curline->v1->fX(); + y = curline->v1->fY(); + if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) + { + double frac = (wallc->tleft.Y + wallc->tleft.X) / den; + x += frac * (curline->v2->fX() - x); + y += frac * (curline->v2->fY() - y); + } + z1 = plane.ZatPoint(x, y) - ViewPos.Z; + + if (wallc->sx2 > wallc->sx1 + 1) + { + x = curline->v2->fX(); + y = curline->v2->fY(); + if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) + { + double frac = (wallc->tright.Y - wallc->tright.X) / den; + x -= frac * (x - curline->v1->fX()); + y -= frac * (y - curline->v1->fY()); + } + z2 = plane.ZatPoint(x, y) - ViewPos.Z; + } + else + { + z2 = z1; + } + } + + return R_CreateWallSegmentY(outbuf, z1, z2, wallc); + } + } + + void PrepWall(float *vstep, fixed_t *upos, double walxrepeat, int x1, int x2) + { + float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); + float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); + float uGradient = WallT.UoverZstep; + float zGradient = WallT.InvZstep; + float xrepeat = (float)walxrepeat; + float depthScale = (float)(WallT.InvZstep * WallTMapScale2); + float depthOrg = (float)(-WallT.UoverZstep * WallTMapScale2); + + if (xrepeat < 0.0f) + { + for (int x = x1; x < x2; x++) + { + float u = uOverZ / invZ; + + upos[x] = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT); + vstep[x] = depthOrg + u * depthScale; + + uOverZ += uGradient; + invZ += zGradient; + } + } + else + { + for (int x = x1; x < x2; x++) + { + float u = uOverZ / invZ; + + upos[x] = (fixed_t)(u * xrepeat * FRACUNIT); + vstep[x] = depthOrg + u * depthScale; + + uOverZ += uGradient; + invZ += zGradient; + } + } + } + + void PrepLWall(fixed_t *upos, double walxrepeat, int x1, int x2) + { + float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); + float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); + float uGradient = WallT.UoverZstep; + float zGradient = WallT.InvZstep; + float xrepeat = (float)walxrepeat; + + if (xrepeat < 0.0f) + { + for (int x = x1; x < x2; x++) + { + float u = uOverZ / invZ * xrepeat - xrepeat; + + upos[x] = (fixed_t)(u * FRACUNIT); + + uOverZ += uGradient; + invZ += zGradient; + } + } + else + { + for (int x = x1; x < x2; x++) + { + float u = uOverZ / invZ * xrepeat; + + upos[x] = (fixed_t)(u * FRACUNIT); + + uOverZ += uGradient; + invZ += zGradient; + } + } + } +} diff --git a/src/swrenderer/line/r_wallsetup.h b/src/swrenderer/line/r_wallsetup.h new file mode 100644 index 000000000..4e483601f --- /dev/null +++ b/src/swrenderer/line/r_wallsetup.h @@ -0,0 +1,24 @@ + +#pragma once + +#include "r_defs.h" + +namespace swrenderer +{ + struct FWallCoords; + + extern short walltop[MAXWIDTH]; + extern short wallbottom[MAXWIDTH]; + extern short wallupper[MAXWIDTH]; + extern short walllower[MAXWIDTH]; + extern float swall[MAXWIDTH]; + extern fixed_t lwall[MAXWIDTH]; + extern double lwallscale; + + int R_CreateWallSegmentY(short *outbuf, double z1, double z2, const FWallCoords *wallc); + int R_CreateWallSegmentYSloped(short *outbuf, const secplane_t &plane, const FWallCoords *wallc, seg_t *line, bool xflip); + int R_CreateWallSegmentY(short *outbuf, double z, const FWallCoords *wallc); + + void PrepWall(float *swall, fixed_t *lwall, double walxrepeat, int x1, int x2); + void PrepLWall(fixed_t *lwall, double walxrepeat, int x1, int x2); +} diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 354396cc7..6d3206f23 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -24,7 +24,6 @@ #include "r_data/colormaps.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "gl/dynlights/gl_dynlight.h" -#include "swrenderer/scene/r_walldraw.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" diff --git a/src/swrenderer/plane/r_fogboundary.cpp b/src/swrenderer/plane/r_fogboundary.cpp index fb140db71..03eed8604 100644 --- a/src/swrenderer/plane/r_fogboundary.cpp +++ b/src/swrenderer/plane/r_fogboundary.cpp @@ -24,7 +24,6 @@ #include "r_data/colormaps.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "gl/dynlights/gl_dynlight.h" -#include "swrenderer/scene/r_walldraw.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index 5ad928ffa..e048751cc 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -24,9 +24,10 @@ #include "r_data/colormaps.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "gl/dynlights/gl_dynlight.h" -#include "swrenderer/scene/r_walldraw.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" +#include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/line/r_walldraw.h" #include "swrenderer/scene/r_portal.h" #include "swrenderer/r_memory.h" diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index 3742f2f40..4eb085ecf 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -24,7 +24,6 @@ #include "r_data/colormaps.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "gl/dynlights/gl_dynlight.h" -#include "swrenderer/scene/r_walldraw.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" diff --git a/src/swrenderer/scene/r_bsp.cpp b/src/swrenderer/scene/r_bsp.cpp index debee35c6..125a3ae21 100644 --- a/src/swrenderer/scene/r_bsp.cpp +++ b/src/swrenderer/scene/r_bsp.cpp @@ -37,6 +37,7 @@ #include "swrenderer/plane/r_visibleplane.h" #include "swrenderer/things/r_particle.h" #include "swrenderer/segments/r_clipsegment.h" +#include "swrenderer/line/r_wallsetup.h" #include "r_things.h" #include "r_3dfloors.h" #include "r_portal.h" @@ -76,19 +77,12 @@ extern bool rw_prepped; extern bool rw_havehigh, rw_havelow; extern int rw_floorstat, rw_ceilstat; extern bool rw_mustmarkfloor, rw_mustmarkceiling; -extern short walltop[MAXWIDTH]; // [RH] record max extents of wall -extern short wallbottom[MAXWIDTH]; -extern short wallupper[MAXWIDTH]; -extern short walllower[MAXWIDTH]; double rw_backcz1, rw_backcz2; double rw_backfz1, rw_backfz2; double rw_frontcz1, rw_frontcz2; double rw_frontfz1, rw_frontfz2; -FWallCoords WallC; -FWallTmapVals WallT; - static BYTE FakeSide; int WindowLeft, WindowRight; @@ -435,12 +429,12 @@ void R_AddLine (seg_t *line) if (rw_frontcz1 > rw_backcz1 || rw_frontcz2 > rw_backcz2) { rw_havehigh = true; - R_CreateWallSegmentYSloped (wallupper, backsector->ceilingplane, &WallC); + R_CreateWallSegmentYSloped (wallupper, backsector->ceilingplane, &WallC, curline, MirrorFlags & RF_XFLIP); } if (rw_frontfz1 < rw_backfz1 || rw_frontfz2 < rw_backfz2) { rw_havelow = true; - R_CreateWallSegmentYSloped (walllower, backsector->floorplane, &WallC); + R_CreateWallSegmentYSloped (walllower, backsector->floorplane, &WallC, curline, MirrorFlags & RF_XFLIP); } // Portal @@ -541,8 +535,8 @@ void R_AddLine (seg_t *line) } else { - rw_ceilstat = R_CreateWallSegmentYSloped (walltop, frontsector->ceilingplane, &WallC); - rw_floorstat = R_CreateWallSegmentYSloped (wallbottom, frontsector->floorplane, &WallC); + rw_ceilstat = R_CreateWallSegmentYSloped (walltop, frontsector->ceilingplane, &WallC, curline, MirrorFlags & RF_XFLIP); + rw_floorstat = R_CreateWallSegmentYSloped (wallbottom, frontsector->floorplane, &WallC, curline, MirrorFlags & RF_XFLIP); // [RH] treat off-screen walls as solid #if 0 // Maybe later... @@ -568,125 +562,26 @@ void R_AddLine (seg_t *line) } } -// -// FWallCoords :: Init -// -// Transform and clip coordinates. Returns true if it was clipped away -// -bool FWallCoords::Init(const DVector2 &pt1, const DVector2 &pt2, double too_close) -{ - tleft.X = float(pt1.X * ViewSin - pt1.Y * ViewCos); - tright.X = float(pt2.X * ViewSin - pt2.Y * ViewCos); - tleft.Y = float(pt1.X * ViewTanCos + pt1.Y * ViewTanSin); - tright.Y = float(pt2.X * ViewTanCos + pt2.Y * ViewTanSin); - - if (MirrorFlags & RF_XFLIP) - { - float t = -tleft.X; - tleft.X = -tright.X; - tright.X = t; - swapvalues(tleft.Y, tright.Y); - } - - if (tleft.X >= -tleft.Y) - { - if (tleft.X > tleft.Y) return true; // left edge is off the right side - if (tleft.Y == 0) return true; - sx1 = xs_RoundToInt(CenterX + tleft.X * CenterX / tleft.Y); - sz1 = tleft.Y; - } - else - { - if (tright.X < -tright.Y) return true; // wall is off the left side - float den = tleft.X - tright.X - tright.Y + tleft.Y; - if (den == 0) return true; - sx1 = 0; - sz1 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X + tleft.Y) / den; - } - - if (sz1 < too_close) - return true; - - if (tright.X <= tright.Y) - { - if (tright.X < -tright.Y) return true; // right edge is off the left side - if (tright.Y == 0) return true; - sx2 = xs_RoundToInt(CenterX + tright.X * CenterX / tright.Y); - sz2 = tright.Y; - } - else - { - if (tleft.X > tleft.Y) return true; // wall is off the right side - float den = tright.Y - tleft.Y - tright.X + tleft.X; - if (den == 0) return true; - sx2 = viewwidth; - sz2 = tleft.Y + (tright.Y - tleft.Y) * (tleft.X - tleft.Y) / den; - } - - if (sz2 < too_close || sx2 <= sx1) - return true; - - return false; -} - -void FWallTmapVals::InitFromWallCoords(const FWallCoords *wallc) -{ - const FVector2 *left = &wallc->tleft; - const FVector2 *right = &wallc->tright; - - if (MirrorFlags & RF_XFLIP) - { - swapvalues(left, right); - } - UoverZorg = left->X * centerx; - UoverZstep = -left->Y; - InvZorg = (left->X - right->X) * centerx; - InvZstep = right->Y - left->Y; -} - -void FWallTmapVals::InitFromLine(const DVector2 &left, const DVector2 &right) -{ // Coordinates should have already had viewx,viewy subtracted - double fullx1 = left.X * ViewSin - left.Y * ViewCos; - double fullx2 = right.X * ViewSin - right.Y * ViewCos; - double fully1 = left.X * ViewTanCos + left.Y * ViewTanSin; - double fully2 = right.X * ViewTanCos + right.Y * ViewTanSin; - - if (MirrorFlags & RF_XFLIP) - { - fullx1 = -fullx1; - fullx2 = -fullx2; - } - - UoverZorg = float(fullx1 * centerx); - UoverZstep = float(-fully1); - InvZorg = float((fullx1 - fullx2) * centerx); - InvZstep = float(fully2 - fully1); -} - -// -// R_CheckBBox // Checks BSP node/subtree bounding box. // Returns true if some part of the bbox might be visible. -// -extern "C" const int checkcoord[12][4] = -{ - {3,0,2,1}, - {3,0,2,0}, - {3,1,2,0}, - {0}, - {2,0,2,1}, - {0,0,0,0}, - {3,1,3,0}, - {0}, - {2,0,3,1}, - {2,1,3,1}, - {2,1,3,0} -}; - - static bool R_CheckBBox (float *bspcoord) // killough 1/28/98: static { + static const int checkcoord[12][4] = + { + { 3,0,2,1 }, + { 3,0,2,0 }, + { 3,1,2,0 }, + { 0 }, + { 2,0,2,1 }, + { 0,0,0,0 }, + { 3,1,3,0 }, + { 0 }, + { 2,0,3,1 }, + { 2,1,3,1 }, + { 2,1,3,0 } + }; + int boxx; int boxy; int boxpos; diff --git a/src/swrenderer/scene/r_bsp.h b/src/swrenderer/scene/r_bsp.h index 6996a684b..3ab94b288 100644 --- a/src/swrenderer/scene/r_bsp.h +++ b/src/swrenderer/scene/r_bsp.h @@ -37,29 +37,6 @@ namespace swrenderer // the texture calculations. #define TOO_CLOSE_Z (3072.0 / (1<<12)) -struct FWallCoords -{ - FVector2 tleft; // coords at left of wall in view space rx1,ry1 - FVector2 tright; // coords at right of wall in view space rx2,ry2 - - float sz1, sz2; // depth at left, right of wall in screen space yb1,yb2 - short sx1, sx2; // x coords at left, right of wall in screen space xb1,xb2 - - bool Init(const DVector2 &pt1, const DVector2 &pt2, double too_close); -}; - -struct FWallTmapVals -{ - float UoverZorg, UoverZstep; - float InvZorg, InvZstep; - - void InitFromWallCoords(const FWallCoords *wallc); - void InitFromLine(const DVector2 &left, const DVector2 &right); -}; - -extern FWallCoords WallC; -extern FWallTmapVals WallT; - enum { FAKED_Center, @@ -78,8 +55,6 @@ extern sector_t* backsector; extern int WindowLeft, WindowRight; extern WORD MirrorFlags; -typedef void (*drawfunc_t) (int start, int stop); - void R_RenderBSPNode (void *node); // killough 4/13/98: fake floors/ceilings for deep water / fake ceilings: diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index acb87dbb2..26dbb2e1c 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -38,6 +38,7 @@ #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/scene/r_bsp.h" #include "swrenderer/r_main.h" #include "swrenderer/r_memory.h" diff --git a/src/swrenderer/scene/r_segs.cpp b/src/swrenderer/scene/r_segs.cpp index 051012973..575e82ef4 100644 --- a/src/swrenderer/scene/r_segs.cpp +++ b/src/swrenderer/scene/r_segs.cpp @@ -48,7 +48,9 @@ #include "swrenderer/drawers/r_draw.h" #include "v_palette.h" #include "r_data/colormaps.h" -#include "r_walldraw.h" +#include "swrenderer/line/r_line.h" +#include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/line/r_walldraw.h" #include "swrenderer/segments/r_drawsegment.h" #include "r_portal.h" #include "swrenderer/things/r_wallsprite.h" @@ -93,13 +95,6 @@ fixed_t rw_offset_mid; fixed_t rw_offset_bottom; -short walltop[MAXWIDTH]; // [RH] record max extents of wall -short wallbottom[MAXWIDTH]; -short wallupper[MAXWIDTH]; -short walllower[MAXWIDTH]; -float swall[MAXWIDTH]; -fixed_t lwall[MAXWIDTH]; -double lwallscale; // // regular wall @@ -198,13 +193,13 @@ void ClipMidtex(int x1, int x2) { short most[MAXWIDTH]; - R_CreateWallSegmentYSloped(most, curline->frontsector->ceilingplane, &WallC); + R_CreateWallSegmentYSloped(most, curline->frontsector->ceilingplane, &WallC, curline, MirrorFlags & RF_XFLIP); for (int i = x1; i < x2; ++i) { if (wallupper[i] < most[i]) wallupper[i] = most[i]; } - R_CreateWallSegmentYSloped(most, curline->frontsector->floorplane, &WallC); + R_CreateWallSegmentYSloped(most, curline->frontsector->floorplane, &WallC, curline, MirrorFlags & RF_XFLIP); for (int i = x1; i < x2; ++i) { if (walllower[i] > most[i]) @@ -1327,7 +1322,7 @@ void R_NewWall (bool needlights) // wall but nothing to draw for it. // Recalculate walltop so that the wall is clipped by the back sector's // ceiling instead of the front sector's ceiling. - R_CreateWallSegmentYSloped (walltop, backsector->ceilingplane, &WallC); + R_CreateWallSegmentYSloped (walltop, backsector->ceilingplane, &WallC, curline, MirrorFlags & RF_XFLIP); } // Putting sky ceilings on the front and back of a line alters the way unpegged // positioning works. @@ -1856,191 +1851,5 @@ bool R_StoreWallRange (int start, int stop) return !(fake3D & FAKE3D_FAKEMASK); } -int R_CreateWallSegmentY(short *outbuf, double z1, double z2, const FWallCoords *wallc) -{ - float y1 = (float)(CenterY - z1 * InvZtoScale / wallc->sz1); - float y2 = (float)(CenterY - z2 * InvZtoScale / wallc->sz2); - - if (y1 < 0 && y2 < 0) // entire line is above screen - { - memset(&outbuf[wallc->sx1], 0, (wallc->sx2 - wallc->sx1) * sizeof(outbuf[0])); - return 3; - } - else if (y1 > viewheight && y2 > viewheight) // entire line is below screen - { - fillshort(&outbuf[wallc->sx1], wallc->sx2 - wallc->sx1, viewheight); - return 12; - } - - if (wallc->sx2 <= wallc->sx1) - return 0; - - float rcp_delta = 1.0f / (wallc->sx2 - wallc->sx1); - if (y1 >= 0.0f && y2 >= 0.0f && xs_RoundToInt(y1) <= viewheight && xs_RoundToInt(y2) <= viewheight) - { - for (int x = wallc->sx1; x < wallc->sx2; x++) - { - float t = (x - wallc->sx1) * rcp_delta; - float y = y1 * (1.0f - t) + y2 * t; - outbuf[x] = (short)xs_RoundToInt(y); - } - } - else - { - for (int x = wallc->sx1; x < wallc->sx2; x++) - { - float t = (x - wallc->sx1) * rcp_delta; - float y = y1 * (1.0f - t) + y2 * t; - outbuf[x] = (short)clamp(xs_RoundToInt(y), 0, viewheight); - } - } - - return 0; -} - -int R_CreateWallSegmentYSloped(short *outbuf, const secplane_t &plane, const FWallCoords *wallc) -{ - if (!plane.isSlope()) - { - return R_CreateWallSegmentY(outbuf, plane.Zat0() - ViewPos.Z, wallc); - } - else - { - // Get Z coordinates at both ends of the line - double x, y, den, z1, z2; - if (MirrorFlags & RF_XFLIP) - { - x = curline->v2->fX(); - y = curline->v2->fY(); - if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) - { - double frac = (wallc->tleft.Y + wallc->tleft.X) / den; - x -= frac * (x - curline->v1->fX()); - y -= frac * (y - curline->v1->fY()); - } - z1 = plane.ZatPoint(x, y) - ViewPos.Z; - - if (wallc->sx2 > wallc->sx1 + 1) - { - x = curline->v1->fX(); - y = curline->v1->fY(); - if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) - { - double frac = (wallc->tright.Y - wallc->tright.X) / den; - x += frac * (curline->v2->fX() - x); - y += frac * (curline->v2->fY() - y); - } - z2 = plane.ZatPoint(x, y) - ViewPos.Z; - } - else - { - z2 = z1; - } - } - else - { - x = curline->v1->fX(); - y = curline->v1->fY(); - if (wallc->sx1 == 0 && 0 != (den = wallc->tleft.X - wallc->tright.X + wallc->tleft.Y - wallc->tright.Y)) - { - double frac = (wallc->tleft.Y + wallc->tleft.X) / den; - x += frac * (curline->v2->fX() - x); - y += frac * (curline->v2->fY() - y); - } - z1 = plane.ZatPoint(x, y) - ViewPos.Z; - - if (wallc->sx2 > wallc->sx1 + 1) - { - x = curline->v2->fX(); - y = curline->v2->fY(); - if (wallc->sx2 == viewwidth && 0 != (den = wallc->tleft.X - wallc->tright.X - wallc->tleft.Y + wallc->tright.Y)) - { - double frac = (wallc->tright.Y - wallc->tright.X) / den; - x -= frac * (x - curline->v1->fX()); - y -= frac * (y - curline->v1->fY()); - } - z2 = plane.ZatPoint(x, y) - ViewPos.Z; - } - else - { - z2 = z1; - } - } - - return R_CreateWallSegmentY(outbuf, z1, z2, wallc); - } -} - -void PrepWall(float *vstep, fixed_t *upos, double walxrepeat, int x1, int x2) -{ - float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); - float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); - float uGradient = WallT.UoverZstep; - float zGradient = WallT.InvZstep; - float xrepeat = (float)walxrepeat; - float depthScale = (float)(WallT.InvZstep * WallTMapScale2); - float depthOrg = (float)(-WallT.UoverZstep * WallTMapScale2); - - if (xrepeat < 0.0f) - { - for (int x = x1; x < x2; x++) - { - float u = uOverZ / invZ; - - upos[x] = (fixed_t)((xrepeat - u * xrepeat) * FRACUNIT); - vstep[x] = depthOrg + u * depthScale; - - uOverZ += uGradient; - invZ += zGradient; - } - } - else - { - for (int x = x1; x < x2; x++) - { - float u = uOverZ / invZ; - - upos[x] = (fixed_t)(u * xrepeat * FRACUNIT); - vstep[x] = depthOrg + u * depthScale; - - uOverZ += uGradient; - invZ += zGradient; - } - } -} - -void PrepLWall(fixed_t *upos, double walxrepeat, int x1, int x2) -{ - float uOverZ = WallT.UoverZorg + WallT.UoverZstep * (float)(x1 + 0.5 - CenterX); - float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX); - float uGradient = WallT.UoverZstep; - float zGradient = WallT.InvZstep; - float xrepeat = (float)walxrepeat; - - if (xrepeat < 0.0f) - { - for (int x = x1; x < x2; x++) - { - float u = uOverZ / invZ * xrepeat - xrepeat; - - upos[x] = (fixed_t)(u * FRACUNIT); - - uOverZ += uGradient; - invZ += zGradient; - } - } - else - { - for (int x = x1; x < x2; x++) - { - float u = uOverZ / invZ * xrepeat; - - upos[x] = (fixed_t)(u * FRACUNIT); - - uOverZ += uGradient; - invZ += zGradient; - } - } -} } diff --git a/src/swrenderer/scene/r_segs.h b/src/swrenderer/scene/r_segs.h index f4ca36e4f..6f0fce65f 100644 --- a/src/swrenderer/scene/r_segs.h +++ b/src/swrenderer/scene/r_segs.h @@ -32,25 +32,10 @@ struct visplane_t; bool R_StoreWallRange(int start, int stop); void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2); -int R_CreateWallSegmentY (short *outbuf, double z1, double z2, const FWallCoords *wallc); -int R_CreateWallSegmentYSloped (short *outbuf, const secplane_t &plane, const FWallCoords *wallc); -inline int R_CreateWallSegmentY(short *outbuf, double z, const FWallCoords *wallc) -{ - return R_CreateWallSegmentY(outbuf, z, z, wallc); -} -void PrepWall (float *swall, fixed_t *lwall, double walxrepeat, int x1, int x2); -void PrepLWall (fixed_t *lwall, double walxrepeat, int x1, int x2); void R_RenderSegLoop (); -extern short walltop[MAXWIDTH]; // [RH] record max extents of wall -extern short wallbottom[MAXWIDTH]; -extern short wallupper[MAXWIDTH]; -extern short walllower[MAXWIDTH]; -extern float swall[MAXWIDTH]; -extern fixed_t lwall[MAXWIDTH]; -extern double lwallscale; extern float rw_light; // [RH] Scale lights with viewsize adjustments extern float rw_lightstep; extern float rw_lightleft; diff --git a/src/swrenderer/scene/r_walldraw.cpp b/src/swrenderer/scene/r_walldraw.cpp deleted file mode 100644 index 21b734872..000000000 --- a/src/swrenderer/scene/r_walldraw.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/* -** Wall drawing stuff free of Build pollution -** Copyright (c) 2016 Magnus Norddahl -** -** This software is provided 'as-is', without any express or implied -** warranty. In no event will the authors be held liable for any damages -** arising from the use of this software. -** -** Permission is granted to anyone to use this software for any purpose, -** including commercial applications, and to alter it and redistribute it -** freely, subject to the following restrictions: -** -** 1. The origin of this software must not be misrepresented; you must not -** claim that you wrote the original software. If you use this software -** in a product, an acknowledgment in the product documentation would be -** appreciated but is not required. -** 2. Altered source versions must be plainly marked as such, and must not be -** misrepresented as being the original software. -** 3. This notice may not be removed or altered from any source distribution. -** -*/ - -#include -#include - -#include "doomdef.h" -#include "doomstat.h" -#include "doomdata.h" - -#include "swrenderer/r_main.h" -#include "r_sky.h" -#include "v_video.h" - -#include "m_swap.h" -#include "a_sharedglobal.h" -#include "d_net.h" -#include "g_level.h" -#include "swrenderer/drawers/r_draw.h" -#include "r_bsp.h" -#include "r_segs.h" -#include "r_3dfloors.h" -#include "v_palette.h" -#include "r_data/colormaps.h" -#include "gl/dynlights/gl_dynlight.h" -#include "swrenderer/drawers/r_drawers.h" -#include "r_walldraw.h" -#include "swrenderer/segments/r_drawsegment.h" - -namespace swrenderer -{ - using namespace drawerargs; - - extern FTexture *rw_pic; - -static const uint8_t *R_GetColumn(FTexture *tex, int col) -{ - int width; - - // If the texture's width isn't a power of 2, then we need to make it a - // positive offset for proper clamping. - if (col < 0 && (width = tex->GetWidth()) != (1 << tex->WidthBits)) - { - col = width + (col % width); - } - - if (r_swtruecolor) - return (const uint8_t *)tex->GetColumnBgra(col, nullptr); - else - return tex->GetColumn(col, nullptr); -} - -WallSampler::WallSampler(int y1, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)) -{ - xoffset += FLOAT2FIXED(xmagnitude * 0.5); - - if (!r_swtruecolor) - { - height = texture->GetHeight(); - - int uv_fracbits = 32 - texture->HeightBits; - if (uv_fracbits != 32) - { - uv_max = height << uv_fracbits; - - // Find start uv in [0-base_height[ range. - // Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range. - double uv_stepd = swal * yrepeat; - double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height; - v = v - floor(v); - v *= height; - v *= (1 << uv_fracbits); - - uv_pos = (uint32_t)v; - uv_step = xs_ToFixed(uv_fracbits, uv_stepd); - if (uv_step == 0) // To prevent divide by zero elsewhere - uv_step = 1; - } - else - { // Hack for one pixel tall textures - uv_pos = 0; - uv_step = 0; - uv_max = 1; - } - - source = getcol(texture, xoffset >> FRACBITS); - source2 = nullptr; - texturefracx = 0; - } - else - { - // Normalize to 0-1 range: - double uv_stepd = swal * yrepeat; - double v = (dc_texturemid + uv_stepd * (y1 - CenterY + 0.5)) / texture->GetHeight(); - v = v - floor(v); - double v_step = uv_stepd / texture->GetHeight(); - - if (isnan(v) || isnan(v_step)) // this should never happen, but it apparently does.. - { - uv_stepd = 0.0; - v = 0.0; - v_step = 0.0; - } - - // Convert to uint32: - uv_pos = (uint32_t)(v * 0x100000000LL); - uv_step = (uint32_t)(v_step * 0x100000000LL); - uv_max = 0; - - // Texture mipmap and filter selection: - if (getcol != R_GetColumn) - { - source = getcol(texture, xoffset >> FRACBITS); - source2 = nullptr; - height = texture->GetHeight(); - texturefracx = 0; - } - else - { - double ymagnitude = fabs(uv_stepd); - double magnitude = MAX(ymagnitude, xmagnitude); - double min_lod = -1000.0; - double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); - bool magnifying = lod < 0.0f; - - int mipmap_offset = 0; - int mip_width = texture->GetWidth(); - int mip_height = texture->GetHeight(); - if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1) - { - uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); - - int level = (int)lod; - while (level > 0 && mip_width > 1 && mip_height > 1) - { - mipmap_offset += mip_width * mip_height; - level--; - mip_width = MAX(mip_width >> 1, 1); - mip_height = MAX(mip_height >> 1, 1); - } - xoffset = (xpos >> FRACBITS) * mip_width; - } - - const uint32_t *pixels = texture->GetPixelsBgra() + mipmap_offset; - - bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); - if (filter_nearest) - { - int tx = (xoffset >> FRACBITS) % mip_width; - if (tx < 0) - tx += mip_width; - source = (BYTE*)(pixels + tx * mip_height); - source2 = nullptr; - height = mip_height; - texturefracx = 0; - } - else - { - xoffset -= FRACUNIT / 2; - int tx0 = (xoffset >> FRACBITS) % mip_width; - if (tx0 < 0) - tx0 += mip_width; - int tx1 = (tx0 + 1) % mip_width; - source = (BYTE*)(pixels + tx0 * mip_height); - source2 = (BYTE*)(pixels + tx1 * mip_height); - height = mip_height; - texturefracx = (xoffset >> (FRACBITS - 4)) & 15; - } - } - } -} - -// Draw a column with support for non-power-of-two ranges -static void Draw1Column(int x, int y1, int y2, WallSampler &sampler, DrawerFunc draw1column) -{ - if (r_dynlights) - { - // Find column position in view space - float w1 = 1.0f / WallC.sz1; - float w2 = 1.0f / WallC.sz2; - float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1); - float wcol = w1 * (1.0f - t) + w2 * t; - float zcol = 1.0f / wcol; - dc_viewpos.X = (float)((x + 0.5 - CenterX) / CenterX * zcol); - dc_viewpos.Y = zcol; - dc_viewpos.Z = (float)((CenterY - y1 - 0.5) / InvZtoScale * zcol); - dc_viewpos_step.Z = (float)(-zcol / InvZtoScale); - - static TriLight lightbuffer[64 * 1024]; - static int nextlightindex = 0; - - // Setup lights for column - dc_num_lights = 0; - dc_lights = lightbuffer + nextlightindex; - FLightNode *cur_node = dc_light_list; - while (cur_node && nextlightindex < 64 * 1024) - { - if (!(cur_node->lightsource->flags2&MF2_DORMANT)) - { - double lightX = cur_node->lightsource->X() - ViewPos.X; - double lightY = cur_node->lightsource->Y() - ViewPos.Y; - double lightZ = cur_node->lightsource->Z() - ViewPos.Z; - - float lx = (float)(lightX * ViewSin - lightY * ViewCos) - dc_viewpos.X; - float ly = (float)(lightX * ViewTanCos + lightY * ViewTanSin) - dc_viewpos.Y; - float lz = (float)lightZ; - - // Precalculate the constant part of the dot here so the drawer doesn't have to. - float lconstant = lx * lx + ly * ly; - - // Include light only if it touches this column - float radius = cur_node->lightsource->GetRadius(); - if (radius * radius >= lconstant) - { - uint32_t red = cur_node->lightsource->GetRed(); - uint32_t green = cur_node->lightsource->GetGreen(); - uint32_t blue = cur_node->lightsource->GetBlue(); - - nextlightindex++; - auto &light = dc_lights[dc_num_lights++]; - light.x = lconstant; - light.z = lz; - light.radius = 256.0f / cur_node->lightsource->GetRadius(); - light.color = (red << 16) | (green << 8) | blue; - } - } - - cur_node = cur_node->nextLight; - } - - if (nextlightindex == 64 * 1024) - nextlightindex = 0; - } - else - { - dc_num_lights = 0; - } - - if (r_swtruecolor) - { - int count = y2 - y1; - - dc_source = sampler.source; - dc_source2 = sampler.source2; - dc_texturefracx = sampler.texturefracx; - dc_dest = (ylookup[y1] + x) * 4 + dc_destorg; - dc_count = count; - dc_iscale = sampler.uv_step; - dc_texturefrac = sampler.uv_pos; - dc_textureheight = sampler.height; - (R_Drawers()->*draw1column)(); - - uint64_t step64 = sampler.uv_step; - uint64_t pos64 = sampler.uv_pos; - sampler.uv_pos = (uint32_t)(pos64 + step64 * count); - } - else - { - if (sampler.uv_max == 0 || sampler.uv_step == 0) // power of two - { - int count = y2 - y1; - - dc_source = sampler.source; - dc_source2 = sampler.source2; - dc_texturefracx = sampler.texturefracx; - dc_dest = (ylookup[y1] + x) + dc_destorg; - dc_count = count; - dc_iscale = sampler.uv_step; - dc_texturefrac = sampler.uv_pos; - (R_Drawers()->*draw1column)(); - - uint64_t step64 = sampler.uv_step; - uint64_t pos64 = sampler.uv_pos; - sampler.uv_pos = (uint32_t)(pos64 + step64 * count); - } - else - { - uint32_t uv_pos = sampler.uv_pos; - - uint32_t left = y2 - y1; - while (left > 0) - { - uint32_t available = sampler.uv_max - uv_pos; - uint32_t next_uv_wrap = available / sampler.uv_step; - if (available % sampler.uv_step != 0) - next_uv_wrap++; - uint32_t count = MIN(left, next_uv_wrap); - - dc_source = sampler.source; - dc_source2 = sampler.source2; - dc_texturefracx = sampler.texturefracx; - dc_dest = (ylookup[y1] + x) + dc_destorg; - dc_count = count; - dc_iscale = sampler.uv_step; - dc_texturefrac = uv_pos; - (R_Drawers()->*draw1column)(); - - left -= count; - uv_pos += sampler.uv_step * count; - if (uv_pos >= sampler.uv_max) - uv_pos -= sampler.uv_max; - } - - sampler.uv_pos = uv_pos; - } - } -} - -static void ProcessWallWorker( - int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, - const BYTE *(*getcol)(FTexture *tex, int x), DrawerFunc drawcolumn) -{ - if (rw_pic->UseType == FTexture::TEX_Null) - return; - - fixed_t xoffset = rw_offset; - - rw_pic->GetHeight(); // To ensure that rw_pic->HeightBits has been set - int fracbits = 32 - rw_pic->HeightBits; - if (fracbits == 32) - { // Hack for one pixel tall textures - fracbits = 0; - yrepeat = 0; - dc_texturemid = 0; - } - - dc_wall_fracbits = r_swtruecolor ? FRACBITS : fracbits; - - bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0); - if (fixed) - { - dc_wall_colormap[0] = dc_colormap; - dc_wall_colormap[1] = dc_colormap; - dc_wall_colormap[2] = dc_colormap; - dc_wall_colormap[3] = dc_colormap; - dc_wall_light[0] = 0; - dc_wall_light[1] = 0; - dc_wall_light[2] = 0; - dc_wall_light[3] = 0; - } - - if (fixedcolormap) - R_SetColorMapLight(fixedcolormap, 0, 0); - else - R_SetColorMapLight(basecolormap, 0, 0); - - float light = rw_light; - - double xmagnitude = 1.0; - - for (int x = x1; x < x2; x++, light += rw_lightstep) - { - int y1 = uwal[x]; - int y2 = dwal[x]; - if (y2 <= y1) - continue; - - if (!fixed) - R_SetColorMapLight(basecolormap, light, wallshade); - - if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); - - WallSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic, getcol); - Draw1Column(x, y1, y2, sampler, drawcolumn); - } - - NetUpdate(); -} - -static void ProcessNormalWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) -{ - ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, &SWPixelFormatDrawers::DrawWallColumn); -} - -static void ProcessMaskedWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) -{ - if (!rw_pic->bMasked) // Textures that aren't masked can use the faster ProcessNormalWall. - { - ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); - } - else - { - ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, &SWPixelFormatDrawers::DrawWallMaskedColumn); - } -} - -static void ProcessTranslucentWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) -{ - DrawerFunc drawcol1 = R_GetTransMaskDrawer(); - if (drawcol1 == nullptr) - { - // The current translucency is unsupported, so draw with regular ProcessMaskedWall instead. - ProcessMaskedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); - } - else - { - ProcessWallWorker(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol, drawcol1); - } -} - -static void ProcessStripedWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade) -{ - FDynamicColormap *startcolormap = basecolormap; - bool fogginess = foggy; - - short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH]; - short *up, *down; - - up = uwal; - down = most1; - - assert(WallC.sx1 <= x1); - assert(WallC.sx2 >= x2); - - // kg3D - fake floors instead of zdoom light list - for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++) - { - int j = R_CreateWallSegmentYSloped (most3, frontsector->e->XFloor.lightlist[i].plane, &WallC); - if (j != 3) - { - for (int j = x1; j < x2; ++j) - { - down[j] = clamp (most3[j], up[j], dwal[j]); - } - ProcessNormalWall (x1, x2, up, down, swal, lwal, yrepeat, wallshade); - up = down; - down = (down == most1) ? most2 : most1; - } - - lightlist_t *lit = &frontsector->e->XFloor.lightlist[i]; - basecolormap = lit->extra_colormap; - wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight); - } - - ProcessNormalWall (x1, x2, up, dwal, swal, lwal, yrepeat, wallshade); - basecolormap = startcolormap; -} - -static void ProcessWall(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, bool mask) -{ - if (mask) - { - if (colfunc == basecolfunc) - { - ProcessMaskedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); - } - else - { - ProcessTranslucentWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); - } - } - else - { - if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size())) - { - ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); - } - else - { - ProcessStripedWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade); - } - } -} - -//============================================================================= -// -// ProcessWallNP2 -// -// This is a wrapper around ProcessWall that helps it tile textures whose heights -// are not powers of 2. It divides the wall into texture-sized strips and calls -// ProcessNormalWall for each of those. Since only one repetition of the texture fits -// in each strip, ProcessWall will not tile. -// -//============================================================================= - -static void ProcessWallNP2(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, double top, double bot, int wallshade, bool mask) -{ - short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH]; - short *up, *down; - double texheight = rw_pic->GetHeight(); - double partition; - double scaledtexheight = texheight / yrepeat; - - if (yrepeat >= 0) - { // normal orientation: draw strips from top to bottom - partition = top - fmod(top - dc_texturemid / yrepeat - ViewPos.Z, scaledtexheight); - if (partition == top) - { - partition -= scaledtexheight; - } - up = uwal; - down = most1; - dc_texturemid = (partition - ViewPos.Z) * yrepeat + texheight; - while (partition > bot) - { - int j = R_CreateWallSegmentY(most3, partition - ViewPos.Z, &WallC); - if (j != 3) - { - for (int j = x1; j < x2; ++j) - { - down[j] = clamp(most3[j], up[j], dwal[j]); - } - ProcessWall(x1, x2, up, down, swal, lwal, yrepeat, wallshade, mask); - up = down; - down = (down == most1) ? most2 : most1; - } - partition -= scaledtexheight; - dc_texturemid -= texheight; - } - ProcessWall(x1, x2, up, dwal, swal, lwal, yrepeat, wallshade, mask); - } - else - { // upside down: draw strips from bottom to top - partition = bot - fmod(bot - dc_texturemid / yrepeat - ViewPos.Z, scaledtexheight); - up = most1; - down = dwal; - dc_texturemid = (partition - ViewPos.Z) * yrepeat + texheight; - while (partition < top) - { - int j = R_CreateWallSegmentY(most3, partition - ViewPos.Z, &WallC); - if (j != 12) - { - for (int j = x1; j < x2; ++j) - { - up[j] = clamp(most3[j], uwal[j], down[j]); - } - ProcessWall(x1, x2, up, down, swal, lwal, yrepeat, wallshade, mask); - down = up; - up = (up == most1) ? most2 : most1; - } - partition -= scaledtexheight; - dc_texturemid -= texheight; - } - ProcessWall(x1, x2, uwal, down, swal, lwal, yrepeat, wallshade, mask); - } -} - -void R_DrawDrawSeg(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade) -{ - if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) - { - double frontcz1 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v1); - double frontfz1 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v1); - double frontcz2 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v2); - double frontfz2 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v2); - double top = MAX(frontcz1, frontcz2); - double bot = MIN(frontfz1, frontfz2); - if (fake3D & FAKE3D_CLIPTOP) - { - top = MIN(top, sclipTop); - } - if (fake3D & FAKE3D_CLIPBOTTOM) - { - bot = MAX(bot, sclipBottom); - } - ProcessWallNP2(x1, x2, uwal, dwal, swal, lwal, yrepeat, top, bot, wallshade, true); - } - else - { - ProcessWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, true); - } -} - - -void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, int wallshade, FLightNode *light_list) -{ - dc_light_list = light_list; - if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) - { - ProcessWallNP2(x1, x2, walltop, wallbottom, swall, lwall, yscale, top, bottom, wallshade, false); - } - else - { - ProcessWall(x1, x2, walltop, wallbottom, swall, lwall, yscale, wallshade, false); - } - dc_light_list = nullptr; -} - -void R_DrawSkySegment(int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, int wallshade, const BYTE *(*getcol)(FTexture *tex, int x)) -{ - ProcessNormalWall(x1, x2, uwal, dwal, swal, lwal, yrepeat, wallshade, getcol); -} - -} \ No newline at end of file diff --git a/src/swrenderer/segments/r_drawsegment.h b/src/swrenderer/segments/r_drawsegment.h index 7174794a3..234a14bc0 100644 --- a/src/swrenderer/segments/r_drawsegment.h +++ b/src/swrenderer/segments/r_drawsegment.h @@ -1,7 +1,7 @@ #pragma once -#include "swrenderer/scene/r_bsp.h" +#include "swrenderer/line/r_line.h" namespace swrenderer { diff --git a/src/swrenderer/things/r_decal.cpp b/src/swrenderer/things/r_decal.cpp index c4a90b414..5aa67a550 100644 --- a/src/swrenderer/things/r_decal.cpp +++ b/src/swrenderer/things/r_decal.cpp @@ -23,7 +23,8 @@ #include "swrenderer/drawers/r_draw.h" #include "v_palette.h" #include "r_data/colormaps.h" -#include "swrenderer/scene/r_walldraw.h" +#include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/line/r_walldraw.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" #include "r_wallsprite.h" diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index 01f7ab3af..090a75706 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -1,7 +1,7 @@ #pragma once -#include "swrenderer/scene/r_bsp.h" +#include "swrenderer/line/r_line.h" struct particle_t; struct FVoxel; diff --git a/src/swrenderer/things/r_wallsprite.cpp b/src/swrenderer/things/r_wallsprite.cpp index 9d7e03c2a..400c1e163 100644 --- a/src/swrenderer/things/r_wallsprite.cpp +++ b/src/swrenderer/things/r_wallsprite.cpp @@ -41,6 +41,8 @@ #include "r_voxel.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" +#include "swrenderer/line/r_wallsetup.h" +#include "swrenderer/line/r_walldraw.h" #include "swrenderer/r_memory.h" namespace swrenderer