diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e59a0fce4e..0b5b9ff777 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -830,6 +830,7 @@ set( FASTMATH_PCH_SOURCES swrenderer/scene/r_particle.cpp swrenderer/scene/r_playersprite.cpp swrenderer/scene/r_wallsprite.cpp + swrenderer/scene/r_decal.cpp polyrenderer/poly_renderer.cpp polyrenderer/scene/poly_scene.cpp polyrenderer/scene/poly_portal.cpp diff --git a/src/swrenderer/drawers/r_draw_rgba.cpp b/src/swrenderer/drawers/r_draw_rgba.cpp index 90c1ec21af..21f7da8286 100644 --- a/src/swrenderer/drawers/r_draw_rgba.cpp +++ b/src/swrenderer/drawers/r_draw_rgba.cpp @@ -60,13 +60,6 @@ CVAR(Float, r_lod_bias, -1.5, 0); // To do: add CVAR_ARCHIVE | CVAR_GLOBALCONFIG namespace swrenderer { - extern "C" short spanend[MAXHEIGHT]; - extern float rw_light; - extern float rw_lightstep; - extern int wallshade; - - ///////////////////////////////////////////////////////////////////////////// - DrawSpanLLVMCommand::DrawSpanLLVMCommand() { using namespace drawerargs; diff --git a/src/swrenderer/scene/r_decal.cpp b/src/swrenderer/scene/r_decal.cpp new file mode 100644 index 0000000000..374552621e --- /dev/null +++ b/src/swrenderer/scene/r_decal.cpp @@ -0,0 +1,296 @@ + +#include +#include +#include "templates.h" +#include "i_system.h" +#include "doomdef.h" +#include "doomstat.h" +#include "doomdata.h" +#include "p_lnspec.h" +#include "swrenderer/r_main.h" +#include "swrenderer/scene/r_things.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_bsp.h" +#include "r_plane.h" +#include "r_decal.h" +#include "r_3dfloors.h" +#include "swrenderer/drawers/r_draw.h" +#include "v_palette.h" +#include "r_data/colormaps.h" +#include "r_walldraw.h" +#include "r_draw_segment.h" +#include "r_portal.h" +#include "r_wallsprite.h" +#include "r_draw_segment.h" +#include "r_segs.h" +#include "swrenderer/r_memory.h" + +namespace swrenderer +{ + void R_RenderDecals(side_t *sidedef, drawseg_t *draw_segment) + { + for (DBaseDecal *decal = sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext) + { + R_RenderDecal(sidedef, decal, draw_segment, 0); + } + } + + // pass = 0: when seg is first drawn + // = 1: drawing masked textures (including sprites) + // Currently, only pass = 0 is done or used + + void R_RenderDecal(side_t *wall, DBaseDecal *decal, drawseg_t *clipper, int pass) + { + DVector2 decal_left, decal_right, decal_pos; + int x1, x2; + double yscale; + BYTE flipx; + double zpos; + int needrepeat = 0; + sector_t *front, *back; + bool calclighting; + bool rereadcolormap; + FDynamicColormap *usecolormap; + + if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) + return; + + // Determine actor z + zpos = decal->Z; + front = curline->frontsector; + back = (curline->backsector != NULL) ? curline->backsector : curline->frontsector; + switch (decal->RenderFlags & RF_RELMASK) + { + default: + zpos = decal->Z; + break; + case RF_RELUPPER: + if (curline->linedef->flags & ML_DONTPEGTOP) + { + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + } + else + { + zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling); + } + break; + case RF_RELLOWER: + if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + } + else + { + zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor); + } + break; + case RF_RELMID: + if (curline->linedef->flags & ML_DONTPEGBOTTOM) + { + zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor); + } + else + { + zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); + } + } + + WallSpriteTile = TexMan(decal->PicNum, true); + flipx = (BYTE)(decal->RenderFlags & RF_XFLIP); + + if (WallSpriteTile == NULL || WallSpriteTile->UseType == FTexture::TEX_Null) + { + return; + } + + // Determine left and right edges of sprite. Since this sprite is bound + // to a wall, we use the wall's angle instead of the decal's. This is + // pretty much the same as what R_AddLine() does. + + FWallCoords savecoord = WallC; + + double edge_right = WallSpriteTile->GetWidth(); + double edge_left = WallSpriteTile->LeftOffset; + edge_right = (edge_right - edge_left) * decal->ScaleX; + edge_left *= decal->ScaleX; + + double dcx, dcy; + decal->GetXY(wall, dcx, dcy); + decal_pos = { dcx, dcy }; + + DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit(); + + decal_left = decal_pos - edge_left * angvec - ViewPos; + decal_right = decal_pos + edge_right * angvec - ViewPos; + + if (WallC.Init(decal_left, decal_right, TOO_CLOSE_Z)) + goto done; + + x1 = WallC.sx1; + x2 = WallC.sx2; + + if (x1 >= clipper->x2 || x2 <= clipper->x1) + goto done; + + WallT.InitFromWallCoords(&WallC); + + // Get the top and bottom clipping arrays + switch (decal->RenderFlags & RF_CLIPMASK) + { + case RF_CLIPFULL: + if (curline->backsector == NULL) + { + if (pass != 0) + { + goto done; + } + mceilingclip = walltop; + mfloorclip = wallbottom; + } + else if (pass == 0) + { + mceilingclip = walltop; + mfloorclip = ceilingclip; + needrepeat = 1; + } + else + { + mceilingclip = openings + clipper->sprtopclip - clipper->x1; + mfloorclip = openings + clipper->sprbottomclip - clipper->x1; + } + break; + + case RF_CLIPUPPER: + if (pass != 0) + { + goto done; + } + mceilingclip = walltop; + mfloorclip = ceilingclip; + break; + + case RF_CLIPMID: + if (curline->backsector != NULL && pass != 2) + { + goto done; + } + mceilingclip = openings + clipper->sprtopclip - clipper->x1; + mfloorclip = openings + clipper->sprbottomclip - clipper->x1; + break; + + case RF_CLIPLOWER: + if (pass != 0) + { + goto done; + } + mceilingclip = floorclip; + mfloorclip = wallbottom; + break; + } + + yscale = decal->ScaleY; + dc_texturemid = WallSpriteTile->TopOffset + (zpos - ViewPos.Z) / yscale; + + // Clip sprite to drawseg + x1 = MAX(clipper->x1, x1); + x2 = MIN(clipper->x2, x2); + if (x1 >= x2) + { + goto done; + } + + PrepWall(swall, lwall, WallSpriteTile->GetWidth(), x1, x2); + + if (flipx) + { + int i; + int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1; + + for (i = x1; i < x2; i++) + { + lwall[i] = right - lwall[i]; + } + } + + // Prepare lighting + calclighting = false; + usecolormap = basecolormap; + rereadcolormap = true; + + // Decals that are added to the scene must fade to black. + if (decal->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0) + { + usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate); + rereadcolormap = false; + } + + rw_light = rw_lightleft + (x1 - savecoord.sx1) * rw_lightstep; + if (fixedlightlev >= 0) + R_SetColorMapLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, FIXEDLIGHT2SHADE(fixedlightlev)); + else if (fixedcolormap != NULL) + R_SetColorMapLight(fixedcolormap, 0, 0); + else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT)) + R_SetColorMapLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, 0); + else + calclighting = true; + + // Draw it + if (decal->RenderFlags & RF_YFLIP) + { + sprflipvert = true; + yscale = -yscale; + dc_texturemid -= WallSpriteTile->GetHeight(); + } + else + { + sprflipvert = false; + } + + float maskedScaleY = float(1 / yscale); + do + { + int x = x1; + + bool visible = R_SetPatchStyle(decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor); + + // R_SetPatchStyle can modify basecolormap. + if (rereadcolormap) + { + usecolormap = basecolormap; + } + + if (visible) + { + while (x < x2) + { + if (calclighting) + { // calculate lighting + R_SetColorMapLight(usecolormap, rw_light, wallshade); + } + R_WallSpriteColumn(x, maskedScaleY); + x++; + } + } + + // If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will + // be set 1 if we need to draw on the lower wall. In all other cases, + // needrepeat will be 0, and the while will fail. + mceilingclip = floorclip; + mfloorclip = wallbottom; + R_FinishSetPatchStyle(); + } while (needrepeat--); + + colfunc = basecolfunc; + + R_FinishSetPatchStyle(); + done: + WallC = savecoord; + } +} diff --git a/src/swrenderer/scene/r_decal.h b/src/swrenderer/scene/r_decal.h new file mode 100644 index 0000000000..8eeadb77ea --- /dev/null +++ b/src/swrenderer/scene/r_decal.h @@ -0,0 +1,13 @@ + +#pragma once + +struct side_t; +class DBaseDecal; + +namespace swrenderer +{ + struct drawseg_t; + + void R_RenderDecals(side_t *wall, drawseg_t *draw_segment); + void R_RenderDecal(side_t *wall, DBaseDecal *first, drawseg_t *clipper, int pass); +} diff --git a/src/swrenderer/scene/r_segs.cpp b/src/swrenderer/scene/r_segs.cpp index 0d6a9276cb..315411b936 100644 --- a/src/swrenderer/scene/r_segs.cpp +++ b/src/swrenderer/scene/r_segs.cpp @@ -52,6 +52,7 @@ #include "r_draw_segment.h" #include "r_portal.h" #include "r_wallsprite.h" +#include "r_decal.h" #include "swrenderer/r_memory.h" #define WALLYREPEAT 8 @@ -138,7 +139,6 @@ FTexture *rw_pic; static fixed_t *maskedtexturecol; -static void R_RenderDecal (side_t *wall, DBaseDecal *first, drawseg_t *clipper, int pass); inline bool IsFogBoundary (sector_t *front, sector_t *back) { @@ -1810,10 +1810,7 @@ bool R_StoreWallRange (int start, int stop) // [ZZ] Only if not an active mirror if (!rw_markportal) { - for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext) - { - R_RenderDecal (curline->sidedef, decal, draw_segment, 0); - } + R_RenderDecals(curline->sidedef, draw_segment); } if (rw_markportal) @@ -2035,256 +2032,4 @@ void PrepLWall(fixed_t *upos, double walxrepeat, int x1, int x2) } } -// pass = 0: when seg is first drawn -// = 1: drawing masked textures (including sprites) -// Currently, only pass = 0 is done or used - -static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, int pass) -{ - DVector2 decal_left, decal_right, decal_pos; - int x1, x2; - double yscale; - BYTE flipx; - double zpos; - int needrepeat = 0; - sector_t *front, *back; - bool calclighting; - bool rereadcolormap; - FDynamicColormap *usecolormap; - - if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) - return; - - // Determine actor z - zpos = decal->Z; - front = curline->frontsector; - back = (curline->backsector != NULL) ? curline->backsector : curline->frontsector; - switch (decal->RenderFlags & RF_RELMASK) - { - default: - zpos = decal->Z; - break; - case RF_RELUPPER: - if (curline->linedef->flags & ML_DONTPEGTOP) - { - zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); - } - else - { - zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling); - } - break; - case RF_RELLOWER: - if (curline->linedef->flags & ML_DONTPEGBOTTOM) - { - zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); - } - else - { - zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor); - } - break; - case RF_RELMID: - if (curline->linedef->flags & ML_DONTPEGBOTTOM) - { - zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor); - } - else - { - zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling); - } - } - - WallSpriteTile = TexMan(decal->PicNum, true); - flipx = (BYTE)(decal->RenderFlags & RF_XFLIP); - - if (WallSpriteTile == NULL || WallSpriteTile->UseType == FTexture::TEX_Null) - { - return; - } - - // Determine left and right edges of sprite. Since this sprite is bound - // to a wall, we use the wall's angle instead of the decal's. This is - // pretty much the same as what R_AddLine() does. - - FWallCoords savecoord = WallC; - - double edge_right = WallSpriteTile->GetWidth(); - double edge_left = WallSpriteTile->LeftOffset; - edge_right = (edge_right - edge_left) * decal->ScaleX; - edge_left *= decal->ScaleX; - - double dcx, dcy; - decal->GetXY(wall, dcx, dcy); - decal_pos = { dcx, dcy }; - - DVector2 angvec = (curline->v2->fPos() - curline->v1->fPos()).Unit(); - - decal_left = decal_pos - edge_left * angvec - ViewPos; - decal_right = decal_pos + edge_right * angvec - ViewPos; - - if (WallC.Init(decal_left, decal_right, TOO_CLOSE_Z)) - goto done; - - x1 = WallC.sx1; - x2 = WallC.sx2; - - if (x1 >= clipper->x2 || x2 <= clipper->x1) - goto done; - - WallT.InitFromWallCoords(&WallC); - - // Get the top and bottom clipping arrays - switch (decal->RenderFlags & RF_CLIPMASK) - { - case RF_CLIPFULL: - if (curline->backsector == NULL) - { - if (pass != 0) - { - goto done; - } - mceilingclip = walltop; - mfloorclip = wallbottom; - } - else if (pass == 0) - { - mceilingclip = walltop; - mfloorclip = ceilingclip; - needrepeat = 1; - } - else - { - mceilingclip = openings + clipper->sprtopclip - clipper->x1; - mfloorclip = openings + clipper->sprbottomclip - clipper->x1; - } - break; - - case RF_CLIPUPPER: - if (pass != 0) - { - goto done; - } - mceilingclip = walltop; - mfloorclip = ceilingclip; - break; - - case RF_CLIPMID: - if (curline->backsector != NULL && pass != 2) - { - goto done; - } - mceilingclip = openings + clipper->sprtopclip - clipper->x1; - mfloorclip = openings + clipper->sprbottomclip - clipper->x1; - break; - - case RF_CLIPLOWER: - if (pass != 0) - { - goto done; - } - mceilingclip = floorclip; - mfloorclip = wallbottom; - break; - } - - yscale = decal->ScaleY; - dc_texturemid = WallSpriteTile->TopOffset + (zpos - ViewPos.Z) / yscale; - - // Clip sprite to drawseg - x1 = MAX(clipper->x1, x1); - x2 = MIN(clipper->x2, x2); - if (x1 >= x2) - { - goto done; - } - - PrepWall (swall, lwall, WallSpriteTile->GetWidth(), x1, x2); - - if (flipx) - { - int i; - int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1; - - for (i = x1; i < x2; i++) - { - lwall[i] = right - lwall[i]; - } - } - - // Prepare lighting - calclighting = false; - usecolormap = basecolormap; - rereadcolormap = true; - - // Decals that are added to the scene must fade to black. - if (decal->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0) - { - usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate); - rereadcolormap = false; - } - - rw_light = rw_lightleft + (x1 - savecoord.sx1) * rw_lightstep; - if (fixedlightlev >= 0) - R_SetColorMapLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, FIXEDLIGHT2SHADE(fixedlightlev)); - else if (fixedcolormap != NULL) - R_SetColorMapLight(fixedcolormap, 0, 0); - else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT)) - R_SetColorMapLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, 0); - else - calclighting = true; - - // Draw it - if (decal->RenderFlags & RF_YFLIP) - { - sprflipvert = true; - yscale = -yscale; - dc_texturemid -= WallSpriteTile->GetHeight(); - } - else - { - sprflipvert = false; - } - - float maskedScaleY = float(1 / yscale); - do - { - int x = x1; - - bool visible = R_SetPatchStyle (decal->RenderStyle, (float)decal->Alpha, decal->Translation, decal->AlphaColor); - - // R_SetPatchStyle can modify basecolormap. - if (rereadcolormap) - { - usecolormap = basecolormap; - } - - if (visible) - { - while (x < x2) - { - if (calclighting) - { // calculate lighting - R_SetColorMapLight(usecolormap, rw_light, wallshade); - } - R_WallSpriteColumn(x, maskedScaleY); - x++; - } - } - - // If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will - // be set 1 if we need to draw on the lower wall. In all other cases, - // needrepeat will be 0, and the while will fail. - mceilingclip = floorclip; - mfloorclip = wallbottom; - R_FinishSetPatchStyle (); - } while (needrepeat--); - - colfunc = basecolfunc; - - R_FinishSetPatchStyle (); -done: - WallC = savecoord; -} - } diff --git a/src/swrenderer/scene/r_segs.h b/src/swrenderer/scene/r_segs.h index 8aafa6ccee..9c83b534d3 100644 --- a/src/swrenderer/scene/r_segs.h +++ b/src/swrenderer/scene/r_segs.h @@ -43,12 +43,18 @@ 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; extern fixed_t rw_offset; +extern int wallshade; }