Figure out some steps in hole cutting logic

This commit is contained in:
James Lambert 2022-06-27 08:25:01 -06:00
parent 2a30dbd8c9
commit 8036e3d60f

View file

@ -14,6 +14,9 @@
#define GET_CURRENT_POINT(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->bIndex : (surfaceEdge->aIndex))
#define GET_NEXT_POINT(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->aIndex : (surfaceEdge->bIndex))
#define SET_NEXT_EDGE(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->nextEdgeReverse = (value); else (surfaceEdge)->nextEdge = (value); } while (0)
#define SET_PREV_EDGE(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->prevEdgeReverse = (value); else (surfaceEdge)->prevEdge = (value); } while (0)
#define MAX_SEARCH_ITERATIONS 20
#define ADDITIONAL_EDGE_CAPACITY 32
@ -36,7 +39,7 @@ struct PortalSurfaceBuilder {
// set when hasEdge is true
struct SurfaceEdgeWithSide cuttingEdge;
// set when hasEdge is false
struct Vector2s16* startingPoint;
int startingPoint;
};
short hasEdge;
short hasConnected;
@ -221,45 +224,35 @@ enum IntersectionType portalSurfaceIntersect(struct Vector2s16* pointA, struct V
return IntersectionTypePoint;
}
void portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* pointA, struct Vector2s16* pointDir) {
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop;
for (int iteration = 0; iteration < MAX_INTERSECT_LOOPS; ++iteration) {
struct SurfaceEdgeWithSide nextEdge;
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge);
if (nextEdge.edgeIndex == surfaceBuilder->edgeOnSearchLoop.edgeIndex && nextEdge.isReverse == surfaceBuilder->edgeOnSearchLoop.isReverse) {
// finished searching loop
break;
}
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex);
struct Vector2s16* edgeA = portalSurfaceGetPoint(surfaceBuilder, GET_CURRENT_POINT(edge, currentEdge.isReverse));
struct Vector2s16* edgeB = portalSurfaceGetPoint(surfaceBuilder, GET_NEXT_POINT(edge, currentEdge.isReverse));
struct Vector2s16 intersectionPoint;
enum IntersectionType intersectType = portalSurfaceIntersect(pointA, pointDir, edgeA, edgeB, &intersectionPoint);
if (intersectType) {
}
currentEdge = nextEdge;
}
}
int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, struct Vector2s16* point) {
if (surfaceBuilder->currentEdge == ADDITIONAL_EDGE_CAPACITY || surfaceBuilder->currentVertex == ADDITIONAL_VERTEX_CAPACITY) {
return 0;
int portalSurfaceNewVertex(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* point) {
if (surfaceBuilder->currentVertex == ADDITIONAL_VERTEX_CAPACITY) {
return -1;
}
surfaceBuilder->additionalVertices[surfaceBuilder->currentVertex] = *point;
int newVertexIndex = surfaceBuilder->currentVertex + surfaceBuilder->surface->vertexCount;
++surfaceBuilder->currentVertex;
return newVertexIndex;
}
int portalSurfaceNewEdge(struct PortalSurfaceBuilder* surfaceBuilder) {
if (surfaceBuilder->currentEdge == ADDITIONAL_EDGE_CAPACITY) {
return -1;
}
int newEdgeIndex = surfaceBuilder->currentEdge + surfaceBuilder->surface->edgeCount;
++surfaceBuilder->currentEdge;
return newEdgeIndex;
}
int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, struct Vector2s16* point) {
int newVertexIndex = portalSurfaceNewVertex(surfaceBuilder, point);
if (newVertexIndex == -1) {
return -1;
}
struct SurfaceEdge* existingEdge = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex);
struct SurfaceEdgeWithSide nextEdge;
@ -268,9 +261,13 @@ int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct S
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge);
portalSurfacePrevEdge(surfaceBuilder, edge, &prevReverseEdge);
struct SurfaceEdge* newEdge = &surfaceBuilder->additionalEdges[surfaceBuilder->currentEdge];
int newEdgeIndex = surfaceBuilder->currentEdge + surfaceBuilder->surface->edgeCount;
++surfaceBuilder->currentEdge;
int newEdgeIndex = portalSurfaceNewEdge(surfaceBuilder);
if (newEdgeIndex == -1) {
return -1;
}
struct SurfaceEdge* newEdge = portalSurfaceGetEdge(surfaceBuilder, newEdgeIndex);
newEdge->bIndex = existingEdge->bIndex;
newEdge->aIndex = newVertexIndex;
@ -293,15 +290,155 @@ int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct S
struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevReverseEdge.edgeIndex);
if (prevReverseEdge.isReverse) {
prevEdgePtr->nextEdgeReverse = newEdgeIndex;
} else {
prevEdgePtr->nextEdge = newEdgeIndex;
SET_NEXT_EDGE(prevEdgePtr, prevReverseEdge.isReverse, newEdgeIndex);
return newVertexIndex;
}
int portalSurfaceConnectToPoint(struct PortalSurfaceBuilder* surfaceBuilder, int pointIndex, struct SurfaceEdgeWithSide* edge) {
int newEdge = portalSurfaceNewEdge(surfaceBuilder);
if (newEdge == -1) {
return 0;
}
struct SurfaceEdge* newEdgePtr = portalSurfaceGetEdge(surfaceBuilder, newEdge);
if (surfaceBuilder->hasEdge) {
struct SurfaceEdgeWithSide nextEdge;
portalSurfaceNextEdge(surfaceBuilder, &surfaceBuilder->cuttingEdge, &nextEdge);
struct SurfaceEdge* cuttingEdgePtr = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->cuttingEdge.edgeIndex);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex);
newEdgePtr->aIndex = GET_NEXT_POINT(cuttingEdgePtr, surfaceBuilder->cuttingEdge.isReverse);
newEdgePtr->prevEdge = surfaceBuilder->cuttingEdge.edgeIndex;
newEdgePtr->nextEdgeReverse = nextEdge.edgeIndex;
SET_NEXT_EDGE(cuttingEdgePtr, surfaceBuilder->cuttingEdge.isReverse, newEdge);
SET_PREV_EDGE(nextEdgePtr, nextEdge.isReverse, newEdge);
} else {
newEdgePtr->prevEdge = newEdge;
newEdgePtr->nextEdgeReverse = newEdge;
newEdgePtr->aIndex = surfaceBuilder->startingPoint;
}
newEdgePtr->bIndex = pointIndex;
if (edge) {
struct SurfaceEdgeWithSide nextEdge;
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex);
newEdgePtr->nextEdge = nextEdge.edgeIndex;
newEdgePtr->prevEdgeReverse = edge->edgeIndex;
SET_NEXT_EDGE(edgePtr, edge->isReverse, newEdge);
SET_PREV_EDGE(nextEdgePtr, nextEdge.isReverse, newEdge);
} else {
newEdgePtr->nextEdge = newEdge;
newEdgePtr->prevEdgeReverse = newEdge;
}
surfaceBuilder->hasEdge = 1;
surfaceBuilder->cuttingEdge.edgeIndex = newEdge;
surfaceBuilder->cuttingEdge.isReverse = 0;
return 1;
}
struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* pointA, struct Vector2s16* pointDir) {
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop;
for (int iteration = 0; iteration < MAX_INTERSECT_LOOPS; ++iteration) {
struct SurfaceEdgeWithSide nextEdge;
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge);
if (nextEdge.edgeIndex == surfaceBuilder->edgeOnSearchLoop.edgeIndex && nextEdge.isReverse == surfaceBuilder->edgeOnSearchLoop.isReverse) {
// finished searching loop
break;
}
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex);
struct Vector2s16* edgeA = portalSurfaceGetPoint(surfaceBuilder, GET_CURRENT_POINT(edge, currentEdge.isReverse));
struct Vector2s16* edgeB = portalSurfaceGetPoint(surfaceBuilder, GET_NEXT_POINT(edge, currentEdge.isReverse));
struct Vector2s16 intersectionPoint;
enum IntersectionType intersectType = portalSurfaceIntersect(pointA, pointDir, edgeA, edgeB, &intersectionPoint);
if (intersectionPoint.equalTest == pointA->equalTest) {
currentEdge = nextEdge;
continue;
}
if (intersectType == IntersectionTypePoint) {
int newPointIndex;
if (intersectionPoint.equalTest == edgeA->equalTest) {
newPointIndex = GET_CURRENT_POINT(edge, currentEdge.isReverse);
} else if (intersectionPoint.equalTest == edgeB->equalTest) {
newPointIndex = GET_NEXT_POINT(edge, currentEdge.isReverse);
} else {
newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, &intersectionPoint);
if (newPointIndex == -1) {
return NULL;
}
}
if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, &currentEdge)) {
return NULL;
}
surfaceBuilder->hasConnected = 1;
return portalSurfaceGetPoint(surfaceBuilder, newPointIndex);
} else if (intersectType == IntersectionTypeColinear) {
int newPointIndex;
if (intersectionPoint.equalTest == edgeA->equalTest) {
newPointIndex = GET_CURRENT_POINT(edge, currentEdge.isReverse);
portalSurfacePrevEdge(surfaceBuilder, &currentEdge, &surfaceBuilder->cuttingEdge);
} else if (intersectionPoint.equalTest == edgeB->equalTest) {
newPointIndex = GET_NEXT_POINT(edge, currentEdge.isReverse);
surfaceBuilder->cuttingEdge = currentEdge;
} else {
int newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, &intersectionPoint);
if (newPointIndex == -1) {
return NULL;
}
surfaceBuilder->cuttingEdge = currentEdge;
}
surfaceBuilder->hasEdge = 1;
surfaceBuilder->hasConnected = 1;
return portalSurfaceGetPoint(surfaceBuilder, newPointIndex);
}
currentEdge = nextEdge;
}
struct Vector2s16 pointB;
vector2s16Add(pointA, pointDir, &pointB);
int newPointIndex = portalSurfaceNewVertex(surfaceBuilder, &pointB);
if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, NULL)) {
return NULL;
}
return portalSurfaceGetPoint(surfaceBuilder, newPointIndex);
}
int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* point) {
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop;
@ -331,7 +468,7 @@ int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder,
} else if (point->equalTest == edgeB->equalTest) {
surfaceBuilder->cuttingEdge = currentEdge;
} else {
if (!portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, point)) {
if (portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, point) == -1) {
return 0;
}
@ -349,7 +486,9 @@ int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder,
surfaceBuilder->hasEdge = 0;
surfaceBuilder->hasConnected = 0;
surfaceBuilder->startingPoint = point;
surfaceBuilder->startingPoint = surfaceBuilder->surface->vertexCount;
surfaceBuilder->additionalVertices[0] = *point;
++surfaceBuilder->currentVertex;
return 1;
}
@ -362,28 +501,44 @@ struct PortalSurface* portalSurfaceCutHole(struct PortalSurface* surface, struct
surfaceBuilder.additionalEdges = stackMalloc(sizeof(struct SurfaceEdge) * ADDITIONAL_EDGE_CAPACITY);
surfaceBuilder.currentEdge = 0;
if (!portalSurfaceFindEnclosingFace(surface, &loop[0], &surfaceBuilder.edgeOnSearchLoop)) {
return NULL;
}
if (!portalSurfaceFindStartingPoint(&surfaceBuilder, &loop[0])) {
return NULL;
}
struct Vector2s16* prev = &loop[0];
for (int i = 1; i < loopSize; ++i) {
struct Vector2s16* next = &loop[0];
if (!portalSurfaceFindEnclosingFace(surface, prev, &surfaceBuilder.edgeOnSearchLoop)) {
goto error;
}
if (!portalSurfaceFindStartingPoint(&surfaceBuilder, prev)) {
goto error;
}
for (int i = 1; i < loopSize;) {
struct Vector2s16* next = &loop[i];
struct Vector2s16 dir;
vector2s16Sub(next, prev, &dir);
portalSurfaceIntersectEdgeWithLoop(&surfaceBuilder, prev, &dir);
struct Vector2s16* newPoint = portalSurfaceIntersectEdgeWithLoop(&surfaceBuilder, prev, &dir);
if (!newPoint) {
goto error;
}
if (newPoint->equalTest == next->equalTest) {
// only increment i if the next point was reached
++i;
}
prev = newPoint;
}
stackMallocFree(surfaceBuilder.additionalEdges);
stackMallocFree(surfaceBuilder.additionalVertices);
return NULL;
error:
stackMallocFree(surfaceBuilder.additionalEdges);
stackMallocFree(surfaceBuilder.additionalVertices);
return NULL;
}
void portalSurface2DPoint(struct PortalSurface* surface, struct Vector3* at, struct Vector2s16* output) {