- made the MapSectionGenerator a class to remove a global array.

This commit is contained in:
Christoph Oelckers 2018-04-02 08:25:07 +02:00
parent 4357f0dc40
commit 202d209eb8
1 changed files with 133 additions and 119 deletions

View File

@ -51,156 +51,169 @@
//========================================================================== //==========================================================================
// //
// // Map section generation
// Map sections are physically separated parts of the map.
// If the player is in section A, any map part in other sections can
// often be quickly discarded to improve performance.
// //
//========================================================================== //==========================================================================
static TArray<subsector_t *> MapSectionCollector;
static void DoSetMapSection(subsector_t *sub, int num) struct MapSectionGenerator
{ {
MapSectionCollector.Resize(1); struct cvertex_t
MapSectionCollector[0] = sub;
sub->mapsection = num;
for (unsigned a = 0; a < MapSectionCollector.Size(); a++)
{ {
sub = MapSectionCollector[a]; double X, Y;
for (uint32_t i = 0; i < sub->numlines; i++)
operator int() const { return xs_FloorToInt(X) + 65536 * xs_FloorToInt(Y); }
bool operator!= (const cvertex_t &other) const { return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON; }
cvertex_t& operator =(const vertex_t *v) { X = v->fX(); Y = v->fY(); return *this; }
};
typedef TMap<cvertex_t, int> FSectionVertexMap;
TArray<subsector_t *> MapSectionCollector;
//==========================================================================
//
//
//
//==========================================================================
void DoSetMapSection(subsector_t *sub, int num)
{
MapSectionCollector.Resize(1);
MapSectionCollector[0] = sub;
sub->mapsection = num;
for (unsigned a = 0; a < MapSectionCollector.Size(); a++)
{ {
seg_t * seg = sub->firstline + i; sub = MapSectionCollector[a];
for (uint32_t i = 0; i < sub->numlines; i++)
if (seg->PartnerSeg)
{ {
subsector_t * sub2 = seg->PartnerSeg->Subsector; seg_t * seg = sub->firstline + i;
if (sub2->mapsection != num) if (seg->PartnerSeg)
{ {
assert(sub2->mapsection == 0); subsector_t * sub2 = seg->PartnerSeg->Subsector;
sub2->mapsection = num;
MapSectionCollector.Push(sub2); if (sub2->mapsection != num)
{
assert(sub2->mapsection == 0);
sub2->mapsection = num;
MapSectionCollector.Push(sub2);
}
} }
} }
} }
MapSectionCollector.Clear();
} }
MapSectionCollector.Clear();
}
//========================================================================== //==========================================================================
// //
// Merge sections. This is needed in case the map contains errors // Merge sections. This is needed in case the map contains errors
// like overlapping lines resulting in abnormal subsectors. // like overlapping lines resulting in abnormal subsectors.
// //
// This function ensures that any vertex position can only be in one section. // This function ensures that any vertex position can only be in one section.
// //
//========================================================================== //==========================================================================
struct cvertex_t
{
double X, Y;
operator int() const { return xs_FloorToInt(X) + 65536 * xs_FloorToInt(Y); } int MergeMapSections(int num)
bool operator!= (const cvertex_t &other) const { return fabs(X - other.X) >= EQUAL_EPSILON || fabs(Y - other.Y) >= EQUAL_EPSILON; }
cvertex_t& operator =(const vertex_t *v) { X = v->fX(); Y = v->fY(); return *this; }
};
typedef TMap<cvertex_t, int> FSectionVertexMap;
static int MergeMapSections(int num)
{
FSectionVertexMap vmap;
FSectionVertexMap::Pair *pair;
TArray<int> sectmap;
TArray<bool> sectvalid;
sectmap.Resize(num);
sectvalid.Resize(num);
for (int i = 0; i < num; i++)
{ {
sectmap[i] = -1; FSectionVertexMap vmap;
sectvalid[i] = true; FSectionVertexMap::Pair *pair;
} TArray<int> sectmap;
int mergecount = 1; TArray<bool> sectvalid;
sectmap.Resize(num);
sectvalid.Resize(num);
cvertex_t vt; for (int i = 0; i < num; i++)
// first step: Set mapsection for all vertex positions.
for (auto &seg : level.segs)
{
int section = seg.Subsector->mapsection;
for (int j = 0; j < 2; j++)
{ {
vt = j == 0 ? seg.v1 : seg.v2; sectmap[i] = -1;
vmap[vt] = section; sectvalid[i] = true;
} }
} int mergecount = 1;
// second step: Check if any seg references more than one mapsection, either by subsector or by vertex
for (auto &seg : level.segs) cvertex_t vt;
{
int section = seg.Subsector->mapsection; // first step: Set mapsection for all vertex positions.
for (int j = 0; j < 2; j++) for (auto &seg : level.segs)
{ {
vt = j == 0 ? seg.v1 : seg.v2; int section = seg.Subsector->mapsection;
int vsection = vmap[vt]; for (int j = 0; j < 2; j++)
if (vsection != section)
{ {
// These 2 sections should be merged vt = j == 0 ? seg.v1 : seg.v2;
for (auto &sub : level.subsectors) vmap[vt] = section;
{
if (sub.mapsection == vsection) sub.mapsection = section;
}
FSectionVertexMap::Iterator it(vmap);
while (it.NextPair(pair))
{
if (pair->Value == vsection) pair->Value = section;
}
sectvalid[vsection - 1] = false;
} }
} }
}
for (int i = 0; i < num; i++)
{
if (sectvalid[i]) sectmap[i] = mergecount++;
}
for (auto &sub : level.subsectors)
{
sub.mapsection = sectmap[sub.mapsection - 1];
assert(sub.mapsection != -1);
}
return mergecount - 1;
}
//========================================================================== // second step: Check if any seg references more than one mapsection, either by subsector or by vertex
// for (auto &seg : level.segs)
// {
// int section = seg.Subsector->mapsection;
//========================================================================== for (int j = 0; j < 2; j++)
{
vt = j == 0 ? seg.v1 : seg.v2;
int vsection = vmap[vt];
static void SetMapSections() if (vsection != section)
{ {
bool set; // These 2 sections should be merged
int num = 0; for (auto &sub : level.subsectors)
do {
{ if (sub.mapsection == vsection) sub.mapsection = section;
set = false; }
FSectionVertexMap::Iterator it(vmap);
while (it.NextPair(pair))
{
if (pair->Value == vsection) pair->Value = section;
}
sectvalid[vsection - 1] = false;
}
}
}
for (int i = 0; i < num; i++)
{
if (sectvalid[i]) sectmap[i] = mergecount++;
}
for (auto &sub : level.subsectors) for (auto &sub : level.subsectors)
{ {
if (sub.mapsection == 0) sub.mapsection = sectmap[sub.mapsection - 1];
assert(sub.mapsection != -1);
}
return mergecount - 1;
}
//==========================================================================
//
//
//
//==========================================================================
void SetMapSections()
{
bool set;
int num = 0;
do
{
set = false;
for (auto &sub : level.subsectors)
{ {
num++; if (sub.mapsection == 0)
DoSetMapSection(&sub, num); {
set = true; num++;
break; DoSetMapSection(&sub, num);
set = true;
break;
}
} }
} }
while (set);
num = MergeMapSections(num);
currentmapsection.Resize(1 + num/8);
#ifdef DEBUG
Printf("%d map sections found\n", num);
#endif
} }
while (set); };
num = MergeMapSections(num);
currentmapsection.Resize(1 + num/8);
#ifdef DEBUG
Printf("%d map sections found\n", num);
#endif
}
//========================================================================== //==========================================================================
// //
@ -283,7 +296,8 @@ static void PrepareSectorData()
} }
} }
} }
SetMapSections(); MapSectionGenerator msg;
msg.SetMapSections();
} }
//========================================================================== //==========================================================================