diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index d54611dd5..699fe2b86 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -416,7 +416,6 @@ void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap) } FlatUpdateList.Clear(); - UpdateWallPortals(); UploadDynLights(doomMap); Collision->Update(); @@ -469,16 +468,9 @@ void DoomLevelMesh::UploadDynLights(FLevelLocals& doomMap) UploadRanges.DynLight.Add(0, sizeof(int) * 4 + totalsize * sizeof(FDynLightInfo)); } -void DoomLevelMesh::UpdateWallPortals() +TArray& DoomLevelMesh::GetSidePortals(int sideIndex) { - WallPortals.Clear(); - for (int sideIndex : SidePortals) - { - for (HWWall& wall : Sides[sideIndex].WallPortals) - { - WallPortals.Push(&wall); - } - } + return Sides[sideIndex].WallPortals; } void DoomLevelMesh::ProcessDecals(HWDrawInfo* di, FRenderState& state) diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 71f23836c..3a172c5cf 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -109,10 +109,10 @@ public: void DrawSector(FRenderState& renderstate, int sectorIndex, LevelMeshDrawType drawType, bool noFragmentShader); void DrawSide(FRenderState& renderstate, int sideIndex, LevelMeshDrawType drawType, bool noFragmentShader); + TArray& GetSidePortals(int sideIndex); TArray SideDecals; TArray SidePortals; - TArray WallPortals; TArray sectorGroup; // index is sector, value is sectorGroup TArray sectorPortals[2]; // index is sector+plane, value is index into the portal list @@ -179,8 +179,6 @@ private: void FreeSide(FLevelLocals& doomMap, unsigned int sideIndex); void FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex); - void UpdateWallPortals(); - void SetSubsectorLightmap(int surfaceIndex); void SetSideLightmap(int surfaceIndex); diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 114d8592e..cc4c1c5b6 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -56,6 +56,7 @@ CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) EXTERN_CVAR(Float, r_actorspriteshadowdist) EXTERN_CVAR(Bool, r_radarclipper) EXTERN_CVAR(Bool, r_dithertransparency) +EXTERN_CVAR(Bool, gl_levelmesh) thread_local bool isWorkerThread; ctpl::thread_pool renderPool(1); @@ -395,6 +396,14 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip, FRenderState& state) { jobQueue.AddJob(RenderJob::WallJob, seg->Subsector, seg); } + else if (uselevelmesh) + { + if (seg->sidedef) + { + SeenSides.Add(seg->sidedef->Index()); + rendered_lines++; + } + } else { HWWall wall; @@ -887,6 +896,10 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state) { jobQueue.AddJob(RenderJob::FlatJob, sub); } + else if (uselevelmesh) + { + SeenSectors.Add(sub->sector->Index()); + } else { HWFlat flat; @@ -917,6 +930,10 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state) { jobQueue.AddJob(RenderJob::PortalJob, sub, (seg_t *)portal); } + else if (uselevelmesh) + { + // To do: what to do here? + } else { AddSubsectorToPortal(portal, sub); @@ -930,6 +947,10 @@ void HWDrawInfo::DoSubsector(subsector_t * sub, FRenderState& state) { jobQueue.AddJob(RenderJob::PortalJob, sub, (seg_t *)portal); } + else if (uselevelmesh) + { + // To do: what to do here? + } else { AddSubsectorToPortal(portal, sub); @@ -1030,6 +1051,13 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites, FRenderState& state) validcount++; // used for processing sidedefs only once by the renderer. multithread = gl_multithread; + uselevelmesh = gl_levelmesh && !outer; + if (uselevelmesh) + multithread = false; + + SeenSectors.Clear(); + SeenSides.Clear(); + if (multithread) { jobQueue.ReleaseAll(); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index f71db35f9..84fb6dc84 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -464,168 +464,23 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) // clip the scene and fill the drawlists - if (gl_levelmesh && !outer) + RenderBSP(Level->HeadNode(), drawpsprites, state); + + if (uselevelmesh) { - // Give the DrawInfo the viewpoint in fixed point because that's what the nodes are. - viewx = FLOAT2FIXED(Viewpoint.Pos.X); - viewy = FLOAT2FIXED(Viewpoint.Pos.Y); + level.levelMesh->CurFrameStats.Portals++; - validcount++; // used for processing sidedefs only once by the renderer. - - auto& portals = level.levelMesh->WallPortals; - - // draw level into depth buffer - state.SetColorMask(false); - state.SetCulling(Cull_CW); - - int numSectors = level.sectors.Size(); - int numSides = level.sides.Size(); - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Opaque, true); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Opaque, true); - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Masked, true); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Masked, true); - - if (gl_portals) + for (int sideIndex : SeenSides.Get()) { - state.SetDepthBias(1, 128); - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Portal, true); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Portal, true); - - state.SetDepthBias(0, 0); - } - - // use occlusion queries on all portals in level to decide which are visible - int queryStart = state.GetNextQueryIndex(); - state.SetDepthMask(false); - state.EnableTexture(false); - state.SetEffect(EFF_PORTAL); - - if (!gl_portals) - state.SetColorMask(true); // For debugging where the query is - - for (HWWall* wall : portals) - { - state.BeginQuery(); - - // sector portals not handled yet by PutWallPortal - if (wall->portaltype != PORTALTYPE_SECTORSTACK) + for (HWWall& portal : level.levelMesh->GetSidePortals(sideIndex)) { - wall->MakeVertices(state, false); - wall->RenderWall(state, HWWall::RWF_BLANK); - wall->vertcount = 0; - } - - state.EndQuery(); - } - state.SetEffect(EFF_NONE); - state.EnableTexture(gl_texture); - state.SetColorMask(true); - state.SetDepthMask(true); - int queryEnd = state.GetNextQueryIndex(); - - state.DispatchLightTiles(VPUniforms.mViewMatrix, VPUniforms.mProjectionMatrix.get()[5]); - - // draw opaque level so the GPU has something to do while we examine the query results - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Opaque, false); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Opaque, false); - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Masked, false); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Masked, false); - - if (!gl_portals) - { - state.SetDepthBias(1, 128); - - for (int i = 0; i < numSectors; i++) - level.levelMesh->DrawSector(state, i, LevelMeshDrawType::Portal, false); - for (int i = 0; i < numSides; i++) - level.levelMesh->DrawSide(state, i, LevelMeshDrawType::Portal, false); - - state.SetDepthBias(0, 0); - } - state.SetCulling(Cull_None); - - if (queryStart != queryEnd) - { - // retrieve the query results and use them to fill the portal manager with portals - state.GetQueryResults(queryStart, queryEnd - queryStart, QueryResultsBuffer); - for (unsigned int i = 0, count = QueryResultsBuffer.Size(); i < count; i++) - { - bool portalVisible = QueryResultsBuffer[i]; - if (portalVisible) + // sector portals not handled yet by PutWallPortal + if (portal.portaltype != PORTALTYPE_SECTORSTACK) { - PutWallPortal(*portals[i], state); + PutWallPortal(portal, state); } } } - - // Draw Decals - { - level.levelMesh->ProcessDecals(this, state); - state.SetRenderStyle(STYLE_Translucent); - state.SetDepthFunc(DF_LEqual); - DrawDecals(state, Decals[0]); - DrawDecals(state, Decals[1]); // Mirror decals - when should they be drawn? - Decals[0].Clear(); - Decals[1].Clear(); - } - - // Draw sprites - auto it = level.GetThinkerIterator(); - AActor* thing; - while ((thing = it.Next()) != nullptr) - { - HWSprite sprite; - - if (R_ShouldDrawSpriteShadow(thing)) - { - double dist = (thing->Pos() - vp.Pos).LengthSquared(); - double check = r_actorspriteshadowdist; - if (dist <= check * check) - { - sprite.Process(this, state, thing, thing->Sector, in_area, false, true); - } - } - - sprite.Process(this, state, thing, thing->Sector, in_area, false); - } - - // Draw particles - for (uint16_t i = level.ActiveParticles; i != NO_PARTICLE; i = level.Particles[i].tnext) - { - if (Level->Particles[i].subsector) - { - HWSprite sprite; - sprite.ProcessParticle(this, state, &Level->Particles[i], Level->Particles[i].subsector->sector, nullptr); - } - } - - // Process all the sprites on the current portal's back side which touch the portal. - if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this, state); - - if (drawpsprites) - PreparePlayerSprites(Viewpoint.sector, in_area, state); - } - else - { - if (gl_levelmesh && level.levelMesh) - level.levelMesh->CurFrameStats.Portals++; - - RenderBSP(Level->HeadNode(), drawpsprites, state); } // And now the crappy hacks that have to be done to avoid rendering anomalies. @@ -847,12 +702,22 @@ void HWDrawInfo::RenderScene(FRenderState &state) state.EnableTexture(gl_texture); state.EnableBrightmap(true); + + // To do: replace this is classic light lists + DrawSeenSides(state, LevelMeshDrawType::Opaque, true); + DrawSeenFlats(state, LevelMeshDrawType::Opaque, true); + state.DispatchLightTiles(VPUniforms.mViewMatrix, VPUniforms.mProjectionMatrix.get()[5]); + + DrawSeenSides(state, LevelMeshDrawType::Opaque, false); drawlists[GLDL_PLAINWALLS].DrawWalls(this, state, false); + DrawSeenFlats(state, LevelMeshDrawType::Opaque, false); drawlists[GLDL_PLAINFLATS].DrawFlats(this, state, false); // 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); + DrawSeenSides(state, LevelMeshDrawType::Masked, false); drawlists[GLDL_MASKEDWALLS].DrawWalls(this, state, false); + DrawSeenFlats(state, LevelMeshDrawType::Masked, false); drawlists[GLDL_MASKEDFLATS].DrawFlats(this, state, false); // Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use. @@ -876,6 +741,18 @@ void HWDrawInfo::RenderScene(FRenderState &state) RenderAll.Unclock(); } +void HWDrawInfo::DrawSeenSides(FRenderState& state, LevelMeshDrawType drawType, bool noFragmentShader) +{ + for (int sideIndex : SeenSides.Get()) + level.levelMesh->DrawSide(state, sideIndex, drawType, noFragmentShader); +} + +void HWDrawInfo::DrawSeenFlats(FRenderState& state, LevelMeshDrawType drawType, bool noFragmentShader) +{ + for (int sectorIndex : SeenSectors.Get()) + level.levelMesh->DrawSector(state, sectorIndex, drawType, noFragmentShader); +} + //----------------------------------------------------------------------------- // // RenderTranslucent @@ -894,6 +771,10 @@ void HWDrawInfo::RenderTranslucent(FRenderState &state) drawlists[GLDL_TRANSLUCENTBORDER].Draw(this, state, true); state.SetDepthMask(false); + // To do: this needs to be sorted + DrawSeenSides(state, LevelMeshDrawType::Translucent, false); + DrawSeenFlats(state, LevelMeshDrawType::Translucent, false); + drawlists[GLDL_TRANSLUCENT].DrawSorted(this, state); state.EnableBrightmap(false); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index 7d99f89f6..7850db01c 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -191,6 +191,42 @@ struct HWDrawInfo area_t in_area; 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 uselevelmesh; + + struct VisList + { + const TArray& Get() const { return List; } + + void Clear() + { + for (int index : List) + AddedToList[index] = false; + List.Clear(); + } + + void Add(int index) + { + if (index >= (int)AddedToList.size()) + { + int lastSize = AddedToList.size(); + AddedToList.resize(index + 1); // Beware! TArray does not clear on resize! + for (int i = lastSize; i < index + 1; i++) + AddedToList[i] = false; + } + + if (!AddedToList[index]) + { + AddedToList[index] = true; + List.Push(index); + } + } + + private: + TArray List; + TArray AddedToList; + }; + + VisList SeenSectors, SeenSides; TArray QueryResultsBuffer; @@ -392,6 +428,9 @@ private: void AddSpecialPortalLines(subsector_t* sub, sector_t* sector, linebase_t* line, FRenderState& state); void UpdateLightmaps(); + + void DrawSeenSides(FRenderState& state, LevelMeshDrawType drawType, bool noFragmentShader); + void DrawSeenFlats(FRenderState& state, LevelMeshDrawType drawType, bool noFragmentShader); }; void CleanSWDrawer();