diff --git a/src/actor.h b/src/actor.h index d87c51e98a..6974107113 100644 --- a/src/actor.h +++ b/src/actor.h @@ -53,6 +53,7 @@ struct FBlockNode; struct FPortalGroupArray; struct visstyle_t; class FLightDefaults; +struct FSection; // // NOTES: AActor // diff --git a/src/hwrenderer/data/hw_sections.cpp b/src/hwrenderer/data/hw_sections.cpp index e56736191a..2c698386c2 100644 --- a/src/hwrenderer/data/hw_sections.cpp +++ b/src/hwrenderer/data/hw_sections.cpp @@ -34,6 +34,7 @@ #include "p_setup.h" #include "c_dispatch.h" #include "memarena.h" +#include "flatvertices.h" using DoublePoint = std::pair; @@ -611,6 +612,114 @@ public: return false; } + + //============================================================================= + // + // + // + //============================================================================= + + // Temporary data for creating an indexed buffer + struct VertexIndexGenerationInfo + { + TArray vertices; + TMap vertexmap; + + TArray indices; + + uint32_t AddVertex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + auto index = vertices.Push(vert); + vertexmap[vert] = index; + return index; + } + + uint32_t GetIndex(vertex_t *vert) + { + auto check = vertexmap.CheckKey(vert); + if (check != nullptr) return *check; + return ~0u; + } + + uint32_t AddIndexForVertex(vertex_t *vert) + { + return indices.Push(GetIndex(vert)); + } + + uint32_t AddIndex(uint32_t indx) + { + return indices.Push(indx); + } + }; + + //============================================================================= + // + // + // + //============================================================================= + + void CreateIndexedSubsectorVertices(subsector_t *sub, VertexIndexGenerationInfo &gen) + { + if (sub->numlines < 3) return; + + uint32_t startindex = gen.indices.Size(); + + if ((sub->flags & SSECF_HOLE) && sub->numlines > 3) + { + // Hole filling "subsectors" are not necessarily convex so they require real triangulation. + // These things are extremely rare so performance is secondary here. + + using Point = std::pair; + std::vector> polygon; + std::vector *curPoly; + + for (unsigned i = 0; i < sub->numlines; i++) + { + polygon.resize(1); + curPoly = &polygon.back(); + curPoly->push_back({ sub->firstline[i].v1->fX(), sub->firstline[i].v1->fY() }); + } + auto indices = mapbox::earcut(polygon); + for (auto vti : indices) + { + gen.AddIndexForVertex(sub->firstline[vti].v1); + } + } + else + { + int firstndx = gen.GetIndex(sub->firstline[0].v1); + int secondndx = gen.GetIndex(sub->firstline[1].v1); + for (unsigned int k = 2; k < sub->numlines; k++) + { + gen.AddIndex(firstndx); + gen.AddIndex(secondndx); + auto ndx = gen.GetIndex(sub->firstline[k].v1); + gen.AddIndex(ndx); + secondndx = ndx; + } + } + } + + + void CreateVerticesForSection(FSectionContainer &output, FSection §ion) + { + VertexIndexGenerationInfo gen; + + for (auto sub : section.subsectors) + { + CreateIndexedSubsectorVertices(sub, gen); + } + section.vertexindex = output.allVertices.Size(); + section.vertexcount = gen.vertices.Size(); + section.indexindex = output.allVertexIndices.Size(); + section.indexcount = gen.indices.Size(); + output.allVertices.Append(gen.vertices); + output.allVertexIndices.Append(gen.indices); + } + + //============================================================================= // // @@ -620,10 +729,14 @@ public: void ConstructOutput(FSectionContainer &output) { output.allSections.Resize(groups.Size()); - output.allIndices.Resize(level.subsectors.Size() + level.sides.Size()); + output.allIndices.Resize(level.subsectors.Size() + level.sides.Size() + 2*level.sectors.Size()); output.sectionForSubsectorPtr = &output.allIndices[0]; output.sectionForSidedefPtr = &output.allIndices[level.subsectors.Size()]; + output.firstSectionForSectorPtr = &output.allIndices[level.subsectors.Size() + level.sides.Size()]; + output.numberOfSectionForSectorPtr = &output.allIndices[level.subsectors.Size() + level.sides.Size() + level.sectors.Size()]; memset(output.sectionForSubsectorPtr, -1, sizeof(int) * level.subsectors.Size()); + memset(output.firstSectionForSectorPtr, -1, sizeof(int) * level.sectors.Size()); + memset(output.numberOfSectionForSectorPtr, 0, sizeof(int) * level.sectors.Size()); unsigned numsegments = 0; unsigned numsides = 0; @@ -669,10 +782,15 @@ public: dest.validcount = 0; dest.segments.Set(&output.allLines[numsegments], group.segments.Size()); dest.sides.Set(&output.allSides[numsides], group.sideMap.CountUsed()); - dest.subsectors.Set(&output.allSubsectors[numsubsectors]); + dest.subsectors.Set(&output.allSubsectors[numsubsectors], group.subsectors.Size()); + dest.vertexindex = -1; + dest.vertexcount = 0; dest.bounds = {1e32, 1e32, -1e32, -1e32}; numsegments += group.segments.Size(); + if (output.firstSectionForSectorPtr[dest.sector->Index()] == -1) + output.firstSectionForSectorPtr[dest.sector->Index()] = curgroup; + for (auto &segment : group.segments) { // Use the indices calculated above to store these elements. @@ -697,6 +815,7 @@ public: output.sectionForSubsectorPtr[ssi] = curgroup; } numsubsectors += group.subsectors.Size(); + CreateVerticesForSection(output, dest); curgroup++; } } diff --git a/src/hwrenderer/data/hw_sections.h b/src/hwrenderer/data/hw_sections.h index 6edda1143d..7e1e94b6ce 100644 --- a/src/hwrenderer/data/hw_sections.h +++ b/src/hwrenderer/data/hw_sections.h @@ -80,11 +80,15 @@ struct FSection { // tbd: Do we need a list of subsectors here? Ideally the subsectors should not be used anywhere anymore except for finding out where a location is. TArrayView segments; - TArrayView sides; // contains all sidedefs, including the internal ones that do not make up the outer shape. (this list is not exclusive. A sidedef can be in multiple sections!) - TArrayView subsectors; // contains all sidedefs, including the internal ones that do not make up the outer shape. (this list is not exclusive. A sidedef can be in multiple sections!) + TArrayView sides; // contains all sidedefs, including the internal ones that do not make up the outer shape. + TArrayView subsectors; // contains all subsectors making up this section sector_t *sector; - FLightNode *lighthead; // Light nodes (blended and additive) + FLightNode *lighthead; // Light nodes (blended and additive) BoundingRect bounds; + int vertexindex; + int vertexcount; // index and length of this section's entry in the allVertices array + int indexindex; + int indexcount; // index and length of this section's entry in the allVertices array int validcount; short mapsection; char hacked; // 1: is part of a render hack @@ -95,13 +99,16 @@ class FSectionContainer public: TArray allLines; TArray allSections; - //TArray allVertices; + TArray allVertices; + TArray allVertexIndices; TArray allSides; TArray allSubsectors; TArray allIndices; int *sectionForSubsectorPtr; // stored inside allIndices int *sectionForSidedefPtr; // also stored inside allIndices; + int *firstSectionForSectorPtr; // ditto. + int *numberOfSectionForSectorPtr; // ditto. FSection *SectionForSubsector(subsector_t *sub) { @@ -111,6 +118,14 @@ public: { return ssindex < 0 ? nullptr : &allSections[sectionForSubsectorPtr[ssindex]]; } + int SectionNumForSubsector(subsector_t *sub) + { + return SectionNumForSubsector(sub->Index()); + } + int SectionNumForSubsector(int ssindex) + { + return ssindex < 0 ? -1 : sectionForSubsectorPtr[ssindex]; + } FSection *SectionForSidedef(side_t *side) { return SectionForSidedef(side->Index()); @@ -119,11 +134,35 @@ public: { return sindex < 0 ? nullptr : &allSections[sectionForSidedefPtr[sindex]]; } + int SectionNumForSidedef(side_t *side) + { + return SectionNumForSidedef(side->Index()); + } + int SectionNumForSidedef(int sindex) + { + return sindex < 0 ? -1 : sectionForSidedefPtr[sindex]; + } + TArrayView SectionsForSector(sector_t *sec) + { + return SectionsForSector(sec->Index()); + } + TArrayView SectionsForSector(int sindex) + { + return sindex < 0 ? TArrayView(0) : TArrayView(&allSections[firstSectionForSectorPtr[sindex]], numberOfSectionForSectorPtr[sindex]); + } + int SectionIndex(const FSection *sect) + { + return int(sect - allSections.Data()); + } void Clear() { allLines.Clear(); allSections.Clear(); allIndices.Clear(); + allVertexIndices.Clear(); + allVertices.Clear(); + allSides.Clear(); + allSubsectors.Clear(); } void Reset() { @@ -131,6 +170,10 @@ public: allLines.ShrinkToFit(); allSections.ShrinkToFit(); allIndices.ShrinkToFit(); + allVertexIndices.ShrinkToFit(); + allVertices.ShrinkToFit(); + allSides.ShrinkToFit(); + allSubsectors.ShrinkToFit(); } }; diff --git a/src/hwrenderer/scene/hw_bsp.cpp b/src/hwrenderer/scene/hw_bsp.cpp index 75be620f41..92b9117814 100644 --- a/src/hwrenderer/scene/hw_bsp.cpp +++ b/src/hwrenderer/scene/hw_bsp.cpp @@ -155,6 +155,7 @@ void HWDrawInfo::WorkerThread() { GLFlat flat; SetupFlat.Clock(); + flat.section = level.sections.SectionForSubsector(job->sub); front = hw_FakeFlat(job->sub->render_sector, &fakefront, in_area, false); flat.ProcessSector(this, front); SetupFlat.Unclock(); @@ -679,7 +680,8 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) fakesector = hw_FakeFlat(sector, &fake, in_area, false); } - uint8_t &srf = sectorrenderflags[sub->render_sector->sectornum]; + auto secnum = level.sections.SectionNumForSubsector(sub); + uint8_t &srf = section_renderflags[secnum]; if (!(srf & SSRF_PROCESSED)) { srf |= SSRF_PROCESSED; @@ -691,6 +693,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) else { GLFlat flat; + flat.section = level.sections.SectionForSubsector(sub); SetupFlat.Clock(); flat.ProcessSector(this, fakesector); SetupFlat.Unclock(); diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index d781fc64d9..128b1d8fa5 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -214,11 +214,11 @@ void HWDrawInfo::ClearBuffers() CurrentMapSections.Resize(level.NumMapSections); CurrentMapSections.Zero(); - sectorrenderflags.Resize(level.sectors.Size()); + section_renderflags.Resize(level.sections.allSections.Size()); ss_renderflags.Resize(level.subsectors.Size()); no_renderflags.Resize(level.subsectors.Size()); - memset(§orrenderflags[0], 0, level.sectors.Size() * sizeof(sectorrenderflags[0])); + memset(§ion_renderflags[0], 0, level.sections.allSections.Size() * sizeof(section_renderflags[0])); memset(&ss_renderflags[0], 0, level.subsectors.Size() * sizeof(ss_renderflags[0])); memset(&no_renderflags[0], 0, level.nodes.Size() * sizeof(no_renderflags[0])); diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 1eb4f62821..c3a9ddfb39 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -170,7 +170,7 @@ struct HWDrawInfo TArray HandledSubsectors; - TArray sectorrenderflags; + TArray section_renderflags; TArray ss_renderflags; TArray no_renderflags; diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 38514a6bf7..194de2c50b 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -27,6 +27,7 @@ struct FSpriteModelFrame; struct particle_t; class FRenderState; struct GLDecal; +struct FSection; enum area_t : int; enum HWRenderStyle @@ -293,6 +294,7 @@ class GLFlat { public: sector_t * sector; + FSection *section; float z; // the z position of the flat (only valid for non-sloped planes) FMaterial *gltexture; diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index 7763461140..db9edfccbb 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -189,6 +189,8 @@ void GLFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) SetupLights(di, sector->lighthead, lightdata, sector->PortalGroup); } state.SetLightIndex(dynlightindex); + + if (vcount > 0 && !di->ClipLineShouldBeActive()) { state.DrawIndexed(DT_Triangles, iboindex, vcount); @@ -197,6 +199,7 @@ void GLFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) } else { + /* int index = iboindex; bool applied = false; for (int i = 0; i < sector->subsectorcount; i++) @@ -213,6 +216,7 @@ void GLFlat::DrawSubsectors(HWDrawInfo *di, FRenderState &state) } index += (sub->numlines - 2) * 3; } + */ } if (!(renderflags&SSRF_RENDER3DPLANES)) @@ -473,7 +477,7 @@ void GLFlat::ProcessSector(HWDrawInfo *di, sector_t * frontsector) extsector_t::xfloor &x = sector->e->XFloor; dynlightindex = -1; - uint8_t &srf = di->sectorrenderflags[sector->sectornum]; + uint8_t &srf = di->section_renderflags[level.sections.SectionIndex(section)]; const auto &vp = di->Viewpoint; // diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index f6899b4341..afc8aaab89 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -850,7 +850,8 @@ void HWDrawInfo::PrepareUnhandledMissingTextures() if (seg->linedef->validcount == validcount) continue; // already done seg->linedef->validcount = validcount; - if (!(sectorrenderflags[seg->backsector->sectornum] & SSRF_RENDERFLOOR)) continue; + int section = level.sections.SectionNumForSidedef(seg->sidedef); + if (!(section_renderflags[section] & 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;