diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index d7c5a98c6..b5372fcc8 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -31,6 +31,7 @@ enum ERenderEffect EFF_SPHEREMAP, EFF_BURN, EFF_STENCIL, + EFF_PORTAL, MAX_EFFECTS }; @@ -689,8 +690,8 @@ public: } // Draw level mesh - virtual void DrawLevelMeshDepthPass() { } - virtual void DrawLevelMeshOpaquePass() { } + virtual void DrawLevelMeshSurfaces(bool noFragmentShader) { } + virtual void DrawLevelMeshPortals(bool noFragmentShader) { } virtual int GetNextQueryIndex() { return 0; } virtual void BeginQuery() { } virtual void EndQuery() { } diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 16f147f81..e1a6379a9 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -71,6 +71,7 @@ VkShaderProgram* VkShaderManager::Get(const VkShaderKey& key) { "spheremap", "shaders/scene/frag_main.glsl", "shaders/scene/material_default.glsl", "shaders/scene/mateffect_default.glsl", "shaders/scene/lightmodel_normal.glsl", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, { "burn", "shaders/scene/frag_burn.glsl", nullptr, nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, { "stencil", "shaders/scene/frag_stencil.glsl", nullptr, nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "portal", "shaders/scene/frag_portal.glsl", nullptr, nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, }; const auto& desc = effectshaders[key.SpecialEffect]; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 958f3f783..40186cb37 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -851,31 +851,31 @@ void VkRenderState::ApplyLevelMesh() mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32); } -void VkRenderState::DrawLevelMeshDepthPass() +void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader) { ApplyLevelMesh(); - auto submesh = fb->GetLevelMesh()->GetMesh()->StaticMesh.get(); - for (LevelSubmeshDrawRange& range : submesh->DrawList) + auto mesh = fb->GetLevelMesh()->GetMesh(); + for (LevelSubmesh* submesh : { mesh->StaticMesh.get(), mesh->DynamicMesh.get() }) { - DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, true); + for (LevelSubmeshDrawRange& range : submesh->DrawList) + { + DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); + } } - /* - for (LevelSubmeshDrawRange& range : submesh->PortalList) - { - DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, true); - } - */ } -void VkRenderState::DrawLevelMeshOpaquePass() +void VkRenderState::DrawLevelMeshPortals(bool noFragmentShader) { ApplyLevelMesh(); - auto submesh = fb->GetLevelMesh()->GetMesh()->StaticMesh.get(); - for (LevelSubmeshDrawRange& range : submesh->DrawList) + auto mesh = fb->GetLevelMesh()->GetMesh(); + for (LevelSubmesh* submesh : { mesh->StaticMesh.get(), mesh->DynamicMesh.get() }) { - DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, false); + for (LevelSubmeshDrawRange& range : submesh->PortalList) + { + DrawLevelMeshRange(mCommandBuffer, fb->GetLevelMeshPipelineKey(range.PipelineID), range.Start, range.Count, noFragmentShader); + } } } @@ -925,6 +925,8 @@ void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelin pipelineKey.StencilPassOp = mStencilOp; pipelineKey.ColorMask = mColorMask; pipelineKey.CullMode = mCullMode; + if (!mTextureEnabled) + pipelineKey.ShaderKey.EffectState = SHADER_NoTexture; mPipelineKey = pipelineKey; PushConstants pushConstants = {}; diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index 45a91eea5..383d62607 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -57,8 +57,8 @@ public: void ResetVertices() override; // Draw level mesh - void DrawLevelMeshDepthPass() override; - void DrawLevelMeshOpaquePass() override; + void DrawLevelMeshSurfaces(bool noFragmentShader) override; + void DrawLevelMeshPortals(bool noFragmentShader) override; int GetNextQueryIndex() override; void BeginQuery() override; void EndQuery() override; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index 4d83e9704..c97dcb646 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3693,7 +3693,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) // set up world state SpawnSpecials(); - InitLevelMesh(map); + //InitLevelMesh(map); // disable reflective planes on sloped sectors. for (auto &sec : Level->sectors) @@ -3728,7 +3728,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position) if (!Level->IsReentering()) Level->FinalizePortals(); // finalize line portals after polyobjects have been initialized. This info is needed for properly flagging them. - Level->levelMesh->CreatePortals(*Level); // [RaveYard]: needs portal data, but at the same time intializing the level mesh here breaks floor/ceiling planes! + InitLevelMesh(map); Level->aabbTree = new DoomLevelAABBTree(Level); } diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index 4368ebf32..4a1c29141 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -17,12 +17,12 @@ public: void DumpMesh(const FString& objFilename, const FString& mtlFilename) const; void BuildSectorGroups(const FLevelLocals& doomMap); - void CreatePortals(FLevelLocals& doomMap); TArray sectorGroup; // index is sector, value is sectorGroup TArray sectorPortals[2]; // index is sector+plane, value is index into the portal list TArray linePortals; // index is linedef, value is index into the portal list private: + void CreatePortals(FLevelLocals& doomMap); FLightNode* GetSurfaceLightNode(const DoomLevelMeshSurface* doomsurf); }; diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.cpp b/src/rendering/hwrenderer/doom_levelsubmesh.cpp index 0844696b7..3ff8b3cd8 100644 --- a/src/rendering/hwrenderer/doom_levelsubmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelsubmesh.cpp @@ -19,7 +19,6 @@ VSMatrix GetPlaneTextureRotationMatrix(FGameTexture* gltexture, const sector_t* sector, int plane); void GetTexCoordInfo(FGameTexture* tex, FTexCoordInfo* tci, side_t* side, int texpos); -EXTERN_CVAR(Bool, gl_texture) EXTERN_CVAR(Float, lm_scale); DoomLevelSubmesh::DoomLevelSubmesh(DoomLevelMesh* mesh, FLevelLocals& doomMap, bool staticMesh) : LevelMesh(mesh), StaticMesh(staticMesh) @@ -61,7 +60,7 @@ void DoomLevelSubmesh::Update(FLevelLocals& doomMap, int lightmapStartIndex) void DoomLevelSubmesh::Reset() { Surfaces.Clear(); - WallPortals.Clear(); + Portals.Clear(); Mesh.Vertices.Clear(); Mesh.Indexes.Clear(); Mesh.SurfaceIndexes.Clear(); @@ -113,22 +112,24 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap) // Part 1: solid geometry. This is set up so that there are no transparent parts state.SetDepthFunc(DF_LEqual); state.ClearDepthBias(); - state.EnableTexture(gl_texture); + state.EnableTexture(true); state.EnableBrightmap(true); state.AlphaFunc(Alpha_GEqual, 0.f); CreateWallSurface(side, disp, state, result.list); + for (HWWall& portal : result.portals) + { + Portals.Push(portal); + } + + CreateWallSurface(side, disp, state, result.portals, true); + // final pass: translucent stuff state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold); state.SetRenderStyle(STYLE_Translucent); CreateWallSurface(side, disp, state, result.translucent); state.AlphaFunc(Alpha_GEqual, 0.f); state.SetRenderStyle(STYLE_Normal); - - for (const HWWall& portal : result.portals) - { - WallPortals.Push(portal); - } } // Create surfaces for all flats @@ -149,7 +150,7 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap) // Part 1: solid geometry. This is set up so that there are no transparent parts state.SetDepthFunc(DF_LEqual); state.ClearDepthBias(); - state.EnableTexture(gl_texture); + state.EnableTexture(true); state.EnableBrightmap(true); CreateFlatSurface(disp, state, result.list); @@ -168,20 +169,39 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap) } } -void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray& list) +void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray& list, bool isSky) { for (HWWall& wallpart : list) { - if (wallpart.texture && wallpart.texture->isMasked()) + if (isSky) { - state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + state.SetEffect(EFF_PORTAL); + state.EnableTexture(false); + state.SetRenderStyle(STYLE_Normal); + + wallpart.MakeVertices(state, false); + wallpart.RenderWall(state, HWWall::RWF_BLANK); + wallpart.vertcount = 0; + + wallpart.LevelMeshInfo.Type = ST_UPPERSIDE; + wallpart.LevelMeshInfo.ControlSector = nullptr; + + state.SetEffect(EFF_NONE); + state.EnableTexture(true); } else { - state.AlphaFunc(Alpha_GEqual, 0.f); - } + if (wallpart.texture && wallpart.texture->isMasked()) + { + state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + } + else + { + state.AlphaFunc(Alpha_GEqual, 0.f); + } - wallpart.DrawWall(&disp, state, false); + wallpart.DrawWall(&disp, state, false); + } int pipelineID = 0; int startVertIndex = Mesh.Vertices.Size(); @@ -230,7 +250,8 @@ void DoomLevelSubmesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, M surf.Plane = ToPlane(Mesh.Vertices[startVertIndex + 3].fPos(), Mesh.Vertices[startVertIndex + 2].fPos(), Mesh.Vertices[startVertIndex + 1].fPos(), Mesh.Vertices[startVertIndex].fPos()); surf.Texture = wallpart.texture; surf.PipelineID = pipelineID; - surf.PortalIndex = (surf.Type == ST_MIDDLESIDE) ? LevelMesh->linePortals[side->linedef->Index()] : 0; + surf.PortalIndex = isSky ? LevelMesh->linePortals[side->linedef->Index()] : 0; + surf.IsSky = isSky; Surfaces.Push(surf); } } @@ -239,16 +260,30 @@ void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& st { for (HWFlat& flatpart : list) { - if (flatpart.texture && flatpart.texture->isMasked()) + if (isSky) { - state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + state.SetEffect(EFF_PORTAL); + state.EnableTexture(false); + state.SetRenderStyle(STYLE_Normal); + + flatpart.DrawSubsectors(&disp, state); + + state.SetEffect(EFF_NONE); + state.EnableTexture(true); } else { - state.AlphaFunc(Alpha_GEqual, 0.f); - } + if (flatpart.texture && flatpart.texture->isMasked()) + { + state.AlphaFunc(Alpha_GEqual, gl_mask_threshold); + } + else + { + state.AlphaFunc(Alpha_GEqual, 0.f); + } - flatpart.DrawFlat(&disp, state, false); + flatpart.DrawFlat(&disp, state, false); + } int pipelineID = 0; int uniformsIndex = 0; @@ -290,6 +325,8 @@ void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& st if (surf.ControlSector) surf.Plane = -surf.Plane; + float skyZ = flatpart.ceiling ? 32768.0f : -32768.0f; + for (subsector_t* sub : flatpart.section->subsectors) { int startVertIndex = Mesh.Vertices.Size(); @@ -301,7 +338,7 @@ void DoomLevelSubmesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& st FFlatVertex ffv; ffv.x = (float)vt->fX(); ffv.y = (float)vt->fY(); - ffv.z = (float)plane.ZatPoint(vt); + ffv.z = isSky ? skyZ : (float)plane.ZatPoint(vt); ffv.u = (float)vt->fX() / 64.f; ffv.v = -(float)vt->fY() / 64.f; ffv.lu = 0.0f; diff --git a/src/rendering/hwrenderer/doom_levelsubmesh.h b/src/rendering/hwrenderer/doom_levelsubmesh.h index 9a2f73158..d42918f44 100644 --- a/src/rendering/hwrenderer/doom_levelsubmesh.h +++ b/src/rendering/hwrenderer/doom_levelsubmesh.h @@ -49,7 +49,7 @@ public: TArray> PolyLMSurfaces; - TArray WallPortals; + TArray Portals; private: void Reset(); @@ -64,7 +64,7 @@ private: void CreateIndexes(); - void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray& list); + void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray& list, bool isSky = false); void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray& list, bool isSky = false); static FVector4 ToPlane(const FVector3& pt1, const FVector3& pt2, const FVector3& pt3) diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index d023081f8..22f91a810 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -52,6 +52,7 @@ EXTERN_CVAR(Float, r_visibility) EXTERN_CVAR(Int, lm_background_updates); EXTERN_CVAR(Float, r_actorspriteshadowdist) +EXTERN_CVAR(Bool, gl_portals) CVAR(Bool, lm_always_update, false, 0) @@ -410,20 +411,25 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) validcount++; // used for processing sidedefs only once by the renderer. - auto& wallPortals = static_cast(level.levelMesh->StaticMesh.get())->WallPortals; + auto& portals = static_cast(level.levelMesh->StaticMesh.get())->Portals; // draw level into depth buffer state.SetColorMask(false); state.SetCulling(Cull_CW); - state.DrawLevelMeshDepthPass(); + state.DrawLevelMeshSurfaces(true); + if (gl_portals) + { + state.SetDepthBias(1, 128); + state.DrawLevelMeshPortals(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_FOGBOUNDARY); - state.AlphaFunc(Alpha_GEqual, 0.f); - for (HWWall& wall : wallPortals) + state.SetEffect(EFF_PORTAL); + for (HWWall& wall : portals) { state.BeginQuery(); @@ -434,13 +440,19 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) state.EndQuery(); } state.SetEffect(EFF_NONE); - state.EnableTexture(true); + state.EnableTexture(gl_texture); 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.DrawLevelMeshSurfaces(false); + if (!gl_portals) + { + state.SetDepthBias(1, 128); + state.DrawLevelMeshPortals(false); + state.SetDepthBias(0, 0); + } state.SetCulling(Cull_None); // retrieve the query results and use them to fill the portal manager with portals @@ -450,7 +462,7 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state) bool portalVisible = QueryResultsBuffer[i]; if (portalVisible) { - PutWallPortal(wallPortals[i], state); + PutWallPortal(portals[i], state); } } @@ -524,9 +536,11 @@ void HWDrawInfo::PutWallPortal(HWWall wall, FRenderState& state) } else if (portaltype == PORTALTYPE_SECTORSTACK) { - if (screen->instack[1 - portalplane]) - return; - wall.PutPortal(&ddi, state, portaltype, portalplane); + // To do: this seems to need AddSubsectorToPortal? + + //if (screen->instack[1 - portalplane]) + // return; + //wall.PutPortal(&ddi, state, portaltype, portalplane); } else if (portaltype == PORTALTYPE_PLANEMIRROR) { diff --git a/wadsrc/static/shaders/scene/frag_portal.glsl b/wadsrc/static/shaders/scene/frag_portal.glsl new file mode 100644 index 000000000..355cf5282 --- /dev/null +++ b/wadsrc/static/shaders/scene/frag_portal.glsl @@ -0,0 +1,10 @@ + +void main() +{ + FragColor = vec4(0.0, 1.0, 0.0, 1.0); +#ifdef GBUFFER_PASS + FragFog = vec4(0.0, 0.0, 0.0, 1.0); + FragNormal = vec4(0.5, 0.5, 0.5, 1.0); +#endif +} +