From 094afdfd5f0f8bcfcabc9e09b16276791cbbff4b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 11 Nov 2018 09:33:40 +0100 Subject: [PATCH] - fixed: It may happen that a degenerate subsector ends up without any section or sector. Try to assign the best fit in such a case so that the relevant pointers are not null. --- src/r_data/r_sections.cpp | 84 +++++++++++++++++++++++++++++++++++++-- src/tarray.h | 7 +++- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/src/r_data/r_sections.cpp b/src/r_data/r_sections.cpp index 9186a13a1..5be657c25 100644 --- a/src/r_data/r_sections.cpp +++ b/src/r_data/r_sections.cpp @@ -184,6 +184,33 @@ public: { CompileSections(pair->Value, rawsections); } + + // Make sure that all subsectors have a sector. In some degenerate cases a subsector may come up empty. + // An example is in Doom.wad E3M4 near linedef 1087. With the grouping data here this is relatively easy to fix. + sector_t *lastsector = &level.sectors[0]; + for (auto &rawsection : rawsections) + { + sector_t *mysector = nullptr; + bool missing = false; + for (auto num : rawsection) + { + auto &sub = level.subsectors[num]; + if (sub.sector == nullptr) missing = true; + else mysector = sub.sector; + } + // Should the worst case happen and no sector be found, use the last used one. Subsectors must not be sector-less! + if (mysector == nullptr) mysector = lastsector; + else lastsector = mysector; + for (auto num : rawsection) + { + auto &sub = level.subsectors[num]; + if (sub.sector == nullptr) + { + sub.sector = mysector; + } + } + } + subsectormap.Clear(); return rawsections; } @@ -253,8 +280,7 @@ public: { MakeOutline(list, lineForSeg); } - rawsections.Clear(); - rawsections.ShrinkToFit(); + rawsections.Reset(); // Assign partners after everything has been collected for (auto §ion : sections) @@ -720,8 +746,59 @@ public: curgroup++; } } -}; + //============================================================================= + // + // Check if some subsectors have come up empty on sections. + // In this case assign the best fit from the containing sector. + // This is only to ensure that the section pointer is not null. + // These are always degenerate and do not produce any actual render output. + // + //============================================================================= + + void FixMissingReferences() + { + for (auto &sub : level.subsectors) + { + if (sub.section == nullptr) + { + int sector = sub.sector->Index(); + int mapsection = sub.mapsection; + auto sections = level.sections.SectionsForSector(sector); + FSection *bestfit = nullptr; + for (auto §ion : sections) + { + if (bestfit == nullptr) + { + bestfit = §ion; + } + else if (bestfit->mapsection != section.mapsection && section.mapsection == mapsection) + { + bestfit = §ion; + } + else if (section.mapsection == mapsection) + { + BoundingRect rc; + for (unsigned i = 0; i < sub.numlines; i++) + { + rc.addVertex(sub.firstline[i].v1->fX(), sub.firstline[i].v1->fY()); + rc.addVertex(sub.firstline[i].v2->fX(), sub.firstline[i].v2->fY()); + } + // Pick the one closer to this subsector. + if (rc.distanceTo(section.bounds) < rc.distanceTo(bestfit->bounds)) + { + bestfit = §ion; + } + } + } + // This should really never happen, but better be safe than sorry and assign at least something. + if (bestfit == nullptr) bestfit = &level.sections.allSections[0]; + sub.section = bestfit; + } + } + } + +}; //============================================================================= @@ -787,6 +864,7 @@ void CreateSections(FSectionContainer &container) creat.FindOuterLoops(); creat.GroupSections(); creat.ConstructOutput(container); + creat.FixMissingReferences(); } CCMD(printsections) diff --git a/src/tarray.h b/src/tarray.h index e5f58b548..167f85fa9 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -458,7 +458,12 @@ public: void Reset() { Clear(); - ShrinkToFit(); + Most = 0; + if (Array != nullptr) + { + M_Free(Array); + Array = nullptr; + } } private: T *Array;