From e9dd1c104b212d3f50564ee955ce81c559c2af0a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 18 Mar 2021 10:19:13 +0100 Subject: [PATCH] - started adding the draw list code from GZDoom. --- source/CMakeLists.txt | 1 + source/build/src/engine.cpp | 7 +- source/build/src/polymost.cpp | 19 -- .../rendering/hwrenderer/data/flatvertices.h | 1 - source/common/rendering/v_video.h | 1 - source/core/gamefuncs.cpp | 23 ++ source/core/gamefuncs.h | 3 +- source/core/rendering/scene/hw_drawinfo.h | 222 ++++++++++++++++++ source/core/rendering/scene/hw_drawlist.h | 122 ++++++++++ .../core/rendering/scene/hw_drawlistadd.cpp | 166 +++++++++++++ 10 files changed, 540 insertions(+), 25 deletions(-) create mode 100644 source/core/rendering/scene/hw_drawinfo.h create mode 100644 source/core/rendering/scene/hw_drawlist.h create mode 100644 source/core/rendering/scene/hw_drawlistadd.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 6da475ef4..59fc9b734 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1074,6 +1074,7 @@ set (PCH_SOURCES core/rendering/scene/hw_clipper.cpp core/rendering/scene/hw_walls.cpp core/rendering/render.cpp + core/rendering/scene/hw_drawlistadd.cpp core/console/c_notifybuffer.cpp core/console/d_event.cpp diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index eddcf5f30..6c3981a0b 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -30,6 +30,7 @@ #include "printf.h" #include "gamecontrol.h" #include "render.h" +#include "gamefuncs.h" #ifdef USE_OPENGL # include "mdsprite.h" @@ -1137,7 +1138,7 @@ void renderDrawMasks(void) { const int32_t xs = tspriteptr[i]->x-globalposx, ys = tspriteptr[i]->y-globalposy; const int32_t yp = DMulScale(xs,cosviewingrangeglobalang,ys,sinviewingrangeglobalang, 6); - const int32_t modelp = Polymost::polymost_spriteIsModelOrVoxel(tspriteptr[i]); + const int32_t modelp = spriteIsModelOrVoxel(tspriteptr[i]); if (yp > (4<<8)) { @@ -1201,10 +1202,10 @@ killsprite: int32_t pcstat = tspriteptr[i]->cstat & 48; int32_t pangle = tspriteptr[i]->ang; int j = i + 1; - if (!Polymost::polymost_spriteIsModelOrVoxel(tspriteptr[i])) + if (!spriteIsModelOrVoxel(tspriteptr[i])) { while (j < numSprites && py == spritesxyz[j].y && pcstat == (tspriteptr[j]->cstat & 48) && (pcstat != 16 || pangle == tspriteptr[j]->ang) - && !Polymost::polymost_spriteIsModelOrVoxel(tspriteptr[j])) + && !spriteIsModelOrVoxel(tspriteptr[j])) { j++; } diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index 6674765e6..cf2674003 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -233,25 +233,6 @@ int32_t polymost_spriteHasTranslucency(tspritetype const * const tspr) return checkTranslucentReplacement(tileGetTexture(tspr->picnum)->GetID(), tspr->pal); } -int32_t polymost_spriteIsModelOrVoxel(tspritetype const * const tspr) -{ - if ((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].flags&SPREXT_NOTMD) - return false; - - - if (hw_models && tile2model[Ptile2tile(tspr->picnum, tspr->pal)].modelid >= 0 && - tile2model[Ptile2tile(tspr->picnum, tspr->pal)].framenum >= 0) - return true; - - if (r_voxels && (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) != CSTAT_SPRITE_ALIGNMENT_SLAB && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]]) - return true; - - if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB && voxmodels[tspr->picnum]) - return true; - - return false; -} - static void polymost_updaterotmat(void) { //Up/down rotation diff --git a/source/common/rendering/hwrenderer/data/flatvertices.h b/source/common/rendering/hwrenderer/data/flatvertices.h index 04feb8388..d28339ee7 100644 --- a/source/common/rendering/hwrenderer/data/flatvertices.h +++ b/source/common/rendering/hwrenderer/data/flatvertices.h @@ -9,7 +9,6 @@ class FRenderState; struct secplane_t; -struct subsector_t; struct FFlatVertex { diff --git a/source/common/rendering/v_video.h b/source/common/rendering/v_video.h index ae4b318d0..ee714a6aa 100644 --- a/source/common/rendering/v_video.h +++ b/source/common/rendering/v_video.h @@ -45,7 +45,6 @@ #include "hw_shadowmap.h" -struct sector_t; struct FPortalSceneState; class FSkyVertexBuffer; class IIndexBuffer; diff --git a/source/core/gamefuncs.cpp b/source/core/gamefuncs.cpp index ac81b680f..9a8879a31 100644 --- a/source/core/gamefuncs.cpp +++ b/source/core/gamefuncs.cpp @@ -146,3 +146,26 @@ bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnu return true; } + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +bool spriteIsModelOrVoxel(const spritetype * tspr) +{ + if ((unsigned)tspr->owner < MAXSPRITES && spriteext[tspr->owner].flags & SPREXT_NOTMD) + return false; + + if (hw_models) + { + auto& mdinfo = tile2model[Ptile2tile(tspr->picnum, tspr->pal)]; + if (mdinfo.modelid >= 0 && mdinfo.framenum >= 0) return true; + } + + auto slabalign = (tspr->cstat & CSTAT_SPRITE_ALIGNMENT) == CSTAT_SPRITE_ALIGNMENT_SLAB; + if (r_voxels && !slabalign && tiletovox[tspr->picnum] >= 0 && voxmodels[tiletovox[tspr->picnum]]) return true; + return (slabalign && voxmodels[tspr->picnum]); +} + diff --git a/source/core/gamefuncs.h b/source/core/gamefuncs.h index 0c646aa86..8d118f788 100644 --- a/source/core/gamefuncs.h +++ b/source/core/gamefuncs.h @@ -6,4 +6,5 @@ extern int cameradist, cameraclock; -bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio); \ No newline at end of file +bool calcChaseCamPos(int* px, int* py, int* pz, spritetype* pspr, short *psectnum, binangle ang, fixedhoriz horiz, double const smoothratio); +bool spriteIsModelOrVoxel(const spritetype* tspr); diff --git a/source/core/rendering/scene/hw_drawinfo.h b/source/core/rendering/scene/hw_drawinfo.h new file mode 100644 index 000000000..e10258c03 --- /dev/null +++ b/source/core/rendering/scene/hw_drawinfo.h @@ -0,0 +1,222 @@ +#pragma once + +#include +#include +#include "vectors.h" +#include "hw_viewpointuniforms.h" +#include "v_video.h" +#include "hw_drawlist.h" + +enum EDrawMode +{ + DM_MAINVIEW, + DM_OFFSCREEN, + DM_PORTAL, + DM_SKYPORTAL +}; + +struct FSectorPortalGroup; +struct FLinePortalSpan; +struct FFlatVertex; +class HWWall; +class HWFlat; +class HWSprite; +struct HWDecal; +class IShadowMap; +struct FDynLightData; +struct HUDSprite; +class Clipper; +class HWPortal; +class FFlatVertexBuffer; +class IRenderQueue; +class HWScenePortalBase; +class FRenderState; + +//========================================================================== +// +// these are used to link faked planes due to missing textures to a sector +// +//========================================================================== + +enum SectorRenderFlags +{ + // This is used to merge several subsectors into a single draw item + SSRF_RENDERFLOOR = 1, + SSRF_RENDERCEILING = 2, + SSRF_RENDERALL = 7, + SSRF_PROCESSED = 8, + SSRF_SEEN = 16, +}; + +enum EPortalClip +{ + PClip_InFront, + PClip_Inside, + PClip_Behind, +}; + +enum DrawListType +{ + GLDL_PLAINWALLS, + GLDL_PLAINFLATS, + GLDL_MASKEDWALLS, + GLDL_MASKEDFLATS, + GLDL_MASKEDWALLSOFS, + GLDL_MODELS, + + GLDL_TRANSLUCENT, + GLDL_TRANSLUCENTBORDER, + + GLDL_TYPES, +}; + + +struct HWDrawInfo +{ + struct wallseg + { + float x1, y1, z1, x2, y2, z2; + }; + + HWDrawList drawlists[GLDL_TYPES]; + int vpIndex; + //ELightMode lightmode; + + FLevelLocals *Level; + HWDrawInfo * outer = nullptr; + int FullbrightFlags; + std::atomic spriteindex; + HWPortal *mClipPortal; + HWPortal *mCurrentPortal; + //FRotator mAngles; + Clipper *mClipper; + //FRenderViewpoint Viewpoint; + HWViewpointUniforms VPUniforms; // per-viewpoint uniform state + TArray Portals; + TArray Decals[2]; // the second slot is for mirrors which get rendered in a separate pass. + TArray hudsprites; // These may just be stored by value. + + TArray HandledSubsectors; + + TArray sector_renderflags; + + // This is needed by the BSP traverser. + BitArray CurrentMapSections; // this cannot be a single number, because a group of portals with the same displacement may link different sections. + fixed_t viewx, viewy; // since the nodes are still fixed point, keeping the view position also fixed point for node traversal is faster. + bool multithread; + +private: + // For ProcessLowerMiniseg + bool inview; +// sectortype * viewsubsector; +// sectortype *currentsubsector; // used by the line processing code. + sectortype *currentsector; + + void WorkerThread(); + + void UnclipSubsector(sectortype *sub); + + void AddLine(walltype *seg, bool portalclip); + void AddLines(sectortype* sector); + void AddSpecialPortalLines(sectortype * sector, walltype* line); + public: + //void RenderThings(sectortype * sub, sectortype * sector); + //void RenderParticles(sectortype *sub, sectortype *front); + void SetColor(FRenderState &state, int sectorlightlevel, int rellight, bool fullbright, const FColormap &cm, float alpha, bool weapon = false); + void SetFog(FRenderState &state, int lightlevel, int rellight, bool fullbright, const FColormap *cmap, bool isadditive); + void SetShaderLight(FRenderState &state, float level, float olight); + int CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor); + PalEntry CalcLightColor(int light, PalEntry pe, int blendfactor); + float GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, int blendfactor); + bool CheckFog(sectortype *frontsector, sectortype *backsector); +public: + + void SetCameraPos(const DVector3 &pos) + { + VPUniforms.mCameraPos = { (float)pos.X, (float)pos.Z, (float)pos.Y, 0.f }; + } + + void SetClipHeight(float h, float d) + { + VPUniforms.mClipHeight = h; + VPUniforms.mClipHeightDirection = d; + VPUniforms.mClipLine.X = -1000001.f; + } + + void SetClipLine(walltype *line) + { + //VPUniforms.mClipLine = { (float)line->v1->fX(), (float)line->v1->fY(), (float)line->Delta().X, (float)line->Delta().Y }; + VPUniforms.mClipHeight = 0; + } + + HWPortal * FindPortal(const void * src); + + //static HWDrawInfo *StartDrawInfo(FLevelLocals *lev, HWDrawInfo *parent, FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); + //void StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); + void ClearBuffers(); + HWDrawInfo *EndDrawInfo(); + + void DrawScene(int drawmode); + void CreateScene(bool drawpsprites); + void RenderScene(FRenderState &state); + void RenderTranslucent(FRenderState &state); + void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil); + void EndDrawScene(sectortype * viewsector, FRenderState &state); + void DrawEndScene2D(sectortype * viewsector, FRenderState &state); + void Set3DViewport(FRenderState &state); + void ProcessScene(bool toscreen); + + //void GetDynSpriteLight(AActor *self, float x, float y, float z, FLightNode *node, int portalgroup, float *out); + //void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out); + + void UpdateCurrentMapSection(); + void SetViewMatrix(const FRotator &angles, float vx, float vy, float vz, bool mirror, bool planemirror); + void SetupView(FRenderState &state, float vx, float vy, float vz, bool mirror, bool planemirror); + angle_t FrustumAngle(); + + void DrawDecals(FRenderState &state, TArray &decals); + void DrawPlayerSprites(bool hudModelStep, FRenderState &state); + + //void AddSubsectorToPortal(FSectorPortalGroup *portal, sectortype *sub); + + void AddWall(HWWall *w); + void AddMirrorSurface(HWWall *w); + void AddFlat(HWFlat *flat); + void AddSprite(HWSprite *sprite, bool translucent); + + + HWDecal *AddDecal(bool onmirror); + + bool isSoftwareLighting() const + { + return true;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware || lightmode == ELightMode::Build; + } + + bool isBuildSoftwareLighting() const + { + return true;// lightmode == ELightMode::Build; + } + + bool isDoomSoftwareLighting() const + { + return false;// lightmode == ELightMode::ZDoomSoftware || lightmode == ELightMode::DoomSoftware; + } + + bool isDarkLightMode() const + { + return false;// lightmode == ELightMode::Doom || lightmode == ELightMode::DoomDark; + } + + void SetFallbackLightMode() + { + //lightmode = ELightMode::Doom; + } + +}; + +void CleanSWDrawer(); +//sectortype* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); +//void WriteSavePic(player_t* player, FileWriter* file, int width, int height); +//sectortype* RenderView(player_t* player); + + diff --git a/source/core/rendering/scene/hw_drawlist.h b/source/core/rendering/scene/hw_drawlist.h new file mode 100644 index 000000000..eaa0c471c --- /dev/null +++ b/source/core/rendering/scene/hw_drawlist.h @@ -0,0 +1,122 @@ +#pragma once + +#include "memarena.h" + +extern FMemArena RenderDataAllocator; +void ResetRenderDataAllocator(); +struct HWDrawInfo; +class HWWall; +class HWFlat; +class HWSprite; +class FRenderState; + +//========================================================================== +// +// Intermediate struct to link one draw item into a draw list +// +// unfortunately this struct must not contain pointers because +// the arrays may be reallocated! +// +//========================================================================== + +enum HWDrawItemType +{ + DrawType_WALL, + DrawType_FLAT, + DrawType_SPRITE, +}; + +struct HWDrawItem +{ + HWDrawItemType rendertype; + int index; + + HWDrawItem(HWDrawItemType _rendertype,int _index) : rendertype(_rendertype),index(_index) {} +}; + +struct SortNode +{ + int itemindex; + SortNode * parent; + SortNode * next; // unsorted successor + SortNode * left; // left side of this node + SortNode * equal; // equal to this node + SortNode * right; // right side of this node + + + void UnlinkFromChain(); + void Link(SortNode * hook); + void AddToEqual(SortNode * newnode); + void AddToLeft (SortNode * newnode); + void AddToRight(SortNode * newnode); +}; + +//========================================================================== +// +// One draw list. This contains all info for one type of rendering data +// +//========================================================================== + +struct HWDrawList +{ + //private: + TArray walls; + TArray flats; + TArray sprites; + TArray drawitems; + int SortNodeStart; + float SortZ; + SortNode * sorted; + bool reverseSort; + +public: + HWDrawList() + { + next=NULL; + SortNodeStart=-1; + sorted=NULL; + } + + ~HWDrawList() + { + Reset(); + } + + unsigned int Size() + { + return drawitems.Size(); + } + + HWWall *NewWall(); + HWFlat *NewFlat(); + HWSprite *NewSprite(); + void Reset(); + void SortWalls(); + void SortFlats(); + + + void MakeSortList(); + SortNode * FindSortPlane(SortNode * head); + SortNode * FindSortWall(SortNode * head); + void SortPlaneIntoPlane(SortNode * head,SortNode * sort); + void SortWallIntoPlane(SortNode * head,SortNode * sort); + void SortSpriteIntoPlane(SortNode * head,SortNode * sort); + void SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); + void SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); + int CompareSprites(SortNode * a,SortNode * b); + SortNode * SortSpriteList(SortNode * head); + SortNode * DoSort(HWDrawInfo *di, SortNode * head); + void Sort(HWDrawInfo *di); + + void DoDraw(HWDrawInfo *di, FRenderState &state, bool translucent, int i); + void Draw(HWDrawInfo *di, FRenderState &state, bool translucent); + void DrawWalls(HWDrawInfo *di, FRenderState &state, bool translucent); + void DrawFlats(HWDrawInfo *di, FRenderState &state, bool translucent); + + void DrawSorted(HWDrawInfo *di, FRenderState &state, SortNode * head); + void DrawSorted(HWDrawInfo *di, FRenderState &state); + + HWDrawList * next; +} ; + + diff --git a/source/core/rendering/scene/hw_drawlistadd.cpp b/source/core/rendering/scene/hw_drawlistadd.cpp new file mode 100644 index 000000000..2b3b3f0ec --- /dev/null +++ b/source/core/rendering/scene/hw_drawlistadd.cpp @@ -0,0 +1,166 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2000-2016 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "hw_dynlightdata.h" +#include "hw_cvars.h" +#include "hw_lightbuffer.h" +#include "hw_drawstructs.h" +#include "hw_drawinfo.h" +#include "hw_material.h" +#include "build.h" +#include "polymost.h" +#include "gamefuncs.h" + +EXTERN_CVAR(Bool, gl_seamless) + +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::AddWall(HWWall *wall) +{ +#if 0 + if (wall->flags & HWWall::HWF_TRANSLUCENT) + { + auto newwall = drawlists[GLDL_TRANSLUCENT].NewWall(); + *newwall = *wall; + } + else + { + bool masked = HWWall::passflag[wall->type] == 1 ? false : (wall->texture && wall->texture->isMasked()); + int list; + + if (wall->flags & HWWall::HWF_SKYHACK && wall->type == RENDERWALL_M2S) + { + list = GLDL_MASKEDWALLSOFS; + } + else + { + list = masked ? GLDL_MASKEDWALLS : GLDL_PLAINWALLS; + } + auto newwall = drawlists[list].NewWall(); + *newwall = *wall; + } +#endif +} + +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::AddMirrorSurface(HWWall *w) +{ +#if 0 + w->type = RENDERWALL_MIRRORSURFACE; + auto newwall = drawlists[GLDL_TRANSLUCENTBORDER].NewWall(); + *newwall = *w; + + // Invalidate vertices to allow setting of texture coordinates + newwall->vertcount = 0; + + FVector3 v = newwall->glseg.Normal(); + auto tcs = newwall->tcs; + tcs[HWWall::LOLFT].u = tcs[HWWall::LORGT].u = tcs[HWWall::UPLFT].u = tcs[HWWall::UPRGT].u = v.X; + tcs[HWWall::LOLFT].v = tcs[HWWall::LORGT].v = tcs[HWWall::UPLFT].v = tcs[HWWall::UPRGT].v = v.Z; + newwall->MakeVertices(this, false); + +#if 0 + bool hasDecals = newwall->seg->sidedef && newwall->seg->sidedef->AttachedDecals; + if (hasDecals && Level->HasDynamicLights && !isFullbrightScene()) + { + newwall->SetupLights(this, lightdata); + } + newwall->ProcessDecals(this); +#endif + newwall->dynlightindex = -1; // the environment map should not be affected by lights - only the decals. +#endif +} + +//========================================================================== +// +// FDrawInfo::AddFlat +// +// Checks texture, lighting and translucency settings and puts this +// plane in the appropriate render list. +// +//========================================================================== + +void HWDrawInfo::AddFlat(HWFlat *flat) +{ +#if 0 + int list; + + if (flat->renderstyle != STYLE_Translucent || flat->alpha < 1.f - FLT_EPSILON || flat->texture == nullptr) + { + // translucent portals go into the translucent border list. + list = GLDL_TRANSLUCENTBORDER; + } + else if (flat->texture->GetTranslucency()) + { + if (flat->stack) + { + list = GLDL_TRANSLUCENTBORDER; + } + else + { + list = GLDL_PLAINFLATS; + } + } + else //if (flat->hacktype != SSRF_FLOODHACK) // The flood hack may later need different treatment but with the current setup can go into the existing render list. + { + bool masked = flat->texture->isMasked() && flat->stack; + list = masked ? GLDL_MASKEDFLATS : GLDL_PLAINFLATS; + } + auto newflat = drawlists[list].NewFlat(); + *newflat = *flat; +#endif +} + + +//========================================================================== +// +// +// +//========================================================================== +void HWDrawInfo::AddSprite(HWSprite *sprite, bool translucent) +{ +#if 0 + int list; + // [BB] Allow models to be drawn in the GLDL_TRANSLUCENT pass. + if (translucent || ( (!spriteIsModelOrVoxel(sprite->actor) && !(sprite->actor->cstat & CSTAT_SPRITE_ALIGNMENT_MASK)))) + { + list = GLDL_TRANSLUCENT; + } + else + { + list = GLDL_MODELS; + } + + auto newsprt = drawlists[list].NewSprite(); + *newsprt = *sprite; +#endif +} +