From 8036e3d60f63e1955b90fd3e91bce4ecbc5ee222 Mon Sep 17 00:00:00 2001 From: James Lambert Date: Mon, 27 Jun 2022 08:25:01 -0600 Subject: [PATCH] Figure out some steps in hole cutting logic --- src/scene/portal_surface.c | 263 +++++++++++++++++++++++++++++-------- 1 file changed, 209 insertions(+), 54 deletions(-) diff --git a/src/scene/portal_surface.c b/src/scene/portal_surface.c index 1938bea..089328a 100644 --- a/src/scene/portal_surface.c +++ b/src/scene/portal_surface.c @@ -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,44 +224,34 @@ 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, ¤tEdge, &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); @@ -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, ¤tEdge, &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, ¤tEdge, &intersectionPoint); + + if (newPointIndex == -1) { + return NULL; + } + } + + if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, ¤tEdge)) { + 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, ¤tEdge, &surfaceBuilder->cuttingEdge); + } else if (intersectionPoint.equalTest == edgeB->equalTest) { + newPointIndex = GET_NEXT_POINT(edge, currentEdge.isReverse); + surfaceBuilder->cuttingEdge = currentEdge; + } else { + int newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, ¤tEdge, &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, ¤tEdge, point)) { + if (portalSurfaceSplitEdge(surfaceBuilder, ¤tEdge, 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) {