Implement drawing HWWall portals using the level mesh and occlusion queries

This commit is contained in:
Magnus Norddahl 2023-12-04 12:20:31 +01:00
commit 86ac07f2f8
11 changed files with 141 additions and 32 deletions

View file

@ -63,6 +63,7 @@ void DoomLevelSubmesh::UpdateDynamic(FLevelLocals& doomMap, int lightmapStartInd
void DoomLevelSubmesh::Reset()
{
Surfaces.Clear();
WallPortals.Clear();
MeshVertices.Clear();
MeshElements.Clear();
MeshSurfaceIndexes.Clear();
@ -168,6 +169,11 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
surf.PipelineID = pipelineID;
Surfaces.Push(surf);
}
for (const HWWall& portal : result.portals)
{
WallPortals.Push(portal);
}
}
// Create surfaces for all flats

View file

@ -2,6 +2,7 @@
#pragma once
#include "hw_levelmesh.h"
#include "scene/hw_drawstructs.h"
#include "tarray.h"
#include "vectors.h"
#include "r_defs.h"
@ -14,16 +15,6 @@ typedef dp::rect_pack::RectPacker<int> RectPacker;
struct FLevelLocals;
struct FPolyObj;
enum DoomLevelMeshSurfaceType
{
ST_NONE,
ST_MIDDLESIDE,
ST_UPPERSIDE,
ST_LOWERSIDE,
ST_CEILING,
ST_FLOOR
};
struct DoomLevelMeshSurface : public LevelMeshSurface
{
DoomLevelMeshSurfaceType Type = ST_NONE;
@ -58,6 +49,8 @@ public:
TArray<std::unique_ptr<DoomLevelMeshSurface*[]>> PolyLMSurfaces;
TArray<HWWall> WallPortals;
private:
void Reset();
void BuildSectorGroups(const FLevelLocals& doomMap);

View file

@ -35,6 +35,7 @@
#include "hw_renderstate.h"
#include "hw_drawinfo.h"
#include "hw_drawcontext.h"
#include "hw_walldispatcher.h"
#include "po_man.h"
#include "models.h"
#include "hw_clock.h"
@ -403,21 +404,59 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
if (gl_levelmesh)
{
// To do:
// 1) draw level into depth buffer
// 2) use occlusion queries on all portals in level to decide which are visible
// 3) draw opaque level so the GPU has something to do while we examine the query results
// 4) retrieve the query results and use them to fill the portal manager with portals
//
// 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);
validcount++; // used for processing sidedefs only once by the renderer.
auto& wallPortals = static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->WallPortals;
// draw level into depth buffer
state.DrawLevelMeshDepthPass();
// for (HWWall& wall : PortalWalls) { state.BeginQuery(); wall.Draw(state); state.EndQuery(); }
// for (HWFlat& flat : PortalFlats) { state.BeginQuery(); flat.Draw(state); state.EndQuery(); }
// use occlusion queries on all portals in level to decide which are visible
int queryStart = state.GetNextQueryIndex();
state.SetColorMask(false);
state.SetDepthMask(false);
state.EnableTexture(false);
state.SetEffect(EFF_FOGBOUNDARY);
state.AlphaFunc(Alpha_GEqual, 0.f);
for (HWWall& wall : wallPortals)
{
state.BeginQuery();
wall.MakeVertices(state, false);
wall.RenderWall(state, HWWall::RWF_BLANK);
wall.vertcount = 0;
state.EndQuery();
}
state.SetEffect(EFF_NONE);
state.EnableTexture(true);
state.SetColorMask(true);
state.SetDepthMask(true);
int queryEnd = state.GetNextQueryIndex();
// draw opaque level so the GPU has something to do while we examine the query results
state.DrawLevelMeshOpaquePass();
state.GetQueryResults(QueryResultsBuffer);
// 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)
{
PutWallPortal(wallPortals[i], state);
}
}
// 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
{
@ -447,6 +486,34 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
}
void HWDrawInfo::PutWallPortal(HWWall wall, FRenderState& state)
{
HWWallDispatcher ddi(this);
int portaltype = wall.portaltype;
int portalplane = wall.portalplane;
HWSkyInfo skyinfo;
if (portaltype == PORTALTYPE_SKY)
{
skyinfo.init(this, wall.frontsector->sky, wall.Colormap.FadeColor);
wall.sky = &skyinfo;
}
else if (portaltype == PORTALTYPE_SECTORSTACK)
{
if (screen->instack[1 - portalplane])
return;
}
else if (portaltype == PORTALTYPE_PLANEMIRROR)
{
auto vpz = Viewpoint.Pos.Z;
if ((portalplane == sector_t::ceiling && vpz > wall.frontsector->ceilingplane.fD()) || (portalplane == sector_t::floor && vpz < -wall.frontsector->floorplane.fD()))
return;
wall.planemirror = (portalplane == sector_t::ceiling) ? &wall.frontsector->ceilingplane : &wall.frontsector->floorplane;
}
wall.PutPortal(&ddi, state, portaltype, portalplane);
}
void HWDrawInfo::UpdateLightmaps()
{
if (!outer && VisibleSurfaces.Size() < unsigned(lm_background_updates))
@ -850,7 +917,7 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state)
}
state.SetDepthMask(true);
if (!gl_no_skyclear) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state);
if (!gl_no_skyclear && !gl_levelmesh) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state);
RenderScene(state);

View file

@ -262,6 +262,7 @@ public:
void DrawScene(int drawmode, FRenderState& state);
void CreateScene(bool drawpsprites, FRenderState& state);
void PutWallPortal(HWWall wall, FRenderState& state);
void RenderScene(FRenderState &state);
void RenderTranslucent(FRenderState &state);
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil);

View file

@ -8,7 +8,6 @@
#include "renderstyle.h"
#include "textures.h"
#include "r_data/colormaps.h"
#include "doom_levelmesh.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)
@ -33,6 +32,7 @@ struct HWDecal;
struct FSection;
enum area_t : int;
class HWDrawContext;
class DoomLevelMeshSurface;
enum HWRenderStyle
{
@ -67,6 +67,16 @@ enum PortalTypes
PORTALTYPE_LINETOLINE,
};
enum DoomLevelMeshSurfaceType
{
ST_NONE,
ST_MIDDLESIDE,
ST_UPPERSIDE,
ST_LOWERSIDE,
ST_CEILING,
ST_FLOOR
};
//==========================================================================
//
// One sector plane, still in fixed point

View file

@ -126,9 +126,9 @@ void HWWall::SkyPlane(HWWallDispatcher *di, FRenderState& state, sector_t *secto
{
HWSkyInfo skyinfo;
skyinfo.init(di->di, sector->sky, Colormap.FadeColor);
ptype = PORTALTYPE_SKY;
sky = &skyinfo;
}
ptype = PORTALTYPE_SKY;
PutPortal(di, state, ptype, plane);
}
else if (sportal != nullptr)