diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 7cddfdec4..1aeac50ad 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -237,248 +237,6 @@ FDrawInfo *FDrawInfo::EndDrawInfo() return gl_drawinfo; } - -//========================================================================== -// -// Flood gaps with the back side's ceiling/floor texture -// This requires a stencil because the projected plane interferes with -// the depth buffer -// -//========================================================================== - -void FDrawInfo::SetupFloodStencil(wallseg * ws) -{ - int recursion = GLRenderer->mPortalState.GetRecursion(); - - // Create stencil - glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels - // Use revertible color mask, to avoid stomping on anaglyph 3D state - glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - gl_RenderState.EnableTexture(false); - gl_RenderState.ResetColor(); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - - gl_RenderState.Apply(); - FQuadDrawer qd; - qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); - qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); - qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); - qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); - qd.Render(GL_TRIANGLE_FAN); - - glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil - - glColorMask(1, 1, 1, 1); // don't write to the graphics buffer - gl_RenderState.EnableTexture(true); - glDisable(GL_DEPTH_TEST); - glDepthMask(false); -} - -void FDrawInfo::ClearFloodStencil(wallseg * ws) -{ - int recursion = GLRenderer->mPortalState.GetRecursion(); - - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); - gl_RenderState.EnableTexture(false); - // Use revertible color mask, to avoid stomping on anaglyph 3D state - glColorMask(0, 0, 0, 0); // don't write to the graphics buffer - gl_RenderState.ResetColor(); - - gl_RenderState.Apply(); - FQuadDrawer qd; - qd.Set(0, ws->x1, ws->z1, ws->y1, 0, 0); - qd.Set(1, ws->x1, ws->z2, ws->y1, 0, 0); - qd.Set(2, ws->x2, ws->z2, ws->y2, 0, 0); - qd.Set(3, ws->x2, ws->z1, ws->y2, 0, 0); - qd.Render(GL_TRIANGLE_FAN); - - // restore old stencil op. - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilFunc(GL_EQUAL, recursion, ~0); - gl_RenderState.EnableTexture(true); - glColorMask(1, 1, 1, 1); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); -} - -//========================================================================== -// -// Draw the plane segment into the gap -// -//========================================================================== -void FDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) -{ - GLSectorPlane plane; - int lightlevel; - FColormap Colormap; - FMaterial * gltexture; - - plane.GetFromSector(sec, ceiling); - - gltexture=FMaterial::ValidateTexture(plane.texture, false, true); - if (!gltexture) return; - - if (isFullbrightScene()) - { - Colormap.Clear(); - lightlevel=255; - } - else - { - Colormap = sec->Colormap; - if (gltexture->tex->isFullbright()) - { - Colormap.MakeWhite(); - lightlevel=255; - } - else lightlevel=abs(ceiling? sec->GetCeilingLight() : sec->GetFloorLight()); - } - - int rel = getExtraLight(); - SetColor(lightlevel, rel, Colormap, 1.0f); - SetFog(lightlevel, rel, &Colormap, false); - gl_RenderState.SetMaterial(gltexture, CLAMP_NONE, 0, -1, false); - - float fviewx = Viewpoint.Pos.X; - float fviewy = Viewpoint.Pos.Y; - float fviewz = Viewpoint.Pos.Z; - - gl_RenderState.SetPlaneTextureRotation(&plane, gltexture); - gl_RenderState.Apply(); - - float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); - float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); - - float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); - float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); - - float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); - float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); - - float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); - float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); - - float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); - float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); - - FQuadDrawer qd; - qd.Set(0, px1, planez, py1, px1 / 64, -py1 / 64); - qd.Set(1, px2, planez, py2, px2 / 64, -py2 / 64); - qd.Set(2, px3, planez, py3, px3 / 64, -py3 / 64); - qd.Set(3, px4, planez, py4, px4 / 64, -py4 / 64); - qd.Render(GL_TRIANGLE_FAN); - - gl_RenderState.EnableTextureMatrix(false); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FDrawInfo::FloodUpperGap(seg_t * seg) -{ - wallseg ws; - sector_t ffake, bfake; - sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); - sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); - - vertex_t * v1, * v2; - - // Although the plane can be sloped this code will only be called - // when the edge itself is not. - double backz = fakebsector->ceilingplane.ZatPoint(seg->v1); - double frontz = fakefsector->ceilingplane.ZatPoint(seg->v1); - - if (fakebsector->GetTexture(sector_t::ceiling)==skyflatnum) return; - if (backz < Viewpoint.Pos.Z) return; - - if (seg->sidedef == seg->linedef->sidedef[0]) - { - v1=seg->linedef->v1; - v2=seg->linedef->v2; - } - else - { - v1=seg->linedef->v2; - v2=seg->linedef->v1; - } - - ws.x1 = v1->fX(); - ws.y1 = v1->fY(); - ws.x2 = v2->fX(); - ws.y2 = v2->fY(); - - ws.z1= frontz; - ws.z2= backz; - - // Step1: Draw a stencil into the gap - SetupFloodStencil(&ws); - - // Step2: Project the ceiling plane into the gap - DrawFloodedPlane(&ws, ws.z2, fakebsector, true); - - // Step3: Delete the stencil - ClearFloodStencil(&ws); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FDrawInfo::FloodLowerGap(seg_t * seg) -{ - wallseg ws; - sector_t ffake, bfake; - sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); - sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); - - vertex_t * v1, * v2; - - // Although the plane can be sloped this code will only be called - // when the edge itself is not. - double backz = fakebsector->floorplane.ZatPoint(seg->v1); - double frontz = fakefsector->floorplane.ZatPoint(seg->v1); - - - if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return; - if (fakebsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) return; - - if (seg->sidedef == seg->linedef->sidedef[0]) - { - v1=seg->linedef->v1; - v2=seg->linedef->v2; - } - else - { - v1=seg->linedef->v2; - v2=seg->linedef->v1; - } - - ws.x1 = v1->fX(); - ws.y1 = v1->fY(); - ws.x2 = v2->fX(); - ws.y2 = v2->fY(); - - ws.z2= frontz; - ws.z1= backz; - - // Step1: Draw a stencil into the gap - SetupFloodStencil(&ws); - - // Step2: Project the ceiling plane into the gap - DrawFloodedPlane(&ws, ws.z1, fakebsector, false); - - // Step3: Delete the stencil - ClearFloodStencil(&ws); -} - // Same here for the dependency on the portal. void FDrawInfo::AddSubsectorToPortal(FSectorPortalGroup *ptg, subsector_t *sub) { diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index 7f0c8371d..227e851ef 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -57,11 +57,11 @@ struct FDrawInfo : public HWDrawInfo void DrawDecalsForMirror(GLWall *wall); void StartScene(); - void SetupFloodStencil(wallseg * ws); - void ClearFloodStencil(wallseg * ws); + void SetupFloodStencil(int vindex); + void ClearFloodStencil(int vindex); void DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling); - void FloodUpperGap(seg_t * seg) override; - void FloodLowerGap(seg_t * seg) override; + void FloodUpperGap(seg_t * seg); + void FloodLowerGap(seg_t * seg); // Wall drawer void RenderWall(GLWall *wall, int textured); @@ -75,7 +75,6 @@ struct FDrawInfo : public HWDrawInfo void DrawFlat(GLFlat *flat, int pass, bool trans) override; // trans only has meaning for GLPASS_LIGHTSONLY void DrawSkyboxSector(GLFlat *flat, int pass); void DrawSubsectors(GLFlat *flat, int pass, bool istrans); - void DrawSubsector(GLFlat *flat, subsector_t * sub); // Sprite drawer void DrawSprite(GLSprite *sprite, int pass); @@ -100,18 +99,6 @@ struct FDrawInfo : public HWDrawInfo static FDrawInfo *StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms); FDrawInfo *EndDrawInfo(); - gl_subsectorrendernode * GetOtherFloorPlanes(unsigned int sector) - { - if (sectormVBO->GetBuffer(); - for (unsigned int k = 0; k < sub->numlines; k++) - { - vertex_t *vt = sub->firstline[k].v1; - ptr->x = vt->fX(); - ptr->z = flat->plane.plane.ZatPoint(vt) + flat->dz; - ptr->y = vt->fY(); - ptr->u = vt->fX() / 64.f; - ptr->v = -vt->fY() / 64.f; - ptr++; - } - GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN); - } - else - { - // if we cannot access the buffer, use the quad drawer as fallback by splitting the subsector into quads. - // Trying to get this into the vertex buffer in the processing pass is too costly and this is only used for render hacks. - FQuadDrawer qd; - unsigned int vi[4]; - - vi[0] = 0; - for (unsigned int i = 0; i < sub->numlines - 2; i += 2) - { - for (unsigned int j = 1; j < 4; j++) - { - vi[j] = MIN(i + j, sub->numlines - 1); - } - for (unsigned int x = 0; x < 4; x++) - { - vertex_t *vt = sub->firstline[vi[x]].v1; - qd.Set(x, vt->fX(), flat->plane.plane.ZatPoint(vt) + flat->dz, vt->fY(), vt->fX() / 64.f, -vt->fY() / 64.f); - } - qd.Render(GL_TRIANGLE_FAN); - } - } - - flatvertices += sub->numlines; - flatprimitives++; -} //========================================================================== @@ -146,9 +97,9 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) } } - // Draw the subsectors assigned to it due to missing textures if (!(flat->renderflags&SSRF_RENDER3DPLANES)) { + // Draw the subsectors assigned to it due to missing textures gl_subsectorrendernode * node = (flat->renderflags&SSRF_RENDERFLOOR)? GetOtherFloorPlanes(flat->sector->sectornum) : GetOtherCeilingPlanes(flat->sector->sectornum); @@ -156,12 +107,99 @@ void FDrawInfo::DrawSubsectors(GLFlat *flat, int pass, bool istrans) while (node) { gl_RenderState.ApplyLightIndex(node->lightindex); - DrawSubsector(flat, node->sub); + auto num = node->sub->numlines; + flatvertices += num; + flatprimitives++; + glDrawArrays(GL_TRIANGLE_FAN, node->vertexindex, num); node = node->next; } + // Flood gaps with the back side's ceiling/floor texture + // This requires a stencil because the projected plane interferes with + // the depth buffer + gl_floodrendernode * fnode = (flat->renderflags&SSRF_RENDERFLOOR) ? + GetFloodFloorSegs(flat->sector->sectornum) : + GetFloodCeilingSegs(flat->sector->sectornum); + + gl_RenderState.ApplyLightIndex(flat->dynlightindex); + while (fnode) + { + flatvertices += 12; + flatprimitives+=3; + + // Push bleeding floor/ceiling textures back a little in the z-buffer + // so they don't interfere with overlapping mid textures. + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(1.0f, 128.0f); + + SetupFloodStencil(fnode->vertexindex); + glDrawArrays(GL_TRIANGLE_FAN, fnode->vertexindex + 4, 4); + ClearFloodStencil(fnode->vertexindex); + + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + + fnode = fnode->next; + } + } } +//========================================================================== +// +// +//========================================================================== + +void FDrawInfo::SetupFloodStencil(int vindex) +{ + int recursion = GLRenderer->mPortalState.GetRecursion(); + + // Create stencil + gl_RenderState.SetEffect(EFF_STENCIL); + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + + glStencilFunc(GL_EQUAL, recursion, ~0); // create stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // increment stencil of valid pixels + + glColorMask(0, 0, 0, 0); // don't write to the graphics buffer + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + + glDrawArrays(GL_TRIANGLE_FAN, vindex, 4); + + glStencilFunc(GL_EQUAL, recursion + 1, ~0); // draw sky into stencil + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // this stage doesn't modify the stencil + + glColorMask(1, 1, 1, 1); // don't write to the graphics buffer + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + gl_RenderState.EnableTexture(true); + gl_RenderState.SetEffect(EFF_NONE); + gl_RenderState.Apply(); +} + +void FDrawInfo::ClearFloodStencil(int vindex) +{ + int recursion = GLRenderer->mPortalState.GetRecursion(); + + gl_RenderState.SetEffect(EFF_STENCIL); + gl_RenderState.EnableTexture(false); + gl_RenderState.Apply(); + glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); + // Use revertible color mask, to avoid stomping on anaglyph 3D state + glColorMask(0, 0, 0, 0); // don't write to the graphics buffer + + glDrawArrays(GL_TRIANGLE_FAN, vindex, 4); + + // restore old stencil op. + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, recursion, ~0); + glColorMask(1, 1, 1, 1); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + gl_RenderState.EnableTexture(true); + gl_RenderState.SetEffect(EFF_NONE); +} //========================================================================== // diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index c643a7318..8053a0b4e 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -128,6 +128,7 @@ void FDrawInfo::CreateScene() HandleMissingTextures(in_area); // Missing upper/lower textures HandleHackedSubsectors(); // open sector hacks for deep water ProcessSectorStacks(in_area); // merge visplanes of sector stacks + PrepareUnhandledMissingTextures(); GLRenderer->mLights->Finish(); GLRenderer->mVBO->Unmap(); @@ -208,28 +209,10 @@ void FDrawInfo::RenderScene(int recursion) DrawDecals(); gl_RenderState.SetTextureMode(TM_MODULATE); - - glDepthMask(true); - - - // Push bleeding floor/ceiling textures back a little in the z-buffer - // so they don't interfere with overlapping mid textures. - glPolygonOffset(1.0f, 128.0f); - - // Part 5: flood all the gaps with the back sector's flat texture - // This will always be drawn like GLDL_PLAIN, depending on the fog settings - - glDepthMask(false); // don't write to Z-buffer! - gl_RenderState.EnableFog(true); - gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); - gl_RenderState.BlendFunc(GL_ONE,GL_ZERO); - DrawUnhandledMissingTextures(); - glDepthMask(true); - glPolygonOffset(0.0f, 0.0f); glDisable(GL_POLYGON_OFFSET_FILL); + glDepthMask(true); RenderAll.Unclock(); - } //----------------------------------------------------------------------------- diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index c72f510ae..05f5830a1 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -47,32 +47,31 @@ sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac // //========================================================================== +template +inline void DeleteLinkedList(T *node) +{ + while (node) + { + auto n = node; + node = node->next; + delete n; + } +} + void HWDrawInfo::ClearBuffers() { - for(unsigned int i=0;i< otherfloorplanes.Size();i++) - { - gl_subsectorrendernode * node = otherfloorplanes[i]; - while (node) - { - gl_subsectorrendernode * n = node; - node = node->next; - delete n; - } - } + for (auto node : otherfloorplanes) DeleteLinkedList(node); otherfloorplanes.Clear(); - for(unsigned int i=0;i< otherceilingplanes.Size();i++) - { - gl_subsectorrendernode * node = otherceilingplanes[i]; - while (node) - { - gl_subsectorrendernode * n = node; - node = node->next; - delete n; - } - } + for (auto node : otherceilingplanes) DeleteLinkedList(node); otherceilingplanes.Clear(); + for (auto node : floodfloorsegs) DeleteLinkedList(node); + floodfloorsegs.Clear(); + + for (auto node : floodceilingsegs) DeleteLinkedList(node); + floodceilingsegs.Clear(); + // clear all the lists that might not have been cleared already MissingUpperTextures.Clear(); MissingLowerTextures.Clear(); diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 57434d952..37999e80c 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -35,6 +35,15 @@ struct gl_subsectorrendernode gl_subsectorrendernode * next; subsector_t * sub; int lightindex; + int vertexindex; +}; + +struct gl_floodrendernode +{ + gl_floodrendernode * next; + seg_t *seg; + int vertexindex; + // This will use the light list of the originating sector. }; enum area_t : int; @@ -123,6 +132,8 @@ struct HWDrawInfo TArray otherfloorplanes; TArray otherceilingplanes; + TArray floodfloorsegs; + TArray floodceilingsegs; TArray CeilingStacks; TArray FloorStacks; @@ -162,8 +173,35 @@ private: void RenderThings(subsector_t * sub, sector_t * sector); void DoSubsector(subsector_t * sub); int SetupLightsForOtherPlane(subsector_t * sub, FDynLightData &lightdata, const secplane_t *plane); + int CreateOtherPlaneVertices(subsector_t *sub, const secplane_t *plane); public: + gl_subsectorrendernode * GetOtherFloorPlanes(unsigned int sector) + { + if (sector &lowersegs); virtual void AddSubsectorToPortal(FSectorPortalGroup *portal, subsector_t *sub) = 0; diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index e918ec286..d9de834af 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -35,6 +35,7 @@ #include "hw_drawstructs.h" #include "hwrenderer/utility/hw_clock.h" #include "hwrenderer/dynlights/hw_dynlightdata.h" +#include "hwrenderer/data/flatvertices.h" sector_t * hw_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back); @@ -75,6 +76,29 @@ int HWDrawInfo::SetupLightsForOtherPlane(subsector_t * sub, FDynLightData &light else return -1; } +//========================================================================== +// +// Vertex setup for extra planes +// +//========================================================================== + +int HWDrawInfo::CreateOtherPlaneVertices(subsector_t *sub, const secplane_t *plane) +{ + auto alloc = AllocVertices(sub->numlines); + auto ptr = alloc.first; + for (unsigned int k = 0; k < sub->numlines; k++) + { + vertex_t *vt = sub->firstline[k].v1; + ptr->x = vt->fX(); + ptr->z = plane->ZatPoint(vt); + ptr->y = vt->fY(); + ptr->u = vt->fX() / 64.f; + ptr->v = -vt->fY() / 64.f; + ptr++; + } + return alloc.second; +} + //========================================================================== // // Adds a subsector plane to a sector's render list @@ -85,13 +109,14 @@ void HWDrawInfo::AddOtherFloorPlane(int sector, gl_subsectorrendernode * node) { int oldcnt = otherfloorplanes.Size(); - if (oldcnt<=sector) + if (oldcnt <= sector) { - otherfloorplanes.Resize(sector+1); - for(int i=oldcnt;i<=sector;i++) otherfloorplanes[i]=NULL; + otherfloorplanes.Resize(sector + 1); + for (int i = oldcnt; i <= sector; i++) otherfloorplanes[i] = nullptr; } node->next = otherfloorplanes[sector]; - node->lightindex = SetupLightsForOtherPlane(node->sub, lightdata, &node->sub->sector->floorplane); + node->lightindex = SetupLightsForOtherPlane(node->sub, lightdata, &level.sectors[sector].floorplane); + node->vertexindex = CreateOtherPlaneVertices(node->sub, &level.sectors[sector].floorplane); otherfloorplanes[sector] = node; } @@ -99,13 +124,14 @@ void HWDrawInfo::AddOtherCeilingPlane(int sector, gl_subsectorrendernode * node) { int oldcnt = otherceilingplanes.Size(); - if (oldcnt<=sector) + if (oldcnt <= sector) { - otherceilingplanes.Resize(sector+1); - for(int i=oldcnt;i<=sector;i++) otherceilingplanes[i]=NULL; + otherceilingplanes.Resize(sector + 1); + for (int i = oldcnt; i <= sector; i++) otherceilingplanes[i] = nullptr; } node->next = otherceilingplanes[sector]; - node->lightindex = SetupLightsForOtherPlane(node->sub, lightdata, &node->sub->sector->ceilingplane); + node->lightindex = SetupLightsForOtherPlane(node->sub, lightdata, &level.sectors[sector].ceilingplane); + node->vertexindex = CreateOtherPlaneVertices(node->sub, &level.sectors[sector].ceilingplane); otherceilingplanes[sector] = node; } @@ -607,54 +633,229 @@ void HWDrawInfo::HandleMissingTextures(area_t in_area) } } - //========================================================================== // // // //========================================================================== -void HWDrawInfo::DrawUnhandledMissingTextures() +void HWDrawInfo::CreateFloodStencilPoly(wallseg * ws, FFlatVertex *vertices) { - validcount++; - for (int i = MissingUpperSegs.Size() - 1; i >= 0; i--) + vertices[0].Set(ws->x1, ws->z1, ws->y1, 0, 0); + vertices[1].Set(ws->x1, ws->z2, ws->y1, 0, 0); + vertices[2].Set(ws->x2, ws->z2, ws->y2, 0, 0); + vertices[3].Set(ws->x2, ws->z1, ws->y2, 0, 0); +} + +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::CreateFloodPoly(wallseg * ws, FFlatVertex *vertices, float planez, sector_t * sec, bool ceiling) +{ + float fviewx = Viewpoint.Pos.X; + float fviewy = Viewpoint.Pos.Y; + float fviewz = Viewpoint.Pos.Z; + + float prj_fac1 = (planez - fviewz) / (ws->z1 - fviewz); + float prj_fac2 = (planez - fviewz) / (ws->z2 - fviewz); + + float px1 = fviewx + prj_fac1 * (ws->x1 - fviewx); + float py1 = fviewy + prj_fac1 * (ws->y1 - fviewy); + + float px2 = fviewx + prj_fac2 * (ws->x1 - fviewx); + float py2 = fviewy + prj_fac2 * (ws->y1 - fviewy); + + float px3 = fviewx + prj_fac2 * (ws->x2 - fviewx); + float py3 = fviewy + prj_fac2 * (ws->y2 - fviewy); + + float px4 = fviewx + prj_fac1 * (ws->x2 - fviewx); + float py4 = fviewy + prj_fac1 * (ws->y2 - fviewy); + + vertices[0].Set(px1, planez, py1, px1 / 64, -py1 / 64); + vertices[1].Set(px2, planez, py2, px2 / 64, -py2 / 64); + vertices[2].Set(px3, planez, py3, px3 / 64, -py3 / 64); + vertices[3].Set(px4, planez, py4, px4 / 64, -py4 / 64); +} + +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::PrepareUpperGap(seg_t * seg) +{ + wallseg ws; + sector_t ffake, bfake; + sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); + sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); + + vertex_t * v1, *v2; + + // Although the plane can be sloped this code will only be called + // when the edge itself is not. + double backz = fakebsector->ceilingplane.ZatPoint(seg->v1); + double frontz = fakefsector->ceilingplane.ZatPoint(seg->v1); + + if (fakebsector->GetTexture(sector_t::ceiling) == skyflatnum) return; + if (backz < Viewpoint.Pos.Z) return; + + if (seg->sidedef == seg->linedef->sidedef[0]) { - int index = MissingUpperSegs[i].MTI_Index; - if (index >= 0 && MissingUpperTextures[index].seg == NULL) continue; - - seg_t * seg = MissingUpperSegs[i].seg; - - // already done! - if (seg->linedef->validcount == validcount) continue; // already done - seg->linedef->validcount = validcount; - if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < Viewpoint.Pos.Z) continue; // out of sight - - // FIXME: The check for degenerate subsectors should be more precise - if (seg->PartnerSeg && (seg->PartnerSeg->Subsector->flags & SSECF_DEGENERATE)) continue; - if (seg->backsector->transdoor) continue; - if (seg->backsector->GetTexture(sector_t::ceiling) == skyflatnum) continue; - if (seg->backsector->ValidatePortal(sector_t::ceiling) != NULL) continue; - - if (!level.notexturefill) FloodUpperGap(seg); + v1 = seg->linedef->v1; + v2 = seg->linedef->v2; + } + else + { + v1 = seg->linedef->v2; + v2 = seg->linedef->v1; } - validcount++; - for (int i = MissingLowerSegs.Size() - 1; i >= 0; i--) + ws.x1 = v1->fX(); + ws.y1 = v1->fY(); + ws.x2 = v2->fX(); + ws.y2 = v2->fY(); + + ws.z1 = frontz; + ws.z2 = backz; + + auto vertices = AllocVertices(8); + + CreateFloodStencilPoly(&ws, vertices.first); + CreateFloodPoly(&ws, vertices.first+4, ws.z2, fakebsector, true); + + gl_floodrendernode *node = new gl_floodrendernode; + int oldcnt = floodfloorsegs.Size(); + auto sector = fakebsector->sectornum; + if (oldcnt <= sector) { - int index = MissingLowerSegs[i].MTI_Index; - if (index >= 0 && MissingLowerTextures[index].seg == NULL) continue; + floodfloorsegs.Resize(sector + 1); + for (int i = oldcnt; i <= sector; i++) floodfloorsegs[i] = nullptr; + } - seg_t * seg = MissingLowerSegs[i].seg; + node->next = floodfloorsegs[sector]; + node->seg = seg; + node->vertexindex = vertices.second; + floodfloorsegs[sector] = node; +} - if (seg->linedef->validcount == validcount) continue; // already done - seg->linedef->validcount = validcount; - if (!(sectorrenderflags[seg->backsector->sectornum] & SSRF_RENDERFLOOR)) continue; - if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) continue; // out of sight - if (seg->backsector->transdoor) continue; - if (seg->backsector->GetTexture(sector_t::floor) == skyflatnum) continue; - if (seg->backsector->ValidatePortal(sector_t::floor) != NULL) continue; - if (!level.notexturefill) FloodLowerGap(seg); +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::PrepareLowerGap(seg_t * seg) +{ + wallseg ws; + sector_t ffake, bfake; + sector_t * fakefsector = hw_FakeFlat(seg->frontsector, &ffake, in_area, true); + sector_t * fakebsector = hw_FakeFlat(seg->backsector, &bfake, in_area, false); + + vertex_t * v1, *v2; + + // Although the plane can be sloped this code will only be called + // when the edge itself is not. + double backz = fakebsector->floorplane.ZatPoint(seg->v1); + double frontz = fakefsector->floorplane.ZatPoint(seg->v1); + + + if (fakebsector->GetTexture(sector_t::floor) == skyflatnum) return; + if (fakebsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) return; + + if (seg->sidedef == seg->linedef->sidedef[0]) + { + v1 = seg->linedef->v1; + v2 = seg->linedef->v2; + } + else + { + v1 = seg->linedef->v2; + v2 = seg->linedef->v1; + } + + ws.x1 = v1->fX(); + ws.y1 = v1->fY(); + ws.x2 = v2->fX(); + ws.y2 = v2->fY(); + + ws.z2 = frontz; + ws.z1 = backz; + + auto vertices = AllocVertices(8); + + CreateFloodStencilPoly(&ws, vertices.first); + CreateFloodPoly(&ws, vertices.first+4, ws.z1, fakebsector, false); + + gl_floodrendernode *node = new gl_floodrendernode; + int oldcnt = floodceilingsegs.Size(); + auto sector = fakebsector->sectornum; + if (oldcnt <= sector) + { + floodceilingsegs.Resize(sector + 1); + for (int i = oldcnt; i <= sector; i++) floodceilingsegs[i] = nullptr; + } + + node->next = floodceilingsegs[sector]; + node->seg = seg; + node->vertexindex = vertices.second; + floodceilingsegs[sector] = node; +} + +//========================================================================== +// +// +// +//========================================================================== + +void HWDrawInfo::PrepareUnhandledMissingTextures() +{ + if (!level.notexturefill) + { + validcount++; + for (int i = MissingUpperSegs.Size() - 1; i >= 0; i--) + { + int index = MissingUpperSegs[i].MTI_Index; + if (index >= 0 && MissingUpperTextures[index].seg == NULL) continue; + + seg_t * seg = MissingUpperSegs[i].seg; + + // already done! + if (seg->linedef->validcount == validcount) continue; // already done + seg->linedef->validcount = validcount; + if (seg->frontsector->GetPlaneTexZ(sector_t::ceiling) < Viewpoint.Pos.Z) continue; // out of sight + + // FIXME: The check for degenerate subsectors should be more precise + if (seg->PartnerSeg && (seg->PartnerSeg->Subsector->flags & SSECF_DEGENERATE)) continue; + if (seg->backsector->transdoor) continue; + if (seg->backsector->GetTexture(sector_t::ceiling) == skyflatnum) continue; + if (seg->backsector->ValidatePortal(sector_t::ceiling) != NULL) continue; + + PrepareUpperGap(seg); + } + + validcount++; + for (int i = MissingLowerSegs.Size() - 1; i >= 0; i--) + { + int index = MissingLowerSegs[i].MTI_Index; + if (index >= 0 && MissingLowerTextures[index].seg == NULL) continue; + + seg_t * seg = MissingLowerSegs[i].seg; + + if (seg->linedef->validcount == validcount) continue; // already done + seg->linedef->validcount = validcount; + if (!(sectorrenderflags[seg->backsector->sectornum] & SSRF_RENDERFLOOR)) continue; + if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > Viewpoint.Pos.Z) continue; // out of sight + if (seg->backsector->transdoor) continue; + if (seg->backsector->GetTexture(sector_t::floor) == skyflatnum) continue; + if (seg->backsector->ValidatePortal(sector_t::floor) != NULL) continue; + + PrepareLowerGap(seg); + } } MissingUpperTextures.Clear(); MissingLowerTextures.Clear();