diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e6e01a673..44c72406f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -865,7 +865,9 @@ set( FASTMATH_PCH_SOURCES swrenderer/things/r_wallsprite.cpp swrenderer/things/r_decal.cpp swrenderer/plane/r_visibleplane.cpp + swrenderer/plane/r_visibleplanelist.cpp swrenderer/plane/r_skyplane.cpp + swrenderer/plane/r_planerenderer.cpp swrenderer/plane/r_flatplane.cpp swrenderer/plane/r_slopeplane.cpp polyrenderer/poly_renderer.cpp diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index 805f6aac53..4122623b3f 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -43,6 +43,7 @@ #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/things/r_decal.h" CVAR(Bool, r_fogboundary, true, 0) diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 3a1e3936cc..760ae1b223 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -37,6 +37,7 @@ #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" +#include "swrenderer/plane/r_visibleplane.h" #include "swrenderer/r_memory.h" namespace swrenderer diff --git a/src/swrenderer/plane/r_flatplane.h b/src/swrenderer/plane/r_flatplane.h index 246087c3d1..c72b6402b3 100644 --- a/src/swrenderer/plane/r_flatplane.h +++ b/src/swrenderer/plane/r_flatplane.h @@ -13,10 +13,12 @@ #pragma once -#include "r_visibleplane.h" +#include "r_planerenderer.h" namespace swrenderer { + struct visplane_light; + class RenderFlatPlane : PlaneRenderer { public: diff --git a/src/swrenderer/plane/r_planerenderer.cpp b/src/swrenderer/plane/r_planerenderer.cpp new file mode 100644 index 0000000000..0a6d511bf0 --- /dev/null +++ b/src/swrenderer/plane/r_planerenderer.cpp @@ -0,0 +1,99 @@ +// +// 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 "templates.h" +#include "i_system.h" +#include "w_wad.h" +#include "doomdef.h" +#include "doomstat.h" +#include "r_sky.h" +#include "stats.h" +#include "v_video.h" +#include "a_sharedglobal.h" +#include "c_console.h" +#include "cmdlib.h" +#include "d_net.h" +#include "g_level.h" +#include "gl/dynlights/gl_dynlight.h" +#include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_planerenderer.h" + +namespace swrenderer +{ + void PlaneRenderer::RenderLines(visplane_t *pl) + { + // t1/b1 are at x + // t2/b2 are at x+1 + // spanend[y] is at the right edge + + int x = pl->right - 1; + int t2 = pl->top[x]; + int b2 = pl->bottom[x]; + + if (b2 > t2) + { + fillshort(spanend + t2, b2 - t2, x); + } + + for (--x; x >= pl->left; --x) + { + int t1 = pl->top[x]; + int b1 = pl->bottom[x]; + const int xr = x + 1; + int stop; + + // Draw any spans that have just closed + stop = MIN(t1, b2); + while (t2 < stop) + { + int y = t2++; + int x2 = spanend[y]; + RenderLine(y, xr, x2); + } + stop = MAX(b1, t2); + while (b2 > stop) + { + int y = --b2; + int x2 = spanend[y]; + RenderLine(y, xr, x2); + } + + // Mark any spans that have just opened + stop = MIN(t2, b1); + while (t1 < stop) + { + spanend[t1++] = x; + } + stop = MAX(b2, t2); + while (b1 > stop) + { + spanend[--b1] = x; + } + + t2 = pl->top[x]; + b2 = pl->bottom[x]; + + StepColumn(); + } + // Draw any spans that are still open + while (t2 < b2) + { + int y = --b2; + int x2 = spanend[y]; + RenderLine(y, pl->left, x2); + } + } +} diff --git a/src/swrenderer/plane/r_planerenderer.h b/src/swrenderer/plane/r_planerenderer.h new file mode 100644 index 0000000000..a13fb14e20 --- /dev/null +++ b/src/swrenderer/plane/r_planerenderer.h @@ -0,0 +1,34 @@ +// +// 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 +#include "r_defs.h" + +namespace swrenderer +{ + struct visplane_t; + + class PlaneRenderer + { + public: + void RenderLines(visplane_t *pl); + + virtual void RenderLine(int y, int x1, int x2) = 0; + virtual void StepColumn() { } + + private: + short spanend[MAXHEIGHT]; + }; +} diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index 8a5897bb58..6317928a71 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -38,6 +38,7 @@ #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/scene/r_portal.h" #include "swrenderer/r_memory.h" +#include "swrenderer/plane/r_visibleplane.h" #ifdef _MSC_VER #pragma warning(disable:4244) diff --git a/src/swrenderer/plane/r_slopeplane.h b/src/swrenderer/plane/r_slopeplane.h index 9ea635a26f..6fad957098 100644 --- a/src/swrenderer/plane/r_slopeplane.h +++ b/src/swrenderer/plane/r_slopeplane.h @@ -13,7 +13,7 @@ #pragma once -#include "r_visibleplane.h" +#include "r_planerenderer.h" namespace swrenderer { diff --git a/src/swrenderer/plane/r_visibleplane.cpp b/src/swrenderer/plane/r_visibleplane.cpp index 2f84e18a3e..2fa0fc44d2 100644 --- a/src/swrenderer/plane/r_visibleplane.cpp +++ b/src/swrenderer/plane/r_visibleplane.cpp @@ -123,463 +123,4 @@ namespace swrenderer } NetUpdate(); } - - VisiblePlaneList *VisiblePlaneList::Instance() - { - static VisiblePlaneList instance; - return &instance; - } - - VisiblePlaneList::VisiblePlaneList() - { - for (auto &plane : visplanes) - plane = nullptr; - freehead = &freetail; - } - - void VisiblePlaneList::Deinit() - { - // do not use R_ClearPlanes because at this point the screen pointer is no longer valid. - for (int i = 0; i <= MAXVISPLANES; i++) // new code -- killough - { - for (*freehead = visplanes[i], visplanes[i] = nullptr; *freehead; ) - { - freehead = &(*freehead)->next; - } - } - for (visplane_t *pl = freetail; pl != nullptr; ) - { - visplane_t *next = pl->next; - free(pl); - pl = next; - } - } - - visplane_t *VisiblePlaneList::Add(unsigned hash) - { - visplane_t *check = freetail; - - if (check == nullptr) - { - check = (visplane_t *)M_Malloc(sizeof(*check) + 3 + sizeof(*check->top)*(MAXWIDTH * 2)); - memset(check, 0, sizeof(*check) + 3 + sizeof(*check->top)*(MAXWIDTH * 2)); - check->bottom = check->top + MAXWIDTH + 2; - } - else if (nullptr == (freetail = freetail->next)) - { - freehead = &freetail; - } - - check->lights = nullptr; - - check->next = visplanes[hash]; - visplanes[hash] = check; - return check; - } - - void VisiblePlaneList::Init() - { - int i; - visplane_t *pl; - - // Free all visplanes and let them be re-allocated as needed. - pl = freetail; - - while (pl) - { - visplane_t *next = pl->next; - M_Free(pl); - pl = next; - } - freetail = nullptr; - freehead = &freetail; - - for (i = 0; i < MAXVISPLANES; i++) - { - pl = visplanes[i]; - visplanes[i] = nullptr; - while (pl) - { - visplane_t *next = pl->next; - M_Free(pl); - pl = next; - } - } - } - - void VisiblePlaneList::Clear(bool fullclear) - { - int i; - - // Don't clear fake planes if not doing a full clear. - if (!fullclear) - { - for (i = 0; i <= MAXVISPLANES - 1; i++) // new code -- killough - { - for (visplane_t **probe = &visplanes[i]; *probe != nullptr; ) - { - if ((*probe)->sky < 0) - { // fake: move past it - probe = &(*probe)->next; - } - else - { // not fake: move to freelist - visplane_t *vis = *probe; - *freehead = vis; - *probe = vis->next; - vis->next = nullptr; - freehead = &vis->next; - } - } - } - } - else - { - for (i = 0; i <= MAXVISPLANES; i++) // new code -- killough - { - for (*freehead = visplanes[i], visplanes[i] = nullptr; *freehead; ) - { - freehead = &(*freehead)->next; - } - } - } - } - - visplane_t *VisiblePlaneList::FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal) - { - secplane_t plane; - visplane_t *check; - unsigned hash; // killough - bool isskybox; - const FTransform *xform = &xxform; - fixed_t alpha = FLOAT2FIXED(Alpha); - //angle_t angle = (xform.Angle + xform.baseAngle).BAMs(); - - FTransform nulltransform; - - if (picnum == skyflatnum) // killough 10/98 - { // most skies map together - lightlevel = 0; - xform = &nulltransform; - nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; - nulltransform.xScale = nulltransform.yScale = 1; - nulltransform.Angle = nulltransform.baseAngle = 0.0; - additive = false; - // [RH] Map floor skies and ceiling skies to separate visplanes. This isn't - // always necessary, but it is needed if a floor and ceiling sky are in the - // same column but separated by a wall. If they both try to reside in the - // same visplane, then only the floor sky will be drawn. - plane.set(0., 0., height.fC(), 0.); - isskybox = portal != nullptr && !(portal->mFlags & PORTSF_INSKYBOX); - } - else if (portal != nullptr && !(portal->mFlags & PORTSF_INSKYBOX)) - { - plane = height; - isskybox = true; - } - else - { - plane = height; - isskybox = false; - // kg3D - hack, store alpha in sky - // i know there is ->alpha, but this also allows to identify fake plane - // and ->alpha is for stacked sectors - Clip3DFloors *clip3d = Clip3DFloors::Instance(); - if (clip3d->fake3D & (FAKE3D_FAKEFLOOR | FAKE3D_FAKECEILING)) sky = 0x80000000 | clip3d->fakeAlpha; - else sky = 0; // not skyflatnum so it can't be a sky - portal = nullptr; - alpha = OPAQUE; - } - - // New visplane algorithm uses hash table -- killough - hash = isskybox ? MAXVISPLANES : CalcHash(picnum.GetIndex(), lightlevel, height); - - RenderPortal *renderportal = RenderPortal::Instance(); - - for (check = visplanes[hash]; check; check = check->next) // killough - { - if (isskybox) - { - if (portal == check->portal && plane == check->height) - { - if (portal->mType != PORTS_SKYVIEWPOINT) - { // This skybox is really a stacked sector, so we need to - // check even more. - if (check->extralight == renderportal->stacked_extralight && - check->visibility == renderportal->stacked_visibility && - check->viewpos == renderportal->stacked_viewpos && - ( - // headache inducing logic... :( - (portal->mType != PORTS_STACKEDSECTORTHING) || - ( - check->Alpha == alpha && - check->Additive == additive && - (alpha == 0 || // if alpha is > 0 everything needs to be checked - (plane == check->height && - picnum == check->picnum && - lightlevel == check->lightlevel && - basecolormap == check->colormap && // [RH] Add more checks - *xform == check->xform - ) - ) && - check->viewangle == renderportal->stacked_angle - ) - ) - ) - { - return check; - } - } - else - { - return check; - } - } - } - else - if (plane == check->height && - picnum == check->picnum && - lightlevel == check->lightlevel && - basecolormap == check->colormap && // [RH] Add more checks - *xform == check->xform && - sky == check->sky && - renderportal->CurrentPortalUniq == check->CurrentPortalUniq && - renderportal->MirrorFlags == check->MirrorFlags && - Clip3DFloors::Instance()->CurrentSkybox == check->CurrentSkybox && - ViewPos == check->viewpos - ) - { - return check; - } - } - - check = Add(hash); // killough - - check->height = plane; - check->picnum = picnum; - check->lightlevel = lightlevel; - check->xform = *xform; - check->colormap = basecolormap; // [RH] Save colormap - check->sky = sky; - check->portal = portal; - check->left = viewwidth; // Was SCREENWIDTH -- killough 11/98 - check->right = 0; - check->extralight = renderportal->stacked_extralight; - check->visibility = renderportal->stacked_visibility; - check->viewpos = renderportal->stacked_viewpos; - check->viewangle = renderportal->stacked_angle; - check->Alpha = alpha; - check->Additive = additive; - check->CurrentPortalUniq = renderportal->CurrentPortalUniq; - check->MirrorFlags = renderportal->MirrorFlags; - check->CurrentSkybox = Clip3DFloors::Instance()->CurrentSkybox; - - fillshort(check->top, viewwidth, 0x7fff); - - return check; - } - - visplane_t *VisiblePlaneList::GetRange(visplane_t *pl, int start, int stop) - { - int intrl, intrh; - int unionl, unionh; - int x; - - assert(start >= 0 && start < viewwidth); - assert(stop > start && stop <= viewwidth); - - if (start < pl->left) - { - intrl = pl->left; - unionl = start; - } - else - { - unionl = pl->left; - intrl = start; - } - - if (stop > pl->right) - { - intrh = pl->right; - unionh = stop; - } - else - { - unionh = pl->right; - intrh = stop; - } - - for (x = intrl; x < intrh && pl->top[x] == 0x7fff; x++) - ; - - if (x >= intrh) - { - // use the same visplane - pl->left = unionl; - pl->right = unionh; - } - else - { - // make a new visplane - unsigned hash; - - if (pl->portal != nullptr && !(pl->portal->mFlags & PORTSF_INSKYBOX) && viewactive) - { - hash = MAXVISPLANES; - } - else - { - hash = CalcHash(pl->picnum.GetIndex(), pl->lightlevel, pl->height); - } - visplane_t *new_pl = Add(hash); - - new_pl->height = pl->height; - new_pl->picnum = pl->picnum; - new_pl->lightlevel = pl->lightlevel; - new_pl->xform = pl->xform; - new_pl->colormap = pl->colormap; - new_pl->portal = pl->portal; - new_pl->extralight = pl->extralight; - new_pl->visibility = pl->visibility; - new_pl->viewpos = pl->viewpos; - new_pl->viewangle = pl->viewangle; - new_pl->sky = pl->sky; - new_pl->Alpha = pl->Alpha; - new_pl->Additive = pl->Additive; - new_pl->CurrentPortalUniq = pl->CurrentPortalUniq; - new_pl->MirrorFlags = pl->MirrorFlags; - new_pl->CurrentSkybox = pl->CurrentSkybox; - new_pl->lights = pl->lights; - pl = new_pl; - pl->left = start; - pl->right = stop; - fillshort(pl->top, viewwidth, 0x7fff); - } - return pl; - } - - int VisiblePlaneList::Render() - { - visplane_t *pl; - int i; - int vpcount = 0; - - drawerargs::ds_color = 3; - - RenderPortal *renderportal = RenderPortal::Instance(); - - for (i = 0; i < MAXVISPLANES; i++) - { - for (pl = visplanes[i]; pl; pl = pl->next) - { - // kg3D - draw only correct planes - if (pl->CurrentPortalUniq != renderportal->CurrentPortalUniq || pl->CurrentSkybox != Clip3DFloors::Instance()->CurrentSkybox) - continue; - // kg3D - draw only real planes now - if (pl->sky >= 0) { - vpcount++; - pl->Render(OPAQUE, false, false); - } - } - } - return vpcount; - } - - void VisiblePlaneList::RenderHeight(double height) - { - visplane_t *pl; - int i; - - drawerargs::ds_color = 3; - - DVector3 oViewPos = ViewPos; - DAngle oViewAngle = ViewAngle; - - RenderPortal *renderportal = RenderPortal::Instance(); - - for (i = 0; i < MAXVISPLANES; i++) - { - for (pl = visplanes[i]; pl; pl = pl->next) - { - if (pl->CurrentSkybox != Clip3DFloors::Instance()->CurrentSkybox || pl->CurrentPortalUniq != renderportal->CurrentPortalUniq) - continue; - - if (pl->sky < 0 && pl->height.Zat0() == height) - { - ViewPos = pl->viewpos; - ViewAngle = pl->viewangle; - renderportal->MirrorFlags = pl->MirrorFlags; - - pl->Render(pl->sky & 0x7FFFFFFF, pl->Additive, true); - } - } - } - ViewPos = oViewPos; - ViewAngle = oViewAngle; - } - - void PlaneRenderer::RenderLines(visplane_t *pl) - { - // t1/b1 are at x - // t2/b2 are at x+1 - // spanend[y] is at the right edge - - int x = pl->right - 1; - int t2 = pl->top[x]; - int b2 = pl->bottom[x]; - - if (b2 > t2) - { - fillshort(spanend + t2, b2 - t2, x); - } - - for (--x; x >= pl->left; --x) - { - int t1 = pl->top[x]; - int b1 = pl->bottom[x]; - const int xr = x + 1; - int stop; - - // Draw any spans that have just closed - stop = MIN(t1, b2); - while (t2 < stop) - { - int y = t2++; - int x2 = spanend[y]; - RenderLine(y, xr, x2); - } - stop = MAX(b1, t2); - while (b2 > stop) - { - int y = --b2; - int x2 = spanend[y]; - RenderLine(y, xr, x2); - } - - // Mark any spans that have just opened - stop = MIN(t2, b1); - while (t1 < stop) - { - spanend[t1++] = x; - } - stop = MAX(b2, t2); - while (b1 > stop) - { - spanend[--b1] = x; - } - - t2 = pl->top[x]; - b2 = pl->bottom[x]; - - StepColumn(); - } - // Draw any spans that are still open - while (t2 < b2) - { - int y = --b2; - int x2 = spanend[y]; - RenderLine(y, pl->left, x2); - } - } } diff --git a/src/swrenderer/plane/r_visibleplane.h b/src/swrenderer/plane/r_visibleplane.h index ca4da07547..262d9c4c18 100644 --- a/src/swrenderer/plane/r_visibleplane.h +++ b/src/swrenderer/plane/r_visibleplane.h @@ -68,43 +68,4 @@ namespace swrenderer void AddLights(FLightNode *node); void Render(fixed_t alpha, bool additive, bool masked); }; - - class VisiblePlaneList - { - public: - static VisiblePlaneList *Instance(); - - void Init(); - void Deinit(); - void Clear(bool fullclear); - - visplane_t *FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal); - visplane_t *GetRange(visplane_t *pl, int start, int stop); - - int Render(); - void RenderHeight(double height); - - enum { MAXVISPLANES = 128 }; // must be a power of 2 - visplane_t *visplanes[MAXVISPLANES + 1]; - visplane_t *freetail = nullptr; - visplane_t **freehead = nullptr; - - private: - VisiblePlaneList(); - visplane_t *Add(unsigned hash); - - static unsigned CalcHash(int picnum, int lightlevel, const secplane_t &height) { return (unsigned)((picnum) * 3 + (lightlevel)+(FLOAT2FIXED((height).fD())) * 7) & (MAXVISPLANES - 1); } - }; - - class PlaneRenderer - { - public: - void RenderLines(visplane_t *pl); - - virtual void RenderLine(int y, int x1, int x2) = 0; - virtual void StepColumn() { } - - private: - short spanend[MAXHEIGHT]; - }; } diff --git a/src/swrenderer/plane/r_visibleplanelist.cpp b/src/swrenderer/plane/r_visibleplanelist.cpp new file mode 100644 index 0000000000..299f2f8627 --- /dev/null +++ b/src/swrenderer/plane/r_visibleplanelist.cpp @@ -0,0 +1,439 @@ +// +// 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 "templates.h" +#include "i_system.h" +#include "w_wad.h" +#include "doomdef.h" +#include "doomstat.h" +#include "r_sky.h" +#include "stats.h" +#include "v_video.h" +#include "a_sharedglobal.h" +#include "c_console.h" +#include "cmdlib.h" +#include "d_net.h" +#include "g_level.h" +#include "gl/dynlights/gl_dynlight.h" +#include "swrenderer/r_main.h" +#include "swrenderer/r_memory.h" +#include "swrenderer/scene/r_opaque_pass.h" +#include "swrenderer/scene/r_3dfloors.h" +#include "swrenderer/scene/r_portal.h" +#include "swrenderer/plane/r_flatplane.h" +#include "swrenderer/plane/r_slopeplane.h" +#include "swrenderer/plane/r_skyplane.h" +#include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" +#include "swrenderer/drawers/r_draw.h" + +namespace swrenderer +{ + VisiblePlaneList *VisiblePlaneList::Instance() + { + static VisiblePlaneList instance; + return &instance; + } + + VisiblePlaneList::VisiblePlaneList() + { + for (auto &plane : visplanes) + plane = nullptr; + freehead = &freetail; + } + + void VisiblePlaneList::Deinit() + { + // do not use R_ClearPlanes because at this point the screen pointer is no longer valid. + for (int i = 0; i <= MAXVISPLANES; i++) // new code -- killough + { + for (*freehead = visplanes[i], visplanes[i] = nullptr; *freehead; ) + { + freehead = &(*freehead)->next; + } + } + for (visplane_t *pl = freetail; pl != nullptr; ) + { + visplane_t *next = pl->next; + free(pl); + pl = next; + } + } + + visplane_t *VisiblePlaneList::Add(unsigned hash) + { + visplane_t *check = freetail; + + if (check == nullptr) + { + check = (visplane_t *)M_Malloc(sizeof(*check) + 3 + sizeof(*check->top)*(MAXWIDTH * 2)); + memset(check, 0, sizeof(*check) + 3 + sizeof(*check->top)*(MAXWIDTH * 2)); + check->bottom = check->top + MAXWIDTH + 2; + } + else if (nullptr == (freetail = freetail->next)) + { + freehead = &freetail; + } + + check->lights = nullptr; + + check->next = visplanes[hash]; + visplanes[hash] = check; + return check; + } + + void VisiblePlaneList::Init() + { + int i; + visplane_t *pl; + + // Free all visplanes and let them be re-allocated as needed. + pl = freetail; + + while (pl) + { + visplane_t *next = pl->next; + M_Free(pl); + pl = next; + } + freetail = nullptr; + freehead = &freetail; + + for (i = 0; i < MAXVISPLANES; i++) + { + pl = visplanes[i]; + visplanes[i] = nullptr; + while (pl) + { + visplane_t *next = pl->next; + M_Free(pl); + pl = next; + } + } + } + + void VisiblePlaneList::Clear(bool fullclear) + { + int i; + + // Don't clear fake planes if not doing a full clear. + if (!fullclear) + { + for (i = 0; i <= MAXVISPLANES - 1; i++) // new code -- killough + { + for (visplane_t **probe = &visplanes[i]; *probe != nullptr; ) + { + if ((*probe)->sky < 0) + { // fake: move past it + probe = &(*probe)->next; + } + else + { // not fake: move to freelist + visplane_t *vis = *probe; + *freehead = vis; + *probe = vis->next; + vis->next = nullptr; + freehead = &vis->next; + } + } + } + } + else + { + for (i = 0; i <= MAXVISPLANES; i++) // new code -- killough + { + for (*freehead = visplanes[i], visplanes[i] = nullptr; *freehead; ) + { + freehead = &(*freehead)->next; + } + } + } + } + + visplane_t *VisiblePlaneList::FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal) + { + secplane_t plane; + visplane_t *check; + unsigned hash; // killough + bool isskybox; + const FTransform *xform = &xxform; + fixed_t alpha = FLOAT2FIXED(Alpha); + //angle_t angle = (xform.Angle + xform.baseAngle).BAMs(); + + FTransform nulltransform; + + if (picnum == skyflatnum) // killough 10/98 + { // most skies map together + lightlevel = 0; + xform = &nulltransform; + nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; + nulltransform.xScale = nulltransform.yScale = 1; + nulltransform.Angle = nulltransform.baseAngle = 0.0; + additive = false; + // [RH] Map floor skies and ceiling skies to separate visplanes. This isn't + // always necessary, but it is needed if a floor and ceiling sky are in the + // same column but separated by a wall. If they both try to reside in the + // same visplane, then only the floor sky will be drawn. + plane.set(0., 0., height.fC(), 0.); + isskybox = portal != nullptr && !(portal->mFlags & PORTSF_INSKYBOX); + } + else if (portal != nullptr && !(portal->mFlags & PORTSF_INSKYBOX)) + { + plane = height; + isskybox = true; + } + else + { + plane = height; + isskybox = false; + // kg3D - hack, store alpha in sky + // i know there is ->alpha, but this also allows to identify fake plane + // and ->alpha is for stacked sectors + Clip3DFloors *clip3d = Clip3DFloors::Instance(); + if (clip3d->fake3D & (FAKE3D_FAKEFLOOR | FAKE3D_FAKECEILING)) sky = 0x80000000 | clip3d->fakeAlpha; + else sky = 0; // not skyflatnum so it can't be a sky + portal = nullptr; + alpha = OPAQUE; + } + + // New visplane algorithm uses hash table -- killough + hash = isskybox ? MAXVISPLANES : CalcHash(picnum.GetIndex(), lightlevel, height); + + RenderPortal *renderportal = RenderPortal::Instance(); + + for (check = visplanes[hash]; check; check = check->next) // killough + { + if (isskybox) + { + if (portal == check->portal && plane == check->height) + { + if (portal->mType != PORTS_SKYVIEWPOINT) + { // This skybox is really a stacked sector, so we need to + // check even more. + if (check->extralight == renderportal->stacked_extralight && + check->visibility == renderportal->stacked_visibility && + check->viewpos == renderportal->stacked_viewpos && + ( + // headache inducing logic... :( + (portal->mType != PORTS_STACKEDSECTORTHING) || + ( + check->Alpha == alpha && + check->Additive == additive && + (alpha == 0 || // if alpha is > 0 everything needs to be checked + (plane == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + basecolormap == check->colormap && // [RH] Add more checks + *xform == check->xform + ) + ) && + check->viewangle == renderportal->stacked_angle + ) + ) + ) + { + return check; + } + } + else + { + return check; + } + } + } + else + if (plane == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + basecolormap == check->colormap && // [RH] Add more checks + *xform == check->xform && + sky == check->sky && + renderportal->CurrentPortalUniq == check->CurrentPortalUniq && + renderportal->MirrorFlags == check->MirrorFlags && + Clip3DFloors::Instance()->CurrentSkybox == check->CurrentSkybox && + ViewPos == check->viewpos + ) + { + return check; + } + } + + check = Add(hash); // killough + + check->height = plane; + check->picnum = picnum; + check->lightlevel = lightlevel; + check->xform = *xform; + check->colormap = basecolormap; // [RH] Save colormap + check->sky = sky; + check->portal = portal; + check->left = viewwidth; // Was SCREENWIDTH -- killough 11/98 + check->right = 0; + check->extralight = renderportal->stacked_extralight; + check->visibility = renderportal->stacked_visibility; + check->viewpos = renderportal->stacked_viewpos; + check->viewangle = renderportal->stacked_angle; + check->Alpha = alpha; + check->Additive = additive; + check->CurrentPortalUniq = renderportal->CurrentPortalUniq; + check->MirrorFlags = renderportal->MirrorFlags; + check->CurrentSkybox = Clip3DFloors::Instance()->CurrentSkybox; + + fillshort(check->top, viewwidth, 0x7fff); + + return check; + } + + visplane_t *VisiblePlaneList::GetRange(visplane_t *pl, int start, int stop) + { + int intrl, intrh; + int unionl, unionh; + int x; + + assert(start >= 0 && start < viewwidth); + assert(stop > start && stop <= viewwidth); + + if (start < pl->left) + { + intrl = pl->left; + unionl = start; + } + else + { + unionl = pl->left; + intrl = start; + } + + if (stop > pl->right) + { + intrh = pl->right; + unionh = stop; + } + else + { + unionh = pl->right; + intrh = stop; + } + + for (x = intrl; x < intrh && pl->top[x] == 0x7fff; x++) + ; + + if (x >= intrh) + { + // use the same visplane + pl->left = unionl; + pl->right = unionh; + } + else + { + // make a new visplane + unsigned hash; + + if (pl->portal != nullptr && !(pl->portal->mFlags & PORTSF_INSKYBOX) && viewactive) + { + hash = MAXVISPLANES; + } + else + { + hash = CalcHash(pl->picnum.GetIndex(), pl->lightlevel, pl->height); + } + visplane_t *new_pl = Add(hash); + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xform = pl->xform; + new_pl->colormap = pl->colormap; + new_pl->portal = pl->portal; + new_pl->extralight = pl->extralight; + new_pl->visibility = pl->visibility; + new_pl->viewpos = pl->viewpos; + new_pl->viewangle = pl->viewangle; + new_pl->sky = pl->sky; + new_pl->Alpha = pl->Alpha; + new_pl->Additive = pl->Additive; + new_pl->CurrentPortalUniq = pl->CurrentPortalUniq; + new_pl->MirrorFlags = pl->MirrorFlags; + new_pl->CurrentSkybox = pl->CurrentSkybox; + new_pl->lights = pl->lights; + pl = new_pl; + pl->left = start; + pl->right = stop; + fillshort(pl->top, viewwidth, 0x7fff); + } + return pl; + } + + int VisiblePlaneList::Render() + { + visplane_t *pl; + int i; + int vpcount = 0; + + drawerargs::ds_color = 3; + + RenderPortal *renderportal = RenderPortal::Instance(); + + for (i = 0; i < MAXVISPLANES; i++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + // kg3D - draw only correct planes + if (pl->CurrentPortalUniq != renderportal->CurrentPortalUniq || pl->CurrentSkybox != Clip3DFloors::Instance()->CurrentSkybox) + continue; + // kg3D - draw only real planes now + if (pl->sky >= 0) { + vpcount++; + pl->Render(OPAQUE, false, false); + } + } + } + return vpcount; + } + + void VisiblePlaneList::RenderHeight(double height) + { + visplane_t *pl; + int i; + + drawerargs::ds_color = 3; + + DVector3 oViewPos = ViewPos; + DAngle oViewAngle = ViewAngle; + + RenderPortal *renderportal = RenderPortal::Instance(); + + for (i = 0; i < MAXVISPLANES; i++) + { + for (pl = visplanes[i]; pl; pl = pl->next) + { + if (pl->CurrentSkybox != Clip3DFloors::Instance()->CurrentSkybox || pl->CurrentPortalUniq != renderportal->CurrentPortalUniq) + continue; + + if (pl->sky < 0 && pl->height.Zat0() == height) + { + ViewPos = pl->viewpos; + ViewAngle = pl->viewangle; + renderportal->MirrorFlags = pl->MirrorFlags; + + pl->Render(pl->sky & 0x7FFFFFFF, pl->Additive, true); + } + } + } + ViewPos = oViewPos; + ViewAngle = oViewAngle; + } +} diff --git a/src/swrenderer/plane/r_visibleplanelist.h b/src/swrenderer/plane/r_visibleplanelist.h new file mode 100644 index 0000000000..3db52d5bbc --- /dev/null +++ b/src/swrenderer/plane/r_visibleplanelist.h @@ -0,0 +1,51 @@ +// +// 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 +#include "r_defs.h" + +struct FSectorPortal; + +namespace swrenderer +{ + struct visplane_t; + + class VisiblePlaneList + { + public: + static VisiblePlaneList *Instance(); + + void Init(); + void Deinit(); + void Clear(bool fullclear); + + visplane_t *FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal); + visplane_t *GetRange(visplane_t *pl, int start, int stop); + + int Render(); + void RenderHeight(double height); + + enum { MAXVISPLANES = 128 }; // must be a power of 2 + visplane_t *visplanes[MAXVISPLANES + 1]; + visplane_t *freetail = nullptr; + visplane_t **freehead = nullptr; + + private: + VisiblePlaneList(); + visplane_t *Add(unsigned hash); + + static unsigned CalcHash(int picnum, int lightlevel, const secplane_t &height) { return (unsigned)((picnum) * 3 + (lightlevel)+(FLOAT2FIXED((height).fD())) * 7) & (MAXVISPLANES - 1); } + }; +} diff --git a/src/swrenderer/r_main.cpp b/src/swrenderer/r_main.cpp index cdbc083d5e..f07b26162f 100644 --- a/src/swrenderer/r_main.cpp +++ b/src/swrenderer/r_main.cpp @@ -69,6 +69,7 @@ #include "c_console.h" #include "r_memory.h" #include "swrenderer/things/r_playersprite.h" +#include "swrenderer/plane/r_visibleplanelist.h" CVAR (String, r_viewsize, "", CVAR_NOSET) CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index 99d79f10d7..f43c269320 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -35,6 +35,7 @@ #include "swrenderer/r_main.h" #include "swrenderer/drawers/r_draw.h" #include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/things/r_sprite.h" #include "swrenderer/things/r_wallsprite.h" #include "swrenderer/things/r_voxel.h" diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index b235944d87..1ff62438af 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -48,6 +48,7 @@ #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" #include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/things/r_visiblesprite.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_translucent_pass.h" diff --git a/src/swrenderer/scene/r_translucent_pass.cpp b/src/swrenderer/scene/r_translucent_pass.cpp index 48cf627dc8..6b6db1caae 100644 --- a/src/swrenderer/scene/r_translucent_pass.cpp +++ b/src/swrenderer/scene/r_translucent_pass.cpp @@ -34,6 +34,7 @@ #include "swrenderer/scene/r_portal.h" #include "swrenderer/scene/r_translucent_pass.h" #include "swrenderer/plane/r_visibleplane.h" +#include "swrenderer/plane/r_visibleplanelist.h" #include "swrenderer/r_memory.h" EXTERN_CVAR(Int, r_drawfuzz)