From 6f1836b68bdb22568a645f037c0826081bb24cde Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 11 Jan 2017 19:50:07 +0100 Subject: [PATCH] Move classes in r_visiblesprite to their own files --- src/CMakeLists.txt | 2 + src/swrenderer/r_main.cpp | 1 + src/swrenderer/scene/r_portal.cpp | 1 + src/swrenderer/scene/r_translucent.cpp | 616 ++++++++++++++++ src/swrenderer/scene/r_translucent.h | 46 ++ src/swrenderer/things/r_particle.cpp | 1 + src/swrenderer/things/r_sprite.cpp | 1 + src/swrenderer/things/r_visiblesprite.cpp | 693 ------------------ src/swrenderer/things/r_visiblesprite.h | 55 +- src/swrenderer/things/r_visiblespritelist.cpp | 146 ++++ src/swrenderer/things/r_visiblespritelist.h | 53 ++ src/swrenderer/things/r_voxel.cpp | 1 + src/swrenderer/things/r_wallsprite.cpp | 1 + 13 files changed, 870 insertions(+), 747 deletions(-) create mode 100644 src/swrenderer/scene/r_translucent.cpp create mode 100644 src/swrenderer/scene/r_translucent.h create mode 100644 src/swrenderer/things/r_visiblespritelist.cpp create mode 100644 src/swrenderer/things/r_visiblespritelist.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 74d1183564..5865a4e93e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -848,6 +848,7 @@ set( FASTMATH_PCH_SOURCES swrenderer/scene/r_3dfloors.cpp swrenderer/scene/r_bsp.cpp swrenderer/scene/r_portal.cpp + swrenderer/scene/r_translucent.cpp swrenderer/line/r_line.cpp swrenderer/line/r_walldraw.cpp swrenderer/line/r_wallsetup.cpp @@ -856,6 +857,7 @@ set( FASTMATH_PCH_SOURCES swrenderer/segments/r_drawsegment.cpp swrenderer/segments/r_portalsegment.cpp swrenderer/things/r_visiblesprite.cpp + swrenderer/things/r_visiblespritelist.cpp swrenderer/things/r_voxel.cpp swrenderer/things/r_particle.cpp swrenderer/things/r_playersprite.cpp diff --git a/src/swrenderer/r_main.cpp b/src/swrenderer/r_main.cpp index f90690d494..a72e8214ac 100644 --- a/src/swrenderer/r_main.cpp +++ b/src/swrenderer/r_main.cpp @@ -43,6 +43,7 @@ #include "segments/r_clipsegment.h" #include "scene/r_3dfloors.h" #include "scene/r_portal.h" +#include "scene/r_translucent.h" #include "r_sky.h" #include "drawers/r_draw_rgba.h" #include "st_stuff.h" diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index d22777eea8..daa6769adb 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -50,6 +50,7 @@ #include "swrenderer/plane/r_visibleplane.h" #include "swrenderer/things/r_visiblesprite.h" #include "swrenderer/scene/r_bsp.h" +#include "swrenderer/scene/r_translucent.h" #include "swrenderer/r_main.h" #include "swrenderer/r_memory.h" diff --git a/src/swrenderer/scene/r_translucent.cpp b/src/swrenderer/scene/r_translucent.cpp new file mode 100644 index 0000000000..7b47965055 --- /dev/null +++ b/src/swrenderer/scene/r_translucent.cpp @@ -0,0 +1,616 @@ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// + +#include +#include +#include +#include "p_lnspec.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "i_system.h" +#include "w_wad.h" +#include "g_levellocals.h" +#include "p_maputl.h" +#include "swrenderer/r_main.h" +#include "swrenderer/things/r_visiblesprite.h" +#include "swrenderer/things/r_visiblespritelist.h" +#include "swrenderer/things/r_voxel.h" +#include "swrenderer/things/r_particle.h" +#include "swrenderer/things/r_sprite.h" +#include "swrenderer/things/r_wallsprite.h" +#include "swrenderer/things/r_playersprite.h" +#include "swrenderer/segments/r_drawsegment.h" +#include "swrenderer/scene/r_portal.h" +#include "swrenderer/scene/r_translucent.h" +#include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/r_memory.h" + +EXTERN_CVAR(Int, r_drawfuzz) +EXTERN_CVAR(Bool, r_drawvoxels) +EXTERN_CVAR(Bool, r_blendmethod) + +CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); + +namespace swrenderer +{ + bool RenderTranslucent::DrewAVoxel; + TArray RenderTranslucent::portaldrawsegs; + + void RenderTranslucent::Deinit() + { + VisibleSpriteList::Deinit(); + SortedVisibleSpriteList::Deinit(); + RenderVoxel::Deinit(); + } + + void RenderTranslucent::Clear() + { + VisibleSpriteList::Clear(); + DrewAVoxel = false; + } + + void RenderTranslucent::CollectPortals() + { + // This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals + // Having that function over the entire list of drawsegs can break down performance quite drastically. + // This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can + // a) exit early if no relevant info is found and + // b) skip most of the collected drawsegs which have no portal attached. + portaldrawsegs.Clear(); + for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below + { + // I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...) + // crashes at the first frame of the first map of Action2.wad + if (!seg->curline) continue; + + line_t* line = seg->curline->linedef; + // ignore minisegs from GL nodes. + if (!line) continue; + + // check if this line will clip sprites to itself + if (!line->isVisualPortal() && line->special != Line_Mirror) + continue; + + // don't clip sprites with portal's back side (it's transparent) + if (seg->curline->sidedef != line->sidedef[0]) + continue; + + portaldrawsegs.Push(seg); + } + } + + bool RenderTranslucent::ClipSpriteColumnWithPortals(int x, vissprite_t* spr) + { + RenderPortal *renderportal = RenderPortal::Instance(); + + // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. + if (renderportal->CurrentPortalInSkybox) + return false; + + for (drawseg_t *seg : portaldrawsegs) + { + // ignore segs from other portals + if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq) + continue; + + // (all checks that are already done in R_CollectPortals have been removed for performance reasons.) + + // don't clip if the sprite is in front of the portal + if (!P_PointOnLineSidePrecise(spr->gpos.X, spr->gpos.Y, seg->curline->linedef)) + continue; + + // now if current column is covered by this drawseg, we clip it away + if ((x >= seg->x1) && (x < seg->x2)) + return true; + } + + return false; + } + + void RenderTranslucent::DrawSprite(vissprite_t *spr) + { + static short clipbot[MAXWIDTH]; + static short cliptop[MAXWIDTH]; + drawseg_t *ds; + int i; + int x1, x2; + int r1, r2; + short topclip, botclip; + short *clip1, *clip2; + FSWColormap *colormap = spr->Style.BaseColormap; + int colormapnum = spr->Style.ColormapNum; + F3DFloor *rover; + FDynamicColormap *mybasecolormap; + + Clip3DFloors *clip3d = Clip3DFloors::Instance(); + + // [RH] Check for particles + if (!spr->bIsVoxel && spr->pic == nullptr) + { + // kg3D - reject invisible parts + if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gpos.Z <= clip3d->sclipBottom) return; + if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gpos.Z >= clip3d->sclipTop) return; + RenderParticle::Render(spr); + return; + } + + x1 = spr->x1; + x2 = spr->x2; + + // [RH] Quickly reject sprites with bad x ranges. + if (x1 >= x2) + return; + + // [RH] Sprites split behind a one-sided line can also be discarded. + if (spr->sector == nullptr) + return; + + // kg3D - reject invisible parts + if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= clip3d->sclipBottom) return; + if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gzb >= clip3d->sclipTop) return; + + // kg3D - correct colors now + if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size()) + { + if (!(clip3d->fake3D & FAKE3D_CLIPTOP)) + { + clip3d->sclipTop = spr->sector->ceilingplane.ZatPoint(ViewPos); + } + sector_t *sec = nullptr; + for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--) + { + if (clip3d->sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0()) + { + rover = spr->sector->e->XFloor.lightlist[i].caster; + if (rover) + { + if (rover->flags & FF_DOUBLESHADOW && clip3d->sclipTop <= rover->bottom.plane->Zat0()) + { + break; + } + sec = rover->model; + if (rover->flags & FF_FADEWALLS) + { + mybasecolormap = sec->ColorMap; + } + else + { + mybasecolormap = spr->sector->e->XFloor.lightlist[i].extra_colormap; + } + } + break; + } + } + // found new values, recalculate + if (sec) + { + INTBOOL invertcolormap = (spr->Style.RenderStyle.Flags & STYLEF_InvertOverlay); + + if (spr->Style.RenderStyle.Flags & STYLEF_InvertSource) + { + invertcolormap = !invertcolormap; + } + + // Sprites that are added to the scene must fade to black. + if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0) + { + mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate); + } + + if (spr->Style.RenderStyle.Flags & STYLEF_FadeToBlack) + { + if (invertcolormap) + { // Fade to white + mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255, 255, 255), mybasecolormap->Desaturate); + invertcolormap = false; + } + else + { // Fade to black + mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0, 0, 0), mybasecolormap->Desaturate); + } + } + + // get light level + if (invertcolormap) + { + mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate); + } + if (fixedlightlev >= 0) + { + spr->Style.BaseColormap = mybasecolormap; + spr->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT; + } + else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) + { // full bright + spr->Style.BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap; + spr->Style.ColormapNum = 0; + } + else + { // diminished light + int spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight); + spr->Style.BaseColormap = mybasecolormap; + spr->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(MINZ, (double)spr->depth), spriteshade); + } + } + } + + // [RH] Initialize the clipping arrays to their largest possible range + // instead of using a special "not clipped" value. This eliminates + // visual anomalies when looking down and should be faster, too. + topclip = 0; + botclip = viewheight; + + // killough 3/27/98: + // Clip the sprite against deep water and/or fake ceilings. + // [RH] rewrote this to be based on which part of the sector is really visible + + double scale = InvZtoScale * spr->idepth; + double hzb = DBL_MIN, hzt = DBL_MAX; + + if (spr->bIsVoxel && spr->floorclip != 0) + { + hzb = spr->gzb; + } + + if (spr->heightsec && !(spr->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)) + { // only things in specially marked sectors + if (spr->FakeFlatStat != WaterFakeSide::AboveCeiling) + { + double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos); + int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); + + if (spr->FakeFlatStat == WaterFakeSide::BelowFloor) + { // seen below floor: clip top + if (!spr->bIsVoxel && h > topclip) + { + topclip = short(MIN(h, viewheight)); + } + hzt = MIN(hzt, hz); + } + else + { // seen in the middle: clip bottom + if (!spr->bIsVoxel && h < botclip) + { + botclip = MAX(0, h); + } + hzb = MAX(hzb, hz); + } + } + if (spr->FakeFlatStat != WaterFakeSide::BelowFloor && !(spr->heightsec->MoreFlags & SECF_FAKEFLOORONLY)) + { + double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos); + int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); + + if (spr->FakeFlatStat == WaterFakeSide::AboveCeiling) + { // seen above ceiling: clip bottom + if (!spr->bIsVoxel && h < botclip) + { + botclip = MAX(0, h); + } + hzb = MAX(hzb, hz); + } + else + { // seen in the middle: clip top + if (!spr->bIsVoxel && h > topclip) + { + topclip = MIN(h, viewheight); + } + hzt = MIN(hzt, hz); + } + } + } + // killough 3/27/98: end special clipping for deep water / fake ceilings + else if (!spr->bIsVoxel && spr->floorclip) + { // [RH] Move floorclip stuff from R_DrawVisSprite to here + //int clip = ((FLOAT2FIXED(CenterY) - FixedMul (spr->texturemid - (spr->pic->GetHeight() << FRACBITS) + spr->floorclip, spr->yscale)) >> FRACBITS); + int clip = xs_RoundToInt(CenterY - (spr->texturemid - spr->pic->GetHeight() + spr->floorclip) * spr->yscale); + if (clip < botclip) + { + botclip = MAX(0, clip); + } + } + + if (clip3d->fake3D & FAKE3D_CLIPBOTTOM) + { + if (!spr->bIsVoxel) + { + double hz = clip3d->sclipBottom; + if (spr->fakefloor) + { + double floorz = spr->fakefloor->top.plane->Zat0(); + if (ViewPos.Z > floorz && floorz == clip3d->sclipBottom) + { + hz = spr->fakefloor->bottom.plane->Zat0(); + } + } + int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); + if (h < botclip) + { + botclip = MAX(0, h); + } + } + hzb = MAX(hzb, clip3d->sclipBottom); + } + if (clip3d->fake3D & FAKE3D_CLIPTOP) + { + if (!spr->bIsVoxel) + { + double hz = clip3d->sclipTop; + if (spr->fakeceiling != nullptr) + { + double ceilingZ = spr->fakeceiling->bottom.plane->Zat0(); + if (ViewPos.Z < ceilingZ && ceilingZ == clip3d->sclipTop) + { + hz = spr->fakeceiling->top.plane->Zat0(); + } + } + int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); + if (h > topclip) + { + topclip = short(MIN(h, viewheight)); + } + } + hzt = MIN(hzt, clip3d->sclipTop); + } + + if (topclip >= botclip) + { + spr->Style.BaseColormap = colormap; + spr->Style.ColormapNum = colormapnum; + return; + } + + i = x2 - x1; + clip1 = clipbot + x1; + clip2 = cliptop + x1; + do + { + *clip1++ = botclip; + *clip2++ = topclip; + } while (--i); + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that is closer than the sprite is the clip seg. + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough + { + // [ZZ] portal handling here + //if (ds->CurrentPortalUniq != spr->CurrentPortalUniq) + // continue; + // [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping + + // kg3D - no clipping on fake segs + if (ds->fake) continue; + // determine if the drawseg obscures the sprite + if (ds->x1 >= x2 || ds->x2 <= x1 || + (!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 && + !ds->bFogBoundary)) + { + // does not cover sprite + continue; + } + + r1 = MAX(ds->x1, x1); + r2 = MIN(ds->x2, x2); + + float neardepth, fardepth; + if (!spr->bWallSprite) + { + if (ds->sz1 < ds->sz2) + { + neardepth = ds->sz1, fardepth = ds->sz2; + } + else + { + neardepth = ds->sz2, fardepth = ds->sz1; + } + } + + + // Check if sprite is in front of draw seg: + if ((!spr->bWallSprite && neardepth > spr->depth) || ((spr->bWallSprite || fardepth > spr->depth) && + (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - + (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) + { + RenderPortal *renderportal = RenderPortal::Instance(); + + // seg is behind sprite, so draw the mid texture if it has one + if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq && // [ZZ] instead, portal uniq check is made here + (ds->maskedtexturecol != -1 || ds->bFogBoundary)) + R_RenderMaskedSegRange(ds, r1, r2); + + continue; + } + + // clip this piece of the sprite + // killough 3/27/98: optimized and made much shorter + // [RH] Optimized further (at least for VC++; + // other compilers should be at least as good as before) + + if (ds->silhouette & SIL_BOTTOM) //bottom sil + { + clip1 = clipbot + r1; + clip2 = openings + ds->sprbottomclip + r1 - ds->x1; + i = r2 - r1; + do + { + if (*clip1 > *clip2) + *clip1 = *clip2; + clip1++; + clip2++; + } while (--i); + } + + if (ds->silhouette & SIL_TOP) // top sil + { + clip1 = cliptop + r1; + clip2 = openings + ds->sprtopclip + r1 - ds->x1; + i = r2 - r1; + do + { + if (*clip1 < *clip2) + *clip1 = *clip2; + clip1++; + clip2++; + } while (--i); + } + } + + // all clipping has been performed, so draw the sprite + + if (!spr->bIsVoxel) + { + if (!spr->bWallSprite) + { + RenderSprite::Render(spr, clipbot, cliptop); + } + else + { + RenderWallSprite::Render(spr, clipbot, cliptop); + } + } + else + { + // If it is completely clipped away, don't bother drawing it. + if (cliptop[x2] >= clipbot[x2]) + { + for (i = x1; i < x2; ++i) + { + if (cliptop[i] < clipbot[i]) + { + break; + } + } + if (i == x2) + { + spr->Style.BaseColormap = colormap; + spr->Style.ColormapNum = colormapnum; + return; + } + } + // Add everything outside the left and right edges to the clipping array + // for R_DrawVisVoxel(). + if (x1 > 0) + { + fillshort(cliptop, x1, viewheight); + } + if (x2 < viewwidth - 1) + { + fillshort(cliptop + x2, viewwidth - x2, viewheight); + } + int minvoxely = spr->gzt <= hzt ? 0 : xs_RoundToInt((spr->gzt - hzt) / spr->yscale); + int maxvoxely = spr->gzb > hzb ? INT_MAX : xs_RoundToInt((spr->gzt - hzb) / spr->yscale); + RenderVoxel::Render(spr, minvoxely, maxvoxely, cliptop, clipbot); + } + spr->Style.BaseColormap = colormap; + spr->Style.ColormapNum = colormapnum; + } + + void RenderTranslucent::DrawMaskedSingle(bool renew) + { + RenderPortal *renderportal = RenderPortal::Instance(); + + for (int i = SortedVisibleSpriteList::vsprcount; i > 0; i--) + { + if (SortedVisibleSpriteList::spritesorter[i - 1]->CurrentPortalUniq != renderportal->CurrentPortalUniq) + continue; // probably another time + DrawSprite(SortedVisibleSpriteList::spritesorter[i - 1]); + } + + // render any remaining masked mid textures + + // Modified by Lee Killough: + // (pointer check was originally nonportable + // and buggy, by going past LEFT end of array): + + // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code + + if (renew) + { + Clip3DFloors::Instance()->fake3D |= FAKE3D_REFRESHCLIP; + } + for (drawseg_t *ds = ds_p; ds-- > firstdrawseg; ) // new -- killough + { + // [ZZ] the same as above + if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq) + continue; + // kg3D - no fake segs + if (ds->fake) continue; + if (ds->maskedtexturecol != -1 || ds->bFogBoundary) + { + R_RenderMaskedSegRange(ds, ds->x1, ds->x2); + } + } + } + + void RenderTranslucent::Render() + { + CollectPortals(); + SortedVisibleSpriteList::Sort(DrewAVoxel ? SortedVisibleSpriteList::sv_compare2d : SortedVisibleSpriteList::sv_compare, VisibleSpriteList::firstvissprite - VisibleSpriteList::vissprites); + + Clip3DFloors *clip3d = Clip3DFloors::Instance(); + if (clip3d->height_top == nullptr) + { // kg3D - no visible 3D floors, normal rendering + DrawMaskedSingle(false); + } + else + { // kg3D - correct sorting + // ceilings + for (HeightLevel *hl = clip3d->height_cur; hl != nullptr && hl->height >= ViewPos.Z; hl = hl->prev) + { + if (hl->next) + { + clip3d->fake3D = FAKE3D_CLIPBOTTOM | FAKE3D_CLIPTOP; + clip3d->sclipTop = hl->next->height; + } + else + { + clip3d->fake3D = FAKE3D_CLIPBOTTOM; + } + clip3d->sclipBottom = hl->height; + DrawMaskedSingle(true); + R_DrawHeightPlanes(hl->height); + } + + // floors + clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP; + clip3d->sclipTop = clip3d->height_top->height; + DrawMaskedSingle(true); + for (HeightLevel *hl = clip3d->height_top; hl != nullptr && hl->height < ViewPos.Z; hl = hl->next) + { + R_DrawHeightPlanes(hl->height); + if (hl->next) + { + clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP | FAKE3D_CLIPBOTTOM; + clip3d->sclipTop = hl->next->height; + } + else + { + clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPBOTTOM; + } + clip3d->sclipBottom = hl->height; + DrawMaskedSingle(true); + } + clip3d->DeleteHeights(); + clip3d->fake3D = 0; + } + RenderPlayerSprite::RenderPlayerSprites(); + } +} diff --git a/src/swrenderer/scene/r_translucent.h b/src/swrenderer/scene/r_translucent.h new file mode 100644 index 0000000000..30ca656793 --- /dev/null +++ b/src/swrenderer/scene/r_translucent.h @@ -0,0 +1,46 @@ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// + +#pragma once + +#include "tarray.h" + +#define MINZ double((2048*4) / double(1 << 20)) + +struct particle_t; +struct FVoxel; + +namespace swrenderer +{ + struct vissprite_t; + struct drawseg_t; + + class RenderTranslucent + { + public: + static void Deinit(); + static void Clear(); + static void Render(); + + static bool DrewAVoxel; + + static bool ClipSpriteColumnWithPortals(int x, vissprite_t* spr); + + private: + static void CollectPortals(); + static void DrawSprite(vissprite_t *spr); + static void DrawMaskedSingle(bool renew); + + static TArray portaldrawsegs; + }; +} diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index 8ec92569ff..fd4585aac7 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -40,6 +40,7 @@ #include "p_effect.h" #include "swrenderer/scene/r_bsp.h" #include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/scene/r_translucent.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/drawers/r_draw_pal.h" #include "v_palette.h" diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index 7751f859e7..edd7a24749 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -40,6 +40,7 @@ #include "p_effect.h" #include "swrenderer/scene/r_bsp.h" #include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/scene/r_translucent.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/drawers/r_draw_pal.h" #include "v_palette.h" diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index 36ee18432b..2eb52770e3 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -34,699 +34,6 @@ #include "swrenderer/plane/r_visibleplane.h" #include "swrenderer/r_memory.h" -EXTERN_CVAR(Int, r_drawfuzz) -EXTERN_CVAR(Bool, r_drawvoxels) -EXTERN_CVAR(Bool, r_blendmethod) - -CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); -CVAR(Bool, r_splitsprites, true, CVAR_ARCHIVE) - namespace swrenderer { - void VisibleSpriteList::Deinit() - { - // Free vissprites - for (int i = 0; i < MaxVisSprites; ++i) - { - delete vissprites[i]; - } - free(vissprites); - vissprites = nullptr; - vissprite_p = lastvissprite = nullptr; - MaxVisSprites = 0; - } - - void VisibleSpriteList::Clear() - { - vissprite_p = firstvissprite; - } - - vissprite_t *VisibleSpriteList::Add() - { - if (vissprite_p == lastvissprite) - { - ptrdiff_t firstvisspritenum = firstvissprite - vissprites; - ptrdiff_t prevvisspritenum = vissprite_p - vissprites; - - MaxVisSprites = MaxVisSprites ? MaxVisSprites * 2 : 128; - vissprites = (vissprite_t **)M_Realloc(vissprites, MaxVisSprites * sizeof(vissprite_t)); - lastvissprite = &vissprites[MaxVisSprites]; - firstvissprite = &vissprites[firstvisspritenum]; - vissprite_p = &vissprites[prevvisspritenum]; - DPrintf(DMSG_NOTIFY, "MaxVisSprites increased to %d\n", MaxVisSprites); - - // Allocate sprites from the new pile - for (vissprite_t **p = vissprite_p; p < lastvissprite; ++p) - { - *p = new vissprite_t; - } - } - - vissprite_p++; - return *(vissprite_p - 1); - } - - int VisibleSpriteList::MaxVisSprites; - vissprite_t **VisibleSpriteList::vissprites; - vissprite_t **VisibleSpriteList::firstvissprite; - vissprite_t **VisibleSpriteList::vissprite_p; - vissprite_t **VisibleSpriteList::lastvissprite; - - ///////////////////////////////////////////////////////////////////////// - - void SortedVisibleSpriteList::Deinit() - { - delete[] spritesorter; - spritesortersize = 0; - spritesorter = nullptr; - } - - // This is the standard version, which does a simple test based on depth. - bool SortedVisibleSpriteList::sv_compare(vissprite_t *a, vissprite_t *b) - { - return a->idepth > b->idepth; - } - - // This is an alternate version, for when one or more voxel is in view. - // It does a 2D distance test based on whichever one is furthest from - // the viewpoint. - bool SortedVisibleSpriteList::sv_compare2d(vissprite_t *a, vissprite_t *b) - { - return DVector2(a->deltax, a->deltay).LengthSquared() < DVector2(b->deltax, b->deltay).LengthSquared(); - } - - void SortedVisibleSpriteList::Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first) - { - int i; - vissprite_t **spr; - - vsprcount = int(VisibleSpriteList::vissprite_p - &VisibleSpriteList::vissprites[first]); - - if (vsprcount == 0) - return; - - if (spritesortersize < VisibleSpriteList::MaxVisSprites) - { - if (spritesorter != nullptr) - delete[] spritesorter; - spritesorter = new vissprite_t *[VisibleSpriteList::MaxVisSprites]; - spritesortersize = VisibleSpriteList::MaxVisSprites; - } - - if (!(i_compatflags & COMPATF_SPRITESORT)) - { - for (i = 0, spr = VisibleSpriteList::firstvissprite; i < vsprcount; i++, spr++) - { - spritesorter[i] = *spr; - } - } - else - { - // If the compatibility option is on sprites of equal distance need to - // be sorted in inverse order. This is most easily achieved by - // filling the sort array backwards before the sort. - for (i = 0, spr = VisibleSpriteList::firstvissprite + vsprcount - 1; i < vsprcount; i++, spr--) - { - spritesorter[i] = *spr; - } - } - - std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare); - } - - vissprite_t **SortedVisibleSpriteList::spritesorter; - int SortedVisibleSpriteList::spritesortersize = 0; - int SortedVisibleSpriteList::vsprcount; - - ///////////////////////////////////////////////////////////////////////// - - bool RenderTranslucent::DrewAVoxel; - TArray RenderTranslucent::portaldrawsegs; - - void RenderTranslucent::Deinit() - { - VisibleSpriteList::Deinit(); - SortedVisibleSpriteList::Deinit(); - RenderVoxel::Deinit(); - } - - void RenderTranslucent::Clear() - { - VisibleSpriteList::Clear(); - DrewAVoxel = false; - } - - void RenderTranslucent::CollectPortals() - { - // This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals - // Having that function over the entire list of drawsegs can break down performance quite drastically. - // This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can - // a) exit early if no relevant info is found and - // b) skip most of the collected drawsegs which have no portal attached. - portaldrawsegs.Clear(); - for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below - { - // I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...) - // crashes at the first frame of the first map of Action2.wad - if (!seg->curline) continue; - - line_t* line = seg->curline->linedef; - // ignore minisegs from GL nodes. - if (!line) continue; - - // check if this line will clip sprites to itself - if (!line->isVisualPortal() && line->special != Line_Mirror) - continue; - - // don't clip sprites with portal's back side (it's transparent) - if (seg->curline->sidedef != line->sidedef[0]) - continue; - - portaldrawsegs.Push(seg); - } - } - - bool RenderTranslucent::ClipSpriteColumnWithPortals(int x, vissprite_t* spr) - { - RenderPortal *renderportal = RenderPortal::Instance(); - - // [ZZ] 10.01.2016: don't clip sprites from the root of a skybox. - if (renderportal->CurrentPortalInSkybox) - return false; - - for (drawseg_t *seg : portaldrawsegs) - { - // ignore segs from other portals - if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq) - continue; - - // (all checks that are already done in R_CollectPortals have been removed for performance reasons.) - - // don't clip if the sprite is in front of the portal - if (!P_PointOnLineSidePrecise(spr->gpos.X, spr->gpos.Y, seg->curline->linedef)) - continue; - - // now if current column is covered by this drawseg, we clip it away - if ((x >= seg->x1) && (x < seg->x2)) - return true; - } - - return false; - } - - void RenderTranslucent::DrawSprite(vissprite_t *spr) - { - static short clipbot[MAXWIDTH]; - static short cliptop[MAXWIDTH]; - drawseg_t *ds; - int i; - int x1, x2; - int r1, r2; - short topclip, botclip; - short *clip1, *clip2; - FSWColormap *colormap = spr->Style.BaseColormap; - int colormapnum = spr->Style.ColormapNum; - F3DFloor *rover; - FDynamicColormap *mybasecolormap; - - Clip3DFloors *clip3d = Clip3DFloors::Instance(); - - // [RH] Check for particles - if (!spr->bIsVoxel && spr->pic == nullptr) - { - // kg3D - reject invisible parts - if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gpos.Z <= clip3d->sclipBottom) return; - if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gpos.Z >= clip3d->sclipTop) return; - RenderParticle::Render(spr); - return; - } - - x1 = spr->x1; - x2 = spr->x2; - - // [RH] Quickly reject sprites with bad x ranges. - if (x1 >= x2) - return; - - // [RH] Sprites split behind a one-sided line can also be discarded. - if (spr->sector == nullptr) - return; - - // kg3D - reject invisible parts - if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= clip3d->sclipBottom) return; - if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gzb >= clip3d->sclipTop) return; - - // kg3D - correct colors now - if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size()) - { - if (!(clip3d->fake3D & FAKE3D_CLIPTOP)) - { - clip3d->sclipTop = spr->sector->ceilingplane.ZatPoint(ViewPos); - } - sector_t *sec = nullptr; - for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--) - { - if (clip3d->sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0()) - { - rover = spr->sector->e->XFloor.lightlist[i].caster; - if (rover) - { - if (rover->flags & FF_DOUBLESHADOW && clip3d->sclipTop <= rover->bottom.plane->Zat0()) - { - break; - } - sec = rover->model; - if (rover->flags & FF_FADEWALLS) - { - mybasecolormap = sec->ColorMap; - } - else - { - mybasecolormap = spr->sector->e->XFloor.lightlist[i].extra_colormap; - } - } - break; - } - } - // found new values, recalculate - if (sec) - { - INTBOOL invertcolormap = (spr->Style.RenderStyle.Flags & STYLEF_InvertOverlay); - - if (spr->Style.RenderStyle.Flags & STYLEF_InvertSource) - { - invertcolormap = !invertcolormap; - } - - // Sprites that are added to the scene must fade to black. - if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0) - { - mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate); - } - - if (spr->Style.RenderStyle.Flags & STYLEF_FadeToBlack) - { - if (invertcolormap) - { // Fade to white - mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255, 255, 255), mybasecolormap->Desaturate); - invertcolormap = false; - } - else - { // Fade to black - mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0, 0, 0), mybasecolormap->Desaturate); - } - } - - // get light level - if (invertcolormap) - { - mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate); - } - if (fixedlightlev >= 0) - { - spr->Style.BaseColormap = mybasecolormap; - spr->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT; - } - else if (!foggy && (spr->renderflags & RF_FULLBRIGHT)) - { // full bright - spr->Style.BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap; - spr->Style.ColormapNum = 0; - } - else - { // diminished light - int spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight); - spr->Style.BaseColormap = mybasecolormap; - spr->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(MINZ, (double)spr->depth), spriteshade); - } - } - } - - // [RH] Initialize the clipping arrays to their largest possible range - // instead of using a special "not clipped" value. This eliminates - // visual anomalies when looking down and should be faster, too. - topclip = 0; - botclip = viewheight; - - // killough 3/27/98: - // Clip the sprite against deep water and/or fake ceilings. - // [RH] rewrote this to be based on which part of the sector is really visible - - double scale = InvZtoScale * spr->idepth; - double hzb = DBL_MIN, hzt = DBL_MAX; - - if (spr->bIsVoxel && spr->floorclip != 0) - { - hzb = spr->gzb; - } - - if (spr->heightsec && !(spr->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)) - { // only things in specially marked sectors - if (spr->FakeFlatStat != WaterFakeSide::AboveCeiling) - { - double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos); - int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); - - if (spr->FakeFlatStat == WaterFakeSide::BelowFloor) - { // seen below floor: clip top - if (!spr->bIsVoxel && h > topclip) - { - topclip = short(MIN(h, viewheight)); - } - hzt = MIN(hzt, hz); - } - else - { // seen in the middle: clip bottom - if (!spr->bIsVoxel && h < botclip) - { - botclip = MAX(0, h); - } - hzb = MAX(hzb, hz); - } - } - if (spr->FakeFlatStat != WaterFakeSide::BelowFloor && !(spr->heightsec->MoreFlags & SECF_FAKEFLOORONLY)) - { - double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos); - int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); - - if (spr->FakeFlatStat == WaterFakeSide::AboveCeiling) - { // seen above ceiling: clip bottom - if (!spr->bIsVoxel && h < botclip) - { - botclip = MAX(0, h); - } - hzb = MAX(hzb, hz); - } - else - { // seen in the middle: clip top - if (!spr->bIsVoxel && h > topclip) - { - topclip = MIN(h, viewheight); - } - hzt = MIN(hzt, hz); - } - } - } - // killough 3/27/98: end special clipping for deep water / fake ceilings - else if (!spr->bIsVoxel && spr->floorclip) - { // [RH] Move floorclip stuff from R_DrawVisSprite to here - //int clip = ((FLOAT2FIXED(CenterY) - FixedMul (spr->texturemid - (spr->pic->GetHeight() << FRACBITS) + spr->floorclip, spr->yscale)) >> FRACBITS); - int clip = xs_RoundToInt(CenterY - (spr->texturemid - spr->pic->GetHeight() + spr->floorclip) * spr->yscale); - if (clip < botclip) - { - botclip = MAX(0, clip); - } - } - - if (clip3d->fake3D & FAKE3D_CLIPBOTTOM) - { - if (!spr->bIsVoxel) - { - double hz = clip3d->sclipBottom; - if (spr->fakefloor) - { - double floorz = spr->fakefloor->top.plane->Zat0(); - if (ViewPos.Z > floorz && floorz == clip3d->sclipBottom) - { - hz = spr->fakefloor->bottom.plane->Zat0(); - } - } - int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); - if (h < botclip) - { - botclip = MAX(0, h); - } - } - hzb = MAX(hzb, clip3d->sclipBottom); - } - if (clip3d->fake3D & FAKE3D_CLIPTOP) - { - if (!spr->bIsVoxel) - { - double hz = clip3d->sclipTop; - if (spr->fakeceiling != nullptr) - { - double ceilingZ = spr->fakeceiling->bottom.plane->Zat0(); - if (ViewPos.Z < ceilingZ && ceilingZ == clip3d->sclipTop) - { - hz = spr->fakeceiling->top.plane->Zat0(); - } - } - int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); - if (h > topclip) - { - topclip = short(MIN(h, viewheight)); - } - } - hzt = MIN(hzt, clip3d->sclipTop); - } - - if (topclip >= botclip) - { - spr->Style.BaseColormap = colormap; - spr->Style.ColormapNum = colormapnum; - return; - } - - i = x2 - x1; - clip1 = clipbot + x1; - clip2 = cliptop + x1; - do - { - *clip1++ = botclip; - *clip2++ = topclip; - } while (--i); - - // Scan drawsegs from end to start for obscuring segs. - // The first drawseg that is closer than the sprite is the clip seg. - - // Modified by Lee Killough: - // (pointer check was originally nonportable - // and buggy, by going past LEFT end of array): - - // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code - - for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough - { - // [ZZ] portal handling here - //if (ds->CurrentPortalUniq != spr->CurrentPortalUniq) - // continue; - // [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping - - // kg3D - no clipping on fake segs - if (ds->fake) continue; - // determine if the drawseg obscures the sprite - if (ds->x1 >= x2 || ds->x2 <= x1 || - (!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 && - !ds->bFogBoundary)) - { - // does not cover sprite - continue; - } - - r1 = MAX(ds->x1, x1); - r2 = MIN(ds->x2, x2); - - float neardepth, fardepth; - if (!spr->bWallSprite) - { - if (ds->sz1 < ds->sz2) - { - neardepth = ds->sz1, fardepth = ds->sz2; - } - else - { - neardepth = ds->sz2, fardepth = ds->sz1; - } - } - - - // Check if sprite is in front of draw seg: - if ((!spr->bWallSprite && neardepth > spr->depth) || ((spr->bWallSprite || fardepth > spr->depth) && - (spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) - - (spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0)) - { - RenderPortal *renderportal = RenderPortal::Instance(); - - // seg is behind sprite, so draw the mid texture if it has one - if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq && // [ZZ] instead, portal uniq check is made here - (ds->maskedtexturecol != -1 || ds->bFogBoundary)) - R_RenderMaskedSegRange(ds, r1, r2); - - continue; - } - - // clip this piece of the sprite - // killough 3/27/98: optimized and made much shorter - // [RH] Optimized further (at least for VC++; - // other compilers should be at least as good as before) - - if (ds->silhouette & SIL_BOTTOM) //bottom sil - { - clip1 = clipbot + r1; - clip2 = openings + ds->sprbottomclip + r1 - ds->x1; - i = r2 - r1; - do - { - if (*clip1 > *clip2) - *clip1 = *clip2; - clip1++; - clip2++; - } while (--i); - } - - if (ds->silhouette & SIL_TOP) // top sil - { - clip1 = cliptop + r1; - clip2 = openings + ds->sprtopclip + r1 - ds->x1; - i = r2 - r1; - do - { - if (*clip1 < *clip2) - *clip1 = *clip2; - clip1++; - clip2++; - } while (--i); - } - } - - // all clipping has been performed, so draw the sprite - - if (!spr->bIsVoxel) - { - if (!spr->bWallSprite) - { - RenderSprite::Render(spr, clipbot, cliptop); - } - else - { - RenderWallSprite::Render(spr, clipbot, cliptop); - } - } - else - { - // If it is completely clipped away, don't bother drawing it. - if (cliptop[x2] >= clipbot[x2]) - { - for (i = x1; i < x2; ++i) - { - if (cliptop[i] < clipbot[i]) - { - break; - } - } - if (i == x2) - { - spr->Style.BaseColormap = colormap; - spr->Style.ColormapNum = colormapnum; - return; - } - } - // Add everything outside the left and right edges to the clipping array - // for R_DrawVisVoxel(). - if (x1 > 0) - { - fillshort(cliptop, x1, viewheight); - } - if (x2 < viewwidth - 1) - { - fillshort(cliptop + x2, viewwidth - x2, viewheight); - } - int minvoxely = spr->gzt <= hzt ? 0 : xs_RoundToInt((spr->gzt - hzt) / spr->yscale); - int maxvoxely = spr->gzb > hzb ? INT_MAX : xs_RoundToInt((spr->gzt - hzb) / spr->yscale); - RenderVoxel::Render(spr, minvoxely, maxvoxely, cliptop, clipbot); - } - spr->Style.BaseColormap = colormap; - spr->Style.ColormapNum = colormapnum; - } - - void RenderTranslucent::DrawMaskedSingle(bool renew) - { - RenderPortal *renderportal = RenderPortal::Instance(); - - for (int i = SortedVisibleSpriteList::vsprcount; i > 0; i--) - { - if (SortedVisibleSpriteList::spritesorter[i - 1]->CurrentPortalUniq != renderportal->CurrentPortalUniq) - continue; // probably another time - DrawSprite(SortedVisibleSpriteList::spritesorter[i - 1]); - } - - // render any remaining masked mid textures - - // Modified by Lee Killough: - // (pointer check was originally nonportable - // and buggy, by going past LEFT end of array): - - // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code - - if (renew) - { - Clip3DFloors::Instance()->fake3D |= FAKE3D_REFRESHCLIP; - } - for (drawseg_t *ds = ds_p; ds-- > firstdrawseg; ) // new -- killough - { - // [ZZ] the same as above - if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq) - continue; - // kg3D - no fake segs - if (ds->fake) continue; - if (ds->maskedtexturecol != -1 || ds->bFogBoundary) - { - R_RenderMaskedSegRange(ds, ds->x1, ds->x2); - } - } - } - - void RenderTranslucent::Render() - { - CollectPortals(); - SortedVisibleSpriteList::Sort(DrewAVoxel ? SortedVisibleSpriteList::sv_compare2d : SortedVisibleSpriteList::sv_compare, VisibleSpriteList::firstvissprite - VisibleSpriteList::vissprites); - - Clip3DFloors *clip3d = Clip3DFloors::Instance(); - if (clip3d->height_top == nullptr) - { // kg3D - no visible 3D floors, normal rendering - DrawMaskedSingle(false); - } - else - { // kg3D - correct sorting - // ceilings - for (HeightLevel *hl = clip3d->height_cur; hl != nullptr && hl->height >= ViewPos.Z; hl = hl->prev) - { - if (hl->next) - { - clip3d->fake3D = FAKE3D_CLIPBOTTOM | FAKE3D_CLIPTOP; - clip3d->sclipTop = hl->next->height; - } - else - { - clip3d->fake3D = FAKE3D_CLIPBOTTOM; - } - clip3d->sclipBottom = hl->height; - DrawMaskedSingle(true); - R_DrawHeightPlanes(hl->height); - } - - // floors - clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP; - clip3d->sclipTop = clip3d->height_top->height; - DrawMaskedSingle(true); - for (HeightLevel *hl = clip3d->height_top; hl != nullptr && hl->height < ViewPos.Z; hl = hl->next) - { - R_DrawHeightPlanes(hl->height); - if (hl->next) - { - clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP | FAKE3D_CLIPBOTTOM; - clip3d->sclipTop = hl->next->height; - } - else - { - clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPBOTTOM; - } - clip3d->sclipBottom = hl->height; - DrawMaskedSingle(true); - } - clip3d->DeleteHeights(); - clip3d->fake3D = 0; - } - RenderPlayerSprite::RenderPlayerSprites(); - } } diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index b9405dc199..06e50f2922 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -15,6 +15,7 @@ #include "swrenderer/line/r_line.h" #include "swrenderer/scene/r_bsp.h" +#include "swrenderer/things/r_visiblespritelist.h" #define MINZ double((2048*4) / double(1 << 20)) @@ -23,8 +24,6 @@ struct FVoxel; namespace swrenderer { - struct drawseg_t; - struct vissprite_t { struct posang @@ -89,56 +88,4 @@ namespace swrenderer vissprite_t() {} }; - - class VisibleSpriteList - { - public: - static int MaxVisSprites; - static vissprite_t **vissprites; - static vissprite_t **firstvissprite; - static vissprite_t **vissprite_p; - - static void Deinit(); - static void Clear(); - static vissprite_t *Add(); - - private: - static vissprite_t **lastvissprite; - }; - - class SortedVisibleSpriteList - { - public: - static void Deinit(); - - static void Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first); - - static bool sv_compare(vissprite_t *a, vissprite_t *b); - static bool sv_compare2d(vissprite_t *a, vissprite_t *b); - - static vissprite_t **spritesorter; - static int vsprcount; - - private: - static int spritesortersize; - }; - - class RenderTranslucent - { - public: - static void Deinit(); - static void Clear(); - static void Render(); - - static bool DrewAVoxel; - - static bool ClipSpriteColumnWithPortals(int x, vissprite_t* spr); - - private: - static void CollectPortals(); - static void DrawSprite(vissprite_t *spr); - static void DrawMaskedSingle(bool renew); - - static TArray portaldrawsegs; - }; } diff --git a/src/swrenderer/things/r_visiblespritelist.cpp b/src/swrenderer/things/r_visiblespritelist.cpp new file mode 100644 index 0000000000..fff4dce8eb --- /dev/null +++ b/src/swrenderer/things/r_visiblespritelist.cpp @@ -0,0 +1,146 @@ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// + +#include +#include +#include +#include "p_lnspec.h" +#include "templates.h" +#include "doomdef.h" +#include "m_swap.h" +#include "i_system.h" +#include "w_wad.h" +#include "g_levellocals.h" +#include "p_maputl.h" +#include "swrenderer/r_main.h" +#include "swrenderer/things/r_visiblesprite.h" +#include "swrenderer/things/r_visiblespritelist.h" +#include "swrenderer/r_memory.h" + +namespace swrenderer +{ + void VisibleSpriteList::Deinit() + { + // Free vissprites + for (int i = 0; i < MaxVisSprites; ++i) + { + delete vissprites[i]; + } + free(vissprites); + vissprites = nullptr; + vissprite_p = lastvissprite = nullptr; + MaxVisSprites = 0; + } + + void VisibleSpriteList::Clear() + { + vissprite_p = firstvissprite; + } + + vissprite_t *VisibleSpriteList::Add() + { + if (vissprite_p == lastvissprite) + { + ptrdiff_t firstvisspritenum = firstvissprite - vissprites; + ptrdiff_t prevvisspritenum = vissprite_p - vissprites; + + MaxVisSprites = MaxVisSprites ? MaxVisSprites * 2 : 128; + vissprites = (vissprite_t **)M_Realloc(vissprites, MaxVisSprites * sizeof(vissprite_t)); + lastvissprite = &vissprites[MaxVisSprites]; + firstvissprite = &vissprites[firstvisspritenum]; + vissprite_p = &vissprites[prevvisspritenum]; + DPrintf(DMSG_NOTIFY, "MaxVisSprites increased to %d\n", MaxVisSprites); + + // Allocate sprites from the new pile + for (vissprite_t **p = vissprite_p; p < lastvissprite; ++p) + { + *p = new vissprite_t; + } + } + + vissprite_p++; + return *(vissprite_p - 1); + } + + int VisibleSpriteList::MaxVisSprites; + vissprite_t **VisibleSpriteList::vissprites; + vissprite_t **VisibleSpriteList::firstvissprite; + vissprite_t **VisibleSpriteList::vissprite_p; + vissprite_t **VisibleSpriteList::lastvissprite; + + ///////////////////////////////////////////////////////////////////////// + + void SortedVisibleSpriteList::Deinit() + { + delete[] spritesorter; + spritesortersize = 0; + spritesorter = nullptr; + } + + // This is the standard version, which does a simple test based on depth. + bool SortedVisibleSpriteList::sv_compare(vissprite_t *a, vissprite_t *b) + { + return a->idepth > b->idepth; + } + + // This is an alternate version, for when one or more voxel is in view. + // It does a 2D distance test based on whichever one is furthest from + // the viewpoint. + bool SortedVisibleSpriteList::sv_compare2d(vissprite_t *a, vissprite_t *b) + { + return DVector2(a->deltax, a->deltay).LengthSquared() < DVector2(b->deltax, b->deltay).LengthSquared(); + } + + void SortedVisibleSpriteList::Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first) + { + int i; + vissprite_t **spr; + + vsprcount = int(VisibleSpriteList::vissprite_p - &VisibleSpriteList::vissprites[first]); + + if (vsprcount == 0) + return; + + if (spritesortersize < VisibleSpriteList::MaxVisSprites) + { + if (spritesorter != nullptr) + delete[] spritesorter; + spritesorter = new vissprite_t *[VisibleSpriteList::MaxVisSprites]; + spritesortersize = VisibleSpriteList::MaxVisSprites; + } + + if (!(i_compatflags & COMPATF_SPRITESORT)) + { + for (i = 0, spr = VisibleSpriteList::firstvissprite; i < vsprcount; i++, spr++) + { + spritesorter[i] = *spr; + } + } + else + { + // If the compatibility option is on sprites of equal distance need to + // be sorted in inverse order. This is most easily achieved by + // filling the sort array backwards before the sort. + for (i = 0, spr = VisibleSpriteList::firstvissprite + vsprcount - 1; i < vsprcount; i++, spr--) + { + spritesorter[i] = *spr; + } + } + + std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare); + } + + vissprite_t **SortedVisibleSpriteList::spritesorter; + int SortedVisibleSpriteList::spritesortersize = 0; + int SortedVisibleSpriteList::vsprcount; +} diff --git a/src/swrenderer/things/r_visiblespritelist.h b/src/swrenderer/things/r_visiblespritelist.h new file mode 100644 index 0000000000..0e3fddfdc8 --- /dev/null +++ b/src/swrenderer/things/r_visiblespritelist.h @@ -0,0 +1,53 @@ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// + +#pragma once + +namespace swrenderer +{ + struct drawseg_t; + struct vissprite_t; + + class VisibleSpriteList + { + public: + static int MaxVisSprites; + static vissprite_t **vissprites; + static vissprite_t **firstvissprite; + static vissprite_t **vissprite_p; + + static void Deinit(); + static void Clear(); + static vissprite_t *Add(); + + private: + static vissprite_t **lastvissprite; + }; + + class SortedVisibleSpriteList + { + public: + static void Deinit(); + + static void Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first); + + static bool sv_compare(vissprite_t *a, vissprite_t *b); + static bool sv_compare2d(vissprite_t *a, vissprite_t *b); + + static vissprite_t **spritesorter; + static int vsprcount; + + private: + static int spritesortersize; + }; +} diff --git a/src/swrenderer/things/r_voxel.cpp b/src/swrenderer/things/r_voxel.cpp index 2d81f2e62c..c55f7439e0 100644 --- a/src/swrenderer/things/r_voxel.cpp +++ b/src/swrenderer/things/r_voxel.cpp @@ -37,6 +37,7 @@ #include "swrenderer/things/r_visiblesprite.h" #include "swrenderer/things/r_voxel.h" #include "swrenderer/scene/r_portal.h" +#include "swrenderer/scene/r_translucent.h" #include "swrenderer/r_main.h" EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) diff --git a/src/swrenderer/things/r_wallsprite.cpp b/src/swrenderer/things/r_wallsprite.cpp index 307f1bdf08..8fc5ea0932 100644 --- a/src/swrenderer/things/r_wallsprite.cpp +++ b/src/swrenderer/things/r_wallsprite.cpp @@ -40,6 +40,7 @@ #include "p_effect.h" #include "swrenderer/scene/r_bsp.h" #include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/scene/r_translucent.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/drawers/r_draw_pal.h" #include "v_palette.h"