// // 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_memory.h" #include "swrenderer/scene/r_opaque_pass.h" #include "swrenderer/scene/r_3dfloors.h" #include "swrenderer/scene/r_portal.h" #include "swrenderer/scene/r_scene.h" #include "swrenderer/scene/r_light.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" #include "swrenderer/viewport/r_viewport.h" #include "swrenderer/r_renderthread.h" namespace swrenderer { VisiblePlaneList::VisiblePlaneList(RenderThread *thread) { Thread = thread; } VisiblePlaneList::VisiblePlaneList() { for (auto &plane : visplanes) plane = nullptr; } VisiblePlane *VisiblePlaneList::Add(unsigned hash) { VisiblePlane *newplane = Thread->FrameMemory->NewObject(Thread); newplane->next = visplanes[hash]; visplanes[hash] = newplane; return newplane; } void VisiblePlaneList::Clear() { for (int i = 0; i <= MAXVISPLANES; i++) visplanes[i] = nullptr; } void VisiblePlaneList::ClearKeepFakePlanes() { for (int i = 0; i <= MAXVISPLANES - 1; i++) { for (VisiblePlane **probe = &visplanes[i]; *probe != nullptr; ) { if ((*probe)->sky < 0) { // fake: move past it probe = &(*probe)->next; } else { // not fake: move from list VisiblePlane *vis = *probe; *probe = vis->next; vis->next = nullptr; } } } } VisiblePlane *VisiblePlaneList::FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal, FDynamicColormap *basecolormap) { secplane_t plane; VisiblePlane *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 = Thread->Clip3D.get(); 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 ? ((unsigned)MAXVISPLANES) : CalcHash(picnum.GetIndex(), lightlevel, height); RenderPortal *renderportal = Thread->Portal.get(); 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 && Thread->Clip3D->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->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 = Thread->Clip3D->CurrentSkybox; return check; } VisiblePlane *VisiblePlaneList::GetRange(VisiblePlane *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; } x = intrl; while (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); } VisiblePlane *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; } return pl; } bool VisiblePlaneList::HasPortalPlanes() const { return visplanes[MAXVISPLANES] != nullptr; } VisiblePlane *VisiblePlaneList::PopFirstPortalPlane() { VisiblePlane *pl = visplanes[VisiblePlaneList::MAXVISPLANES]; if (pl) { visplanes[VisiblePlaneList::MAXVISPLANES] = pl->next; pl->next = nullptr; } return pl; } void VisiblePlaneList::ClearPortalPlanes() { visplanes[VisiblePlaneList::MAXVISPLANES] = nullptr; } int VisiblePlaneList::Render() { VisiblePlane *pl; int i; int vpcount = 0; RenderPortal *renderportal = Thread->Portal.get(); 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 != Thread->Clip3D->CurrentSkybox) continue; // kg3D - draw only real planes now if (pl->sky >= 0) { vpcount++; pl->Render(Thread, OPAQUE, false, false); } } } return vpcount; } void VisiblePlaneList::RenderHeight(double height) { VisiblePlane *pl; int i; DVector3 oViewPos = ViewPos; DAngle oViewAngle = ViewAngle; RenderPortal *renderportal = Thread->Portal.get(); for (i = 0; i < MAXVISPLANES; i++) { for (pl = visplanes[i]; pl; pl = pl->next) { if (pl->CurrentSkybox != Thread->Clip3D->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(Thread, pl->sky & 0x7FFFFFFF, pl->Additive, true); } } } ViewPos = oViewPos; ViewAngle = oViewAngle; } }