diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e2ffed32..3ba350529 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -885,6 +885,7 @@ set (PCH_SOURCES rendering/hwrenderer/scene/hw_lighting.cpp rendering/hwrenderer/scene/hw_drawlistadd.cpp rendering/hwrenderer/scene/hw_setcolor.cpp + rendering/hwrenderer/scene/hw_meshcache.cpp maploader/edata.cpp maploader/specials.cpp maploader/maploader.cpp diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index c8d4bb0fd..4bfb59407 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -50,6 +50,7 @@ #include "hwrenderer/scene/hw_fakeflat.h" #include "hwrenderer/scene/hw_clipper.h" #include "hwrenderer/scene/hw_portal.h" +#include "hwrenderer/scene/hw_meshcache.h" #include "hw_vrmodes.h" EXTERN_CVAR(Bool, cl_capfps) @@ -127,6 +128,8 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou screen->SetLevelMesh(camera->Level->levelMesh); + meshcache.Update(mainvp); + // Update the attenuation flag of all light defaults for each viewpoint. // This function will only do something if the setting differs. FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index f750a2313..abbd181a1 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -182,6 +182,8 @@ struct HWDrawInfo 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; + bool MeshBuilding = false; + private: // For ProcessLowerMiniseg bool inview; diff --git a/src/rendering/hwrenderer/scene/hw_meshcache.cpp b/src/rendering/hwrenderer/scene/hw_meshcache.cpp new file mode 100644 index 000000000..5c63f4165 --- /dev/null +++ b/src/rendering/hwrenderer/scene/hw_meshcache.cpp @@ -0,0 +1,90 @@ + +#include "hw_meshcache.h" +#include "hw_drawinfo.h" +#include "hw_drawstructs.h" +#include "hw_mesh.h" +#include "g_levellocals.h" + +EXTERN_CVAR(Bool, gl_texture) +EXTERN_CVAR(Float, gl_mask_threshold) + +HWMeshCache meshcache; + +void HWMeshCache::Update(FRenderViewpoint& vp) +{ + auto level = vp.ViewLevel; + unsigned int count = level->sectors.Size(); + Sectors.Resize(count); + for (unsigned int i = 0; i < count; i++) + { + auto sector = &level->sectors[i]; + if (Sectors[i].Sector != sector) // Note: this is just a stupid way to detect we changed map. What is the proper way? + { + Sectors[i].Sector = sector; + Sectors[i].Update(vp); + } + } +} + +void HWCachedSector::Update(FRenderViewpoint& vp) +{ + HWDrawInfo* di = HWDrawInfo::StartDrawInfo(vp.ViewLevel, nullptr, vp, nullptr); + di->MeshBuilding = true; + + // Add all the walls to the draw lists + + for (line_t* line : Sector->Lines) + { + side_t* side = (line->sidedef[0]->sector == Sector) ? line->sidedef[0] : line->sidedef[1]; + + HWWall wall; + wall.sub = Sector->subsectors[0]; + wall.Process(di, side->segs[0], Sector, (line->sidedef[0]->sector == Sector) ? line->backsector : line->frontsector); + } + + // Convert draw lists to meshes + + MeshBuilder state; + + state.SetDepthMask(true); + state.EnableFog(true); + state.SetRenderStyle(STYLE_Source); + + di->drawlists[GLDL_PLAINWALLS].SortWalls(); + di->drawlists[GLDL_PLAINFLATS].SortFlats(); + di->drawlists[GLDL_MASKEDWALLS].SortWalls(); + di->drawlists[GLDL_MASKEDFLATS].SortFlats(); + di->drawlists[GLDL_MASKEDWALLSOFS].SortWalls(); + + // Part 1: solid geometry. This is set up so that there are no transparent parts + state.SetDepthFunc(DF_Less); + state.AlphaFunc(Alpha_GEqual, 0.f); + state.ClearDepthBias(); + state.EnableTexture(gl_texture); + state.EnableBrightmap(true); + di->drawlists[GLDL_PLAINWALLS].DrawWalls(di, state, false); + di->drawlists[GLDL_PLAINFLATS].DrawFlats(di, state, false); + Opaque = state.Create(); + + // Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show + state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + di->drawlists[GLDL_MASKEDWALLS].DrawWalls(di, state, false); + di->drawlists[GLDL_MASKEDFLATS].DrawFlats(di, state, false); + Translucent = state.Create(); + + // Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use. + if (di->drawlists[GLDL_MASKEDWALLSOFS].Size() > 0) + { + state.SetDepthBias(-1, -128); + di->drawlists[GLDL_MASKEDWALLSOFS].DrawWalls(di, state, false); + state.ClearDepthBias(); + TranslucentDepthBiased = state.Create(); + } + else + { + TranslucentDepthBiased.reset(); + } + + di->MeshBuilding = false; + di->EndDrawInfo(); +} diff --git a/src/rendering/hwrenderer/scene/hw_meshcache.h b/src/rendering/hwrenderer/scene/hw_meshcache.h new file mode 100644 index 000000000..868ef686c --- /dev/null +++ b/src/rendering/hwrenderer/scene/hw_meshcache.h @@ -0,0 +1,30 @@ +#pragma once + +#include "hw_mesh.h" +#include "r_defs.h" + +struct FRenderViewpoint; + +class HWCachedSector +{ +public: + sector_t* Sector = nullptr; + + std::unique_ptr Opaque; + std::unique_ptr Translucent; + std::unique_ptr TranslucentDepthBiased; + + void Update(FRenderViewpoint& vp); +}; + +class HWMeshCache +{ +public: + void Update(FRenderViewpoint& vp); + + TArray Sectors; + +private: +}; + +extern HWMeshCache meshcache; diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index d0bfec9cd..4df4342c3 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -565,6 +565,9 @@ void HWWall::PutWall(HWDrawInfo *di, bool translucent) void HWWall::PutPortal(HWDrawInfo *di, int ptype, int plane) { + if (di->MeshBuilding) + return; + HWPortal * portal = nullptr; MakeVertices(di, *screen->RenderState(), false);