From b1d8f92ded247e8234c30cc42170ba11694b97e5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 28 Dec 2021 19:33:27 +0100 Subject: [PATCH] - added wall edge splitting for gl_seamless. --- source/CMakeLists.txt | 1 + source/core/maploader.cpp | 12 +- source/core/rendering/hw_vertexmap.cpp | 11 +- source/core/rendering/scene/hw_drawstructs.h | 6 +- source/core/rendering/scene/hw_walls.cpp | 36 ---- .../core/rendering/scene/hw_walls_vertex.cpp | 204 ++++++++++++++++++ source/games/blood/src/db.cpp | 4 +- 7 files changed, 226 insertions(+), 48 deletions(-) create mode 100644 source/core/rendering/scene/hw_walls_vertex.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index af871009a..06a4fa8d0 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1062,6 +1062,7 @@ set (PCH_SOURCES core/rendering/hw_vertexmap.cpp core/rendering/scene/hw_clipper.cpp core/rendering/scene/hw_walls.cpp + core/rendering/scene/hw_walls_vertex.cpp core/rendering/scene/hw_flats.cpp core/rendering/scene/hw_sprites.cpp core/rendering/scene/hw_drawlistadd.cpp diff --git a/source/core/maploader.cpp b/source/core/maploader.cpp index 49dc953b3..602775168 100644 --- a/source/core/maploader.cpp +++ b/source/core/maploader.cpp @@ -98,8 +98,8 @@ static void ReadSectorV7(FileReader& fr, sectortype& sect) { sect.wallptr = fr.ReadInt16(); sect.wallnum = fr.ReadInt16(); - sect.setceilingz(fr.ReadInt32()); - sect.setfloorz(fr.ReadInt32()); + sect.setceilingz(fr.ReadInt32(), true); + sect.setfloorz(fr.ReadInt32(), true); sect.ceilingstat = ESectorFlags::FromInt(fr.ReadUInt16()); sect.floorstat = ESectorFlags::FromInt(fr.ReadUInt16()); sect.ceilingpicnum = fr.ReadUInt16(); @@ -129,8 +129,8 @@ static void ReadSectorV6(FileReader& fr, sectortype& sect) sect.floorpicnum = fr.ReadUInt16(); sect.ceilingheinum = clamp(fr.ReadInt16() << 5, -32768, 32767); sect.floorheinum = clamp(fr.ReadInt16() << 5, -32768, 32767); - sect.setceilingz(fr.ReadInt32()); - sect.setfloorz(fr.ReadInt32()); + sect.setceilingz(fr.ReadInt32(), true); + sect.setfloorz(fr.ReadInt32(), true); sect.ceilingshade = fr.ReadInt8(); sect.floorshade = fr.ReadInt8(); sect.ceilingxpan_ = fr.ReadUInt8(); @@ -156,8 +156,8 @@ static void ReadSectorV5(FileReader& fr, sectortype& sect) sect.floorpicnum = fr.ReadUInt16(); sect.ceilingheinum = clamp(fr.ReadInt16() << 5, -32768, 32767); sect.floorheinum = clamp(fr.ReadInt16() << 5, -32768, 32767); - sect.setceilingz(fr.ReadInt32()); - sect.setfloorz(fr.ReadInt32()); + sect.setceilingz(fr.ReadInt32(), true); + sect.setfloorz(fr.ReadInt32(), true); sect.ceilingshade = fr.ReadInt8(); sect.floorshade = fr.ReadInt8(); sect.ceilingxpan_ = fr.ReadUInt8(); diff --git a/source/core/rendering/hw_vertexmap.cpp b/source/core/rendering/hw_vertexmap.cpp index 71c355f68..3f1932078 100644 --- a/source/core/rendering/hw_vertexmap.cpp +++ b/source/core/rendering/hw_vertexmap.cpp @@ -33,13 +33,12 @@ ** */ -#include "basics.h" #include "maptypes.h" #include "memarena.h" #include "gamefuncs.h" #include "hw_vertexmap.h" -extern FMemArena sectionArena; // allocate from the same arena as the section as the data here has the same lifetime. +extern FMemArena sectionArena; // allocate from the same arena as the sections as the data here has the same lifetime. TArray vertexMap; // maps walls to the vertex data. TArray vertices; @@ -59,6 +58,7 @@ void CreateVertexMap() verticespersector.Resize(sector.Size()); for (auto& c : countpersector) c = 0; + for (auto& c : vertexMap) c = -1; for (unsigned i = 0; i < wall.Size(); i++) { if (processed[i]) continue; @@ -78,7 +78,7 @@ void CreateVertexMap() } }); - vertices.Reserve(1); + unsigned index = vertices.Reserve(1); auto newvert = &vertices.Last(); newvert->masterwall = walls[0]; @@ -87,6 +87,11 @@ void CreateVertexMap() newvert->dirty = true; newvert->numheights = 0; + for (auto w : walls) + { + vertexMap[w] = index; + } + // allocate all data within this struct from the arena to simplify memory management. auto sect = (int*)sectionArena.Alloc(sectors.Size() * sizeof(int)); newvert->sectors.Set(sect, sectors.Size()); diff --git a/source/core/rendering/scene/hw_drawstructs.h b/source/core/rendering/scene/hw_drawstructs.h index b69438a31..5cacb9e07 100644 --- a/source/core/rendering/scene/hw_drawstructs.h +++ b/source/core/rendering/scene/hw_drawstructs.h @@ -223,7 +223,11 @@ public: int CreateVertices(FFlatVertex *&ptr, bool nosplit); - //int CountVertices(); + int CountVertices(); + void SplitLeftEdge(FFlatVertex*& ptr); + void SplitRightEdge(FFlatVertex*& ptr); + void CountLeftEdge(unsigned& ptr); + void CountRightEdge(unsigned& ptr); void RenderWall(HWDrawInfo *di, FRenderState &state, int textured); void RenderFogBoundary(HWDrawInfo *di, FRenderState &state); diff --git a/source/core/rendering/scene/hw_walls.cpp b/source/core/rendering/scene/hw_walls.cpp index ade1c901c..3cf51cd88 100644 --- a/source/core/rendering/scene/hw_walls.cpp +++ b/source/core/rendering/scene/hw_walls.cpp @@ -133,42 +133,6 @@ static int IsOnWall(tspritetype* tspr, int height) return closest == nullptr? -1 : dist; } -//========================================================================== -// -// Create vertices for one wall -// -//========================================================================== - -int HWWall::CreateVertices(FFlatVertex*& ptr, bool split) -{ - auto oo = ptr; - ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v); - ptr++; - ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v); - ptr++; - ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v); - ptr++; - ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v); - ptr++; - return int(ptr - oo); -} - -//========================================================================== -// -// build the vertices for this wall -// -//========================================================================== - -void HWWall::MakeVertices(HWDrawInfo* di, bool nosplit) -{ - if (vertcount == 0) - { - auto ret = screen->mVertexData->AllocVertices(4); - vertindex = ret.second; - vertcount = CreateVertices(ret.first, false); - } -} - //========================================================================== // // General purpose wall rendering function diff --git a/source/core/rendering/scene/hw_walls_vertex.cpp b/source/core/rendering/scene/hw_walls_vertex.cpp new file mode 100644 index 000000000..fe35c7c13 --- /dev/null +++ b/source/core/rendering/scene/hw_walls_vertex.cpp @@ -0,0 +1,204 @@ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2006-2022 Christoph Oelckers +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "basics.h" +#include "maptypes.h" +#include "memarena.h" +#include "gamefuncs.h" +#include "v_video.h" +#include "flatvertices.h" +#include "hw_vertexmap.h" +#include "hw_drawstructs.h" + + +EXTERN_CVAR(Bool, gl_seamless) + +//========================================================================== +// +// Split left edge of wall +// +//========================================================================== + +void HWWall::SplitLeftEdge(FFlatVertex *&ptr) +{ + if (seg == nullptr) return; + vertex_t* vi = &vertices[vertexMap[wallnum(seg)]]; + + if (vi->numheights) + { + int i = 0; + + float polyh1 = ztop[0] - zbottom[0]; + float factv1 = polyh1 ? (tcs[UPLFT].v - tcs[LOLFT].v) / polyh1 : 0; + float factu1 = polyh1 ? (tcs[UPLFT].u - tcs[LOLFT].u) / polyh1 : 0; + + while (inumheights && vi->heightlist[i] <= zbottom[0]) i++; + while (inumheights && vi->heightlist[i] < ztop[0]) + { + ptr->x = glseg.x1; + ptr->y = glseg.y1; + ptr->z = vi->heightlist[i]; + ptr->u = factu1*(vi->heightlist[i] - ztop[0]) + tcs[UPLFT].u; + ptr->v = factv1*(vi->heightlist[i] - ztop[0]) + tcs[UPLFT].v; + ptr++; + i++; + } + } +} + +//========================================================================== +// +// Split right edge of wall +// +//========================================================================== + +void HWWall::SplitRightEdge(FFlatVertex *&ptr) +{ + if (seg == nullptr) return; + vertex_t* vi = &vertices[vertexMap[seg->point2]]; + + if (vi->numheights) + { + int i = vi->numheights - 1; + + float polyh2 = ztop[1] - zbottom[1]; + float factv2 = polyh2 ? (tcs[UPRGT].v - tcs[LORGT].v) / polyh2 : 0; + float factu2 = polyh2 ? (tcs[UPRGT].u - tcs[LORGT].u) / polyh2 : 0; + + while (i>0 && vi->heightlist[i] >= ztop[1]) i--; + while (i>0 && vi->heightlist[i] > zbottom[1]) + { + ptr->x = glseg.x2; + ptr->y = glseg.y2; + ptr->z = vi->heightlist[i]; + ptr->u = factu2*(vi->heightlist[i] - ztop[1]) + tcs[UPRGT].u; + ptr->v = factv2*(vi->heightlist[i] - ztop[1]) + tcs[UPRGT].v; + ptr++; + i--; + } + } +} + +//========================================================================== +// +// Create vertices for one wall +// +//========================================================================== + +int HWWall::CreateVertices(FFlatVertex *&ptr, bool split) +{ + auto oo = ptr; + ptr->Set(glseg.x1, zbottom[0], glseg.y1, tcs[LOLFT].u, tcs[LOLFT].v); + ptr++; + if (split && glseg.fracleft == 0) SplitLeftEdge(ptr); + ptr->Set(glseg.x1, ztop[0], glseg.y1, tcs[UPLFT].u, tcs[UPLFT].v); + ptr++; + ptr->Set(glseg.x2, ztop[1], glseg.y2, tcs[UPRGT].u, tcs[UPRGT].v); + ptr++; + if (split && glseg.fracright == 1) SplitRightEdge(ptr); + ptr->Set(glseg.x2, zbottom[1], glseg.y2, tcs[LORGT].u, tcs[LORGT].v); + ptr++; + return int(ptr - oo); +} + + +//========================================================================== +// +// Split left edge of wall +// +//========================================================================== + +void HWWall::CountLeftEdge(unsigned &ptr) +{ + vertex_t* vi = &vertices[vertexMap[wallnum(seg)]]; + + if (vi->numheights) + { + int i = 0; + + while (inumheights && vi->heightlist[i] <= zbottom[0]) i++; + while (inumheights && vi->heightlist[i] < ztop[0]) + { + ptr++; + i++; + } + } +} + +//========================================================================== +// +// Split right edge of wall +// +//========================================================================== + +void HWWall::CountRightEdge(unsigned &ptr) +{ + vertex_t* vi = &vertices[vertexMap[seg->point2]]; + + if (vi->numheights) + { + int i = vi->numheights - 1; + + while (i>0 && vi->heightlist[i] >= ztop[1]) i--; + while (i>0 && vi->heightlist[i] > zbottom[1]) + { + ptr++; + i--; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int HWWall::CountVertices() +{ + unsigned ptr = 4; + if (seg) + { + if (glseg.fracleft == 0) CountLeftEdge(ptr); + if (glseg.fracright == 1) CountRightEdge(ptr); + } + return (int)ptr; +} + +//========================================================================== +// +// build the vertices for this wall +// +//========================================================================== + +void HWWall::MakeVertices(HWDrawInfo *di, bool nosplit) +{ + if (vertcount == 0) + { + bool split = (gl_seamless && !nosplit && seg != nullptr); + auto ret = screen->mVertexData->AllocVertices(split ? CountVertices() : 4); + vertindex = ret.second; + vertcount = CreateVertices(ret.first, split); + } +} + + diff --git a/source/games/blood/src/db.cpp b/source/games/blood/src/db.cpp index be8365f76..dee84f8ca 100644 --- a/source/games/blood/src/db.cpp +++ b/source/games/blood/src/db.cpp @@ -253,8 +253,8 @@ void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sect } pSector->wallptr = LittleShort(load.wallptr); pSector->wallnum = LittleShort(load.wallnum); - pSector->setceilingz(LittleLong(load.ceilingz)); - pSector->setfloorz(LittleLong(load.floorz)); + pSector->setceilingz(LittleLong(load.ceilingz), true); + pSector->setfloorz(LittleLong(load.floorz), true); pSector->ceilingstat = ESectorFlags::FromInt(LittleShort(load.ceilingstat)); pSector->floorstat = ESectorFlags::FromInt(LittleShort(load.floorstat)); pSector->ceilingpicnum = LittleShort(load.ceilingpicnum);