- migrated automap to new SectionGeometry class.

This commit is contained in:
Christoph Oelckers 2021-12-14 17:40:03 +01:00
parent 362b824775
commit a407e86ff6
4 changed files with 50 additions and 39 deletions

View file

@ -581,28 +581,31 @@ void renderDrawMapView(int cposx, int cposy, int czoom, int cang)
int picnum = sect->floorpicnum; int picnum = sect->floorpicnum;
if ((unsigned)picnum >= (unsigned)MAXTILES) continue; if ((unsigned)picnum >= (unsigned)MAXTILES) continue;
int translation = TRANSLATION(Translation_Remap + curbasepal, sector[i].floorpal);
PalEntry light = shadeToLight(sector[i].floorshade);
setgotpic(picnum);
for (auto sect : sections2PerSector[i]) for (auto sect : sections2PerSector[i])
{ {
TArray<int>* indices; TArray<int>* indices;
auto mesh = sectionGeometry.get(sect, 0, { 0.f, 0.f }, &indices); auto mesh = sectionGeometry.get(sect, 0, { 0.f, 0.f }, &indices);
vertices.Resize(indices->Size()); vertices.Resize(mesh->vertices.Size());
for (unsigned jj = 0; jj < indices->Size(); jj++) for (unsigned j = 0; j < mesh->vertices.Size(); j++)
{ {
int j = (*indices)[jj];
int ox = int(mesh->vertices[j].X * 16.f) - cposx; int ox = int(mesh->vertices[j].X * 16.f) - cposx;
int oy = int(mesh->vertices[j].Y * -16.f) - cposy; int oy = int(mesh->vertices[j].Y * -16.f) - cposy;
int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11); int x1 = DMulScale(ox, xvect, -oy, yvect, 16) + (width << 11);
int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11); int y1 = DMulScale(oy, xvect, ox, yvect, 16) + (height << 11);
vertices[j] = { x1 / 4096.f, y1 / 4096.f, mesh->texcoords[j].X, mesh->texcoords[j].Y }; vertices[j] = { x1 / 4096.f, y1 / 4096.f, mesh->texcoords[j].X, mesh->texcoords[j].Y };
} }
#ifdef _DEBUG
// visualize the triangulator being used.
if (sections2PerSector[i][0]->geomflags & NoEarcut) light.r = light.b = 80;
#endif
twod->AddPoly(tileGetTexture(picnum, true), vertices.Data(), vertices.Size(), (unsigned*)indices->Data(), indices->Size(), translation, light,
LegacyRenderStyles[STYLE_Translucent], windowxy1.x, windowxy1.y, windowxy2.x + 1, windowxy2.y + 1);
} }
int translation = TRANSLATION(Translation_Remap + curbasepal, sector[i].floorpal);
setgotpic(picnum);
twod->AddPoly(tileGetTexture(picnum, true), vertices.Data(), vertices.Size(), nullptr, 0, translation, shadeToLight(sector[i].floorshade),
LegacyRenderStyles[STYLE_Translucent], windowxy1.x, windowxy1.y, windowxy2.x + 1, windowxy2.y + 1);
} }
qsort(floorsprites.Data(), floorsprites.Size(), sizeof(spritetype*), [](const void* a, const void* b) qsort(floorsprites.Data(), floorsprites.Size(), sizeof(spritetype*), [](const void* a, const void* b)
{ {

View file

@ -28,7 +28,9 @@ struct Section2Loop
struct Section2 struct Section2
{ {
int flags; uint8_t flags;
uint8_t dirty;
uint8_t geomflags;
unsigned index; unsigned index;
sectortype* sector; sectortype* sector;
// this uses a memory arena for storage, so use TArrayView instead of TArray // this uses a memory arena for storage, so use TArrayView instead of TArray

View file

@ -233,13 +233,13 @@ static int OutlineToFloat(Outline& outl, FOutline& polygon)
for (unsigned j = 0; j < outl[i].Size(); j++) for (unsigned j = 0; j < outl[i].Size(); j++)
{ {
float X = RenderX(outl[i][j].x); float X = RenderX(outl[i][j].x);
float Y = RenderX(outl[i][j].y); float Y = RenderY(outl[i][j].y);
if (fabs(X) > 32768.f || fabs(Y) > 32768.f) if (fabs(X) > 32768.f || fabs(Y) > 32768.f)
{ {
// If we get here there's some fuckery going around with the coordinates. Let's better abort and wait for things to realign. // If we get here there's some fuckery going around with the coordinates. Let's better abort and wait for things to realign.
// Do not try alternative methods if this happens. // Do not try alternative methods if this happens.
return -1; return -1;
} }
polygon[i][j] = { X, Y }; polygon[i][j] = { X, Y };
} }
} }
@ -257,7 +257,8 @@ ETriangulateResult TriangulateOutlineEarcut(const FOutline& polygon, int count,
// Sections are already validated so we can assume that the data is well defined here. // Sections are already validated so we can assume that the data is well defined here.
auto indices = mapbox::earcut(polygon); auto indices = mapbox::earcut(polygon);
if (indices.size() < 3 * (count + polygon.size() * 2 - 2)) size_t numtriangles = count + (polygon.size() - 1) * 2 - 2; // accout for the extra connections needed to turn the polygon into s single loop.
if (indices.size() < numtriangles * 3)
{ {
// this means that full triangulation failed. // this means that full triangulation failed.
return ETriangulateResult::Failed; return ETriangulateResult::Failed;
@ -284,10 +285,11 @@ ETriangulateResult TriangulateOutlineEarcut(const FOutline& polygon, int count,
// Try to triangulate a given outline with libtess2. // Try to triangulate a given outline with libtess2.
// //
//========================================================================== //==========================================================================
FMemArena tessArena(100000);
ETriangulateResult TriangulateOutlineLibtess(const FOutline& polygon, int count, TArray<FVector2>& points, TArray<int>& indicesOut) ETriangulateResult TriangulateOutlineLibtess(const FOutline& polygon, int count, TArray<FVector2>& points, TArray<int>& indicesOut)
{ {
FMemArena tessArena(100000); tessArena.FreeAll();
auto poolAlloc = [](void* userData, unsigned int size) -> void* auto poolAlloc = [](void* userData, unsigned int size) -> void*
{ {
@ -309,13 +311,14 @@ ETriangulateResult TriangulateOutlineLibtess(const FOutline& polygon, int count,
if (!tess) if (!tess)
return ETriangulateResult::Failed; return ETriangulateResult::Failed;
//tessSetOption(tess, TESS_CONSTRAINED_DELAUNAY_TRIANGULATION, 1); tessSetOption(tess, TESS_CONSTRAINED_DELAUNAY_TRIANGULATION, 0);
tessSetOption(tess, TESS_REVERSE_CONTOURS, 1);
// Add contours. // Add contours.
for (auto& loop : polygon) for (auto& loop : polygon)
tessAddContour(tess, 2, &loop.data()->first, (int)sizeof(*loop.data()), (int)loop.size()); tessAddContour(tess, 2, &loop.data()->first, (int)sizeof(*loop.data()), (int)loop.size());
int result = tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, 3, 2, 0); int result = tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, 3, 2, nullptr);
if (!result) if (!result)
{ {
tessDeleteTess(tess); tessDeleteTess(tess);
@ -326,16 +329,16 @@ ETriangulateResult TriangulateOutlineLibtess(const FOutline& polygon, int count,
const int* vinds = tessGetVertexIndices(tess); const int* vinds = tessGetVertexIndices(tess);
const int* elems = tessGetElements(tess); const int* elems = tessGetElements(tess);
const int nverts = tessGetVertexCount(tess); const int nverts = tessGetVertexCount(tess);
const int nelems = tessGetElementCount(tess); const int nelems = tessGetElementCount(tess) * 3; // an 'element' here is a full triangle, not a single vertex like in OpenGL...
points.Resize(nverts); points.Resize(nverts);
indicesOut.Resize(nelems); indicesOut.Resize(nelems);
for (int i = 0; i < nverts; i++) for (int i = 0; i < nverts; i++)
{ {
points[i] = { verts[i * 2], verts[i * 2 + 1] }; points[i] = { verts[i * 2], verts[i * 2 + 1] };
} }
for (int i = 0; i < nelems; i++) for (int i = 0; i < nelems; i++)
{ {
indicesOut[i] = elems[i]; indicesOut[i] = elems[i];
} }
return ETriangulateResult::Ok; return ETriangulateResult::Ok;
@ -347,6 +350,7 @@ ETriangulateResult TriangulateOutlineLibtess(const FOutline& polygon, int count,
// //
//========================================================================== //==========================================================================
#if 0
ETriangulateResult TriangulateOutlineNodeBuild(const FOutline& polygon, int count, TArray<FVector2>& points, TArray<int>& indicesOut) ETriangulateResult TriangulateOutlineNodeBuild(const FOutline& polygon, int count, TArray<FVector2>& points, TArray<int>& indicesOut)
{ {
TArray<vertex_t> vertexes(count, true); TArray<vertex_t> vertexes(count, true);
@ -412,6 +416,7 @@ ETriangulateResult TriangulateOutlineNodeBuild(const FOutline& polygon, int coun
} }
return ETriangulateResult::Ok; return ETriangulateResult::Ok;
} }
#endif
//========================================================================== //==========================================================================
// //
@ -434,9 +439,9 @@ bool SectionGeometry::ValidateSection(Section2* section, int plane)
sec->floorypan_ == compare->floorypan_ && sec->floorypan_ == compare->floorypan_ &&
sec->firstWall()->pos == sdata.poscompare[0] && sec->firstWall()->pos == sdata.poscompare[0] &&
sec->firstWall()->point2Wall()->pos == sdata.poscompare2[0] && sec->firstWall()->point2Wall()->pos == sdata.poscompare2[0] &&
!(sdata.dirty & EDirty::FloorDirty) && sdata.planes[plane].vertices.Size() ) return true; !(section->dirty & EDirty::FloorDirty) && sdata.planes[plane].vertices.Size() ) return true;
sdata.dirty &= EDirty::FloorDirty; section->dirty &= EDirty::FloorDirty;
} }
else else
{ {
@ -447,9 +452,9 @@ bool SectionGeometry::ValidateSection(Section2* section, int plane)
sec->ceilingypan_ == compare->ceilingypan_ && sec->ceilingypan_ == compare->ceilingypan_ &&
sec->firstWall()->pos == sdata.poscompare[1] && sec->firstWall()->pos == sdata.poscompare[1] &&
sec->firstWall()->point2Wall()->pos == sdata.poscompare2[1] && sec->firstWall()->point2Wall()->pos == sdata.poscompare2[1] &&
!(sdata.dirty & EDirty::CeilingDirty) && sdata.planes[1].vertices.Size()) return true; !(section->dirty & EDirty::CeilingDirty) && sdata.planes[1].vertices.Size()) return true;
sdata.dirty &= ~EDirty::CeilingDirty; section->dirty &= ~EDirty::CeilingDirty;
} }
*compare = *sec; *compare = *sec;
sdata.poscompare[plane] = sec->firstWall()->pos; sdata.poscompare[plane] = sec->firstWall()->pos;
@ -480,17 +485,20 @@ bool SectionGeometry::CreateMesh(Section2* section)
{ {
result = TriangulateOutlineEarcut(foutline, count, sdata.meshVertices, sdata.meshIndices); result = TriangulateOutlineEarcut(foutline, count, sdata.meshVertices, sdata.meshIndices);
} }
if (result == ETriangulateResult::Failed && !(section->flags & NoLibtess)) if (result == ETriangulateResult::Failed && !(section->geomflags & NoLibtess))
{ {
section->flags |= NoEarcut; section->geomflags |= NoEarcut;
result = TriangulateOutlineLibtess(foutline, count, sdata.meshVertices, sdata.meshIndices); result = TriangulateOutlineLibtess(foutline, count, sdata.meshVertices, sdata.meshIndices);
} }
#if 0
if (result == ETriangulateResult::Failed) if (result == ETriangulateResult::Failed)
{ {
section->flags |= NoLibtess; section->geomflags |= NoLibtess;
result = TriangulateOutlineNodeBuild(foutline, count, sdata.meshVertices, meshIndices); result = TriangulateOutlineNodeBuild(foutline, count, sdata.meshVertices, meshIndices);
} }
section->flags &= ~EDirty::GeometryDirty; #endif
section->dirty &= ~EDirty::GeometryDirty;
return true; return true;
} }
@ -521,7 +529,7 @@ void SectionGeometry::CreatePlaneMesh(Section2* section, int plane, const FVecto
auto& pt = entry.vertices[i]; auto& pt = entry.vertices[i];
auto& tc = entry.texcoords[i]; auto& tc = entry.texcoords[i];
pt.XY() = org; pt.X = org.X; pt.Y = org.Y;
PlanesAtPoint(sectorp, (pt.X * 16), (pt.Y * -16), plane ? &pt.Z : nullptr, !plane ? &pt.Z : nullptr); PlanesAtPoint(sectorp, (pt.X * 16), (pt.Y * -16), plane ? &pt.Z : nullptr, !plane ? &pt.Z : nullptr);
tc = uvcalc.GetUV(int(pt.X * 16.), int(pt.Y * -16.), pt.Z); tc = uvcalc.GetUV(int(pt.X * 16.), int(pt.Y * -16.), pt.Z);
} }
@ -540,7 +548,7 @@ void SectionGeometry::MarkDirty(sectortype* sector)
{ {
for (auto section : sections2PerSector[sectnum(sector)]) for (auto section : sections2PerSector[sectnum(sector)])
{ {
data[section->index].dirty = sector->dirty; section->dirty = sector->dirty;
} }
sector->dirty = 0; sector->dirty = 0;
} }
@ -556,12 +564,12 @@ SectionGeometryPlane* SectionGeometry::get(Section2* section, int plane, const F
if (!section || section->index >= data.Size()) return nullptr; if (!section || section->index >= data.Size()) return nullptr;
auto sectp = section->sector; auto sectp = section->sector;
if (sectp->dirty) MarkDirty(sectp); if (sectp->dirty) MarkDirty(sectp);
if (data[section->index].dirty & EDirty::GeometryDirty) if (section->dirty & EDirty::GeometryDirty)
{ {
bool res = CreateMesh(section); bool res = CreateMesh(section);
if (!res) if (!res)
{ {
section->flags &= ~EDirty::GeometryDirty; // sector is in an invalid state, so pretend the old setup is still valid. Happens in some SW maps. section->dirty &= ~EDirty::GeometryDirty; // sector is in an invalid state, so pretend the old setup is still valid. Happens in some SW maps.
} }
} }
if (!ValidateSection(section, plane)) if (!ValidateSection(section, plane))

View file

@ -67,8 +67,6 @@ struct SectionGeometryData
vec2_t poscompare[2] = {}; vec2_t poscompare[2] = {};
vec2_t poscompare2[2] = {}; vec2_t poscompare2[2] = {};
FVector3 normal[2]; FVector3 normal[2];
int dirty;
int flags;
}; };
class SectionGeometry class SectionGeometry