refactor portable surfaces

This commit is contained in:
James Lambert 2023-08-27 15:16:08 -06:00
parent a2da66a7dc
commit d51d939ec6
9 changed files with 398 additions and 455 deletions

View file

@ -5,7 +5,7 @@
#include <sched.h> #include <sched.h>
// 0 = disable, 1 = record, 2 = playback // 0 = disable, 1 = record, 2 = playback
#define CONTROLLER_LOG_CONTROLLER_DATA 0 #define CONTROLLER_LOG_CONTROLLER_DATA 2
#if CONTROLLER_LOG_CONTROLLER_DATA #if CONTROLLER_LOG_CONTROLLER_DATA
#include "../debugger/serial.h" #include "../debugger/serial.h"

View file

@ -172,6 +172,7 @@ int portalSurfaceCutNewHole(struct Portal* portal, int portalIndex) {
struct PortalSurface newSurface; struct PortalSurface newSurface;
if (!portalSurfacePokeHole(currentSurface, scaledLoop, &newSurface)) { if (!portalSurfacePokeHole(currentSurface, scaledLoop, &newSurface)) {
portalSurfacePokeHole(currentSurface, scaledLoop, &newSurface);
return 0; return 0;
} }
@ -180,10 +181,26 @@ int portalSurfaceCutNewHole(struct Portal* portal, int portalIndex) {
return 1; return 1;
} }
int portalNeedsToRemoveSecondPortal(struct Portal* portals) {
int secondPortalSurfaceIndex = portalSurfaceGetSurfaceIndex(1);
// second portal isn't placed so no need to temporarily remove it
if (secondPortalSurfaceIndex == -1) {
return 0;
}
// first portal doesn't need to move, so no need to temporarily remove
// second portal
if ((portals[0].flags & PortalFlagsNeedsNewHole) == 0) {
return 0;
}
// only remove second portal if the first one is moving to or from the same surface as the second
return portals[0].portalSurfaceIndex == secondPortalSurfaceIndex || portalSurfaceGetSurfaceIndex(0) == secondPortalSurfaceIndex;
}
void portalCheckForHoles(struct Portal* portals) { void portalCheckForHoles(struct Portal* portals) {
if ((portals[1].flags & PortalFlagsNeedsNewHole) != 0 || ( if ((portals[1].flags & PortalFlagsNeedsNewHole) != 0 || portalNeedsToRemoveSecondPortal(portals)) {
portals[0].portalSurfaceIndex == portals[1].portalSurfaceIndex && (portals[0].flags & PortalFlagsNeedsNewHole) != 0
)) {
portalSurfaceRevert(1); portalSurfaceRevert(1);
portals[1].flags |= PortalFlagsNeedsNewHole; portals[1].flags |= PortalFlagsNeedsNewHole;
} }

View file

@ -53,6 +53,15 @@ void portalSurfaceCleanupQueueInit() {
struct PortalSurfaceReplacement gPortalSurfaceReplacements[2]; struct PortalSurfaceReplacement gPortalSurfaceReplacements[2];
int portalSurfaceGetSurfaceIndex(int portalIndex) {
if (gPortalSurfaceReplacements[portalIndex].flags & PortalSurfaceReplacementFlagsIsEnabled) {
return gPortalSurfaceReplacements[portalIndex].portalSurfaceIndex;
}
return -1;
}
void portalSurfaceReplacementRevert(struct PortalSurfaceReplacement* replacement) { void portalSurfaceReplacementRevert(struct PortalSurfaceReplacement* replacement) {
if (!(replacement->flags & PortalSurfaceReplacementFlagsIsEnabled)) { if (!(replacement->flags & PortalSurfaceReplacementFlagsIsEnabled)) {
return; return;
@ -146,12 +155,12 @@ int portalSurfaceIsInside(struct PortalSurface* surface, struct Transform* porta
struct SurfaceEdge* edge = &surface->edges[i]; struct SurfaceEdge* edge = &surface->edges[i];
// only check edges that are one sided // only check edges that are one sided
if (edge->nextEdgeReverse != NO_EDGE_CONNECTION) { if (edge->reverseEdge != NO_EDGE_CONNECTION) {
continue; continue;
} }
struct Vector2s16 a = surface->vertices[edge->aIndex]; struct Vector2s16 a = surface->vertices[edge->pointIndex];
struct Vector2s16 b = surface->vertices[edge->bIndex]; struct Vector2s16 b = surface->vertices[surface->edges[edge->nextEdge].pointIndex];
if ((portalPosition.x - a.x) * (portalPosition.x - b.x) > 0) { if ((portalPosition.x - a.x) * (portalPosition.x - b.x) > 0) {
// edge is to the left or to the right of the portal // edge is to the left or to the right of the portal
@ -241,12 +250,12 @@ int portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform*
struct SurfaceEdge* edge = &surface->edges[i]; struct SurfaceEdge* edge = &surface->edges[i];
// only check edges that are one sided // only check edges that are one sided
if (edge->nextEdgeReverse != NO_EDGE_CONNECTION) { if (edge->reverseEdge != NO_EDGE_CONNECTION) {
continue; continue;
} }
struct Vector2s16 a = surface->vertices[edge->aIndex]; struct Vector2s16 a = surface->vertices[edge->pointIndex];
struct Vector2s16 b = surface->vertices[edge->bIndex]; struct Vector2s16 b = surface->vertices[surface->edges[edge->nextEdge].pointIndex];
struct Vector2s16 edgeMin; struct Vector2s16 edgeMin;
edgeMin.x = MIN(a.x, b.x); edgeMin.x = MIN(a.x, b.x);

View file

@ -14,12 +14,10 @@
#define NO_EDGE_CONNECTION 0xFF #define NO_EDGE_CONNECTION 0xFF
struct SurfaceEdge { struct SurfaceEdge {
u8 aIndex; u8 pointIndex;
u8 bIndex;
u8 nextEdge; u8 nextEdge;
u8 prevEdge; u8 prevEdge;
u8 nextEdgeReverse; u8 reverseEdge;
u8 prevEdgeReverse;
}; };
struct PortalSurface { struct PortalSurface {
@ -74,6 +72,7 @@ void portalSurfaceInverse(struct PortalSurface* surface, struct Vector2s16* inpu
struct PortalSurface* portalSurfaceReplace(int portalSurfaceIndex, int roomIndex, int portalIndex, struct PortalSurface* with); struct PortalSurface* portalSurfaceReplace(int portalSurfaceIndex, int roomIndex, int portalIndex, struct PortalSurface* with);
void portalSurfaceRevert(int portalIndex); void portalSurfaceRevert(int portalIndex);
void portalSurfaceCheckCleanupQueue(); void portalSurfaceCheckCleanupQueue();
int portalSurfaceGetSurfaceIndex(int portalIndex);
#endif #endif

View file

@ -10,15 +10,16 @@
#define MAX_SEARCH_ITERATIONS 32 #define MAX_SEARCH_ITERATIONS 32
#define ADDITIONAL_EDGE_CAPACITY 64 #define ADDITIONAL_EDGE_CAPACITY 128
#define ADDITIONAL_VERTEX_CAPACITY 32 #define ADDITIONAL_VERTEX_CAPACITY 32
#define VERIFY_INTEGRITY 0 #define VERIFY_INTEGRITY 1
#define VERY_FAR_AWAY 1e15f #define VERY_FAR_AWAY 1e15f
int portalSurfaceFindEnclosingFace(struct PortalSurface* surface, struct Vector2s16* aroundPoint, struct SurfaceEdgeWithSide* output) { int portalSurfaceFindEnclosingFace(struct PortalSurface* surface, struct Vector2s16* aroundPoint) {
float minDistance = VERY_FAR_AWAY; float minDistance = VERY_FAR_AWAY;
int result = -1;
struct Vector2 aroundPointF; struct Vector2 aroundPointF;
@ -27,9 +28,16 @@ int portalSurfaceFindEnclosingFace(struct PortalSurface* surface, struct Vector2
for (int i = 0; i < surface->edgeCount; ++i) { for (int i = 0; i < surface->edgeCount; ++i) {
struct SurfaceEdge* edge = &surface->edges[i]; struct SurfaceEdge* edge = &surface->edges[i];
struct SurfaceEdge* nextEdge = &surface->edges[edge->nextEdge];
struct Vector2s16* as16 = &surface->vertices[edge->aIndex]; if (edge->reverseEdge != -1 && edge->pointIndex > nextEdge->pointIndex) {
struct Vector2s16* bs16 = &surface->vertices[edge->bIndex]; // to avoid redundant calcuations only check
// each pair of vertcies once
continue;
}
struct Vector2s16* as16 = &surface->vertices[edge->pointIndex];
struct Vector2s16* bs16 = &surface->vertices[nextEdge->pointIndex];
struct Vector2 a; struct Vector2 a;
struct Vector2 b; struct Vector2 b;
@ -66,13 +74,11 @@ int portalSurfaceFindEnclosingFace(struct PortalSurface* surface, struct Vector2
if (distSqr < minDistance) { if (distSqr < minDistance) {
minDistance = distSqr; minDistance = distSqr;
result = vector2Cross(&edgeOffset, &pointOffset) < 0.0f ? edge->reverseEdge : i;
output->edgeIndex = i;
output->isReverse = vector2Cross(&edgeOffset, &pointOffset) < 0.0f;
} }
} }
return minDistance != VERY_FAR_AWAY; return result;
} }
struct SurfaceEdge* portalSurfaceGetEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) { struct SurfaceEdge* portalSurfaceGetEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) {
@ -83,48 +89,33 @@ struct Vector2s16* portalSurfaceGetVertex(struct PortalSurfaceBuilder* surfaceBu
return &surfaceBuilder->vertices[vertexIndex]; return &surfaceBuilder->vertices[vertexIndex];
} }
void portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* nextEdge) { int portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) {
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge->edgeIndex); return surfaceBuilder->edges[edgeIndex].nextEdge;
int edgeIndex = currentEdge->edgeIndex;
nextEdge->edgeIndex = SB_GET_NEXT_EDGE(edge, currentEdge->isReverse);
nextEdge->isReverse = portalSurfaceGetEdge(surfaceBuilder, nextEdge->edgeIndex)->prevEdgeReverse == edgeIndex;
} }
void portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* prevEdge) { int portalSurfaceNextPoint(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) {
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge->edgeIndex); return surfaceBuilder->edges[surfaceBuilder->edges[edgeIndex].nextEdge].pointIndex;
int edgeIndex = currentEdge->edgeIndex; }
prevEdge->edgeIndex = SB_GET_PREV_EDGE(edge, currentEdge->isReverse); int portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) {
prevEdge->isReverse = portalSurfaceGetEdge(surfaceBuilder, prevEdge->edgeIndex)->nextEdgeReverse == edgeIndex; return surfaceBuilder->edges[edgeIndex].prevEdge;
}
int portalSurfaceReverseEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex) {
return surfaceBuilder->edges[edgeIndex].reverseEdge;
} }
#if VERIFY_INTEGRITY #if VERIFY_INTEGRITY
int portalSurfaceIsWellFormed(struct PortalSurfaceBuilder* surfaceBuilder) { int portalSurfaceIsWellFormed(struct PortalSurfaceBuilder* surfaceBuilder) {
for (int i = 0; i < surfaceBuilder->currentEdge; ++i) { for (int i = 0; i < surfaceBuilder->currentEdge; ++i) {
struct SurfaceEdgeWithSide current; struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, i);
current.edgeIndex = i; struct SurfaceEdge* next = portalSurfaceGetEdge(surfaceBuilder, edge->nextEdge);
struct SurfaceEdge* prev = portalSurfaceGetEdge(surfaceBuilder, edge->prevEdge);
for (current.isReverse = 0; current.isReverse < 2; ++current.isReverse) { struct SurfaceEdge* reverse = edge->reverseEdge == -1 ? NULL : portalSurfaceGetEdge(surfaceBuilder, edge->reverseEdge);
if (current.isReverse && portalSurfaceGetEdge(surfaceBuilder, i)->nextEdgeReverse == NO_EDGE_CONNECTION) {
break;
}
struct SurfaceEdgeWithSide check; if (next->prevEdge != i || prev->nextEdge != i || (reverse != NULL && reverse->reverseEdge != i)) {
portalSurfaceNextEdge(surfaceBuilder, &current, &check); return 0;
struct SurfaceEdge* checkPtr = portalSurfaceGetEdge(surfaceBuilder, check.edgeIndex);
if (checkPtr->prevEdge != i && checkPtr->prevEdgeReverse != i) {
return 0;
}
portalSurfacePrevEdge(surfaceBuilder, &current, &check);
checkPtr = portalSurfaceGetEdge(surfaceBuilder, check.edgeIndex);
if (checkPtr->nextEdge != i && checkPtr->nextEdgeReverse != i) {
return 0;
}
} }
} }
@ -133,16 +124,15 @@ int portalSurfaceIsWellFormed(struct PortalSurfaceBuilder* surfaceBuilder) {
#endif #endif
int portalSurfacePointInsideFace(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct Vector2s16* point) { int portalSurfacePointInsideFace(struct PortalSurfaceBuilder* surfaceBuilder, int currentEdge, struct Vector2s16* point) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
portalSurfaceNextEdge(surfaceBuilder, currentEdge, &nextEdge);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge->edgeIndex); struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex); struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
struct Vector2s16* corner = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(edgePtr, currentEdge->isReverse)); struct Vector2s16* corner = portalSurfaceGetVertex(surfaceBuilder, nextEdgePtr->pointIndex);
struct Vector2s16* prevPoint = portalSurfaceGetVertex(surfaceBuilder, SB_GET_CURRENT_POINT(edgePtr, currentEdge->isReverse)); struct Vector2s16* prevPoint = portalSurfaceGetVertex(surfaceBuilder, edgePtr->pointIndex);
struct Vector2s16* nextPoint = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(nextEdgePtr, nextEdge.isReverse)); struct Vector2s16* nextPoint = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, nextEdgePtr->nextEdge)->pointIndex);
struct Vector2s16 nextDir; struct Vector2s16 nextDir;
struct Vector2s16 prevDir; struct Vector2s16 prevDir;
@ -156,57 +146,54 @@ int portalSurfacePointInsideFace(struct PortalSurfaceBuilder* surfaceBuilder, st
return vector2s16FallsBetween(&nextDir, &prevDir, &pointDir); return vector2s16FallsBetween(&nextDir, &prevDir, &pointDir);
} }
int portalSurfaceIsEdgeValid(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge) { int portalSurfaceIsEdgeValid(struct PortalSurfaceBuilder* surfaceBuilder, int currentEdge) {
return SB_GET_NEXT_EDGE(portalSurfaceGetEdge(surfaceBuilder, currentEdge->edgeIndex), currentEdge->isReverse) != NO_EDGE_CONNECTION; return surfaceBuilder->edges[currentEdge].nextEdge != NO_EDGE_CONNECTION;
} }
int portalSurfaceNextLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* nextFace) { // Steps to the next surface around a vertex
portalSurfaceNextEdge(surfaceBuilder, currentEdge, nextFace); int portalSurfaceNextLoop(struct PortalSurfaceBuilder* surfaceBuilder, int currentEdge) {
nextFace->isReverse = !nextFace->isReverse; int nextFace = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
nextFace = portalSurfaceReverseEdge(surfaceBuilder, nextFace);
if (portalSurfaceIsEdgeValid(surfaceBuilder, nextFace)) { if (nextFace != NO_EDGE_CONNECTION) {
return 1; return nextFace;
} }
*nextFace = *currentEdge; // hit the edge, the next surface is all the way back
nextFace->isReverse = !nextFace->isReverse; nextFace = portalSurfaceReverseEdge(surfaceBuilder, currentEdge);
int i = 0; int i = 0;
while (i < MAX_SEARCH_ITERATIONS && portalSurfaceIsEdgeValid(surfaceBuilder, nextFace)) { while (i < MAX_SEARCH_ITERATIONS && portalSurfaceReverseEdge(surfaceBuilder, currentEdge) != NO_EDGE_CONNECTION) {
struct SurfaceEdgeWithSide prevFace; currentEdge = portalSurfaceReverseEdge(surfaceBuilder, currentEdge);
portalSurfacePrevEdge(surfaceBuilder, nextFace, &prevFace); currentEdge = portalSurfacePrevEdge(surfaceBuilder, currentEdge);
*nextFace = prevFace;
nextFace->isReverse = !nextFace->isReverse;
++i; ++i;
} }
nextFace->isReverse = !nextFace->isReverse; return i < MAX_SEARCH_ITERATIONS ? currentEdge : NO_EDGE_CONNECTION;
return i < MAX_SEARCH_ITERATIONS;
} }
int portalSurfaceFindCurrentFace(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* forPoint, struct SurfaceEdgeWithSide* edgeToAdjust) { // Find the edge with the associated triangle that contain the point forPoint around a vertex
int portalSurfaceFindCurrentFace(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* forPoint, int currentEdge) {
int i = 0; int i = 0;
while (i < MAX_SEARCH_ITERATIONS && !portalSurfacePointInsideFace(surfaceBuilder, edgeToAdjust, forPoint)) { while (i < MAX_SEARCH_ITERATIONS && !portalSurfacePointInsideFace(surfaceBuilder, currentEdge, forPoint)) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextLoop(surfaceBuilder, currentEdge);
if (!portalSurfaceNextLoop(surfaceBuilder, edgeToAdjust, &nextEdge)) { if (nextEdge == NO_EDGE_CONNECTION) {
return 0; return NO_EDGE_CONNECTION;
} }
if (i != 0 && edgeToAdjust->edgeIndex == surfaceBuilder->edgeOnSearchLoop.edgeIndex) { if (i != 0 && currentEdge == surfaceBuilder->edgeOnSearchLoop) {
// a full loop and no face found // a full loop and no face found
return 0; return NO_EDGE_CONNECTION;
} }
*edgeToAdjust = nextEdge; currentEdge = nextEdge;
++i; ++i;
} }
return i < MAX_SEARCH_ITERATIONS; return i < MAX_SEARCH_ITERATIONS ? currentEdge : NO_EDGE_CONNECTION;
} }
int portalSurfaceFindNextLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* forPoint) { int portalSurfaceFindNextLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* forPoint) {
@ -214,17 +201,19 @@ int portalSurfaceFindNextLoop(struct PortalSurfaceBuilder* surfaceBuilder, struc
return 1; return 1;
} }
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop; int currentEdge = surfaceBuilder->edgeOnSearchLoop;
int nextIndex = SB_GET_NEXT_EDGE(portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->cuttingEdge.edgeIndex), surfaceBuilder->cuttingEdge.isReverse); int nextIndex = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->cuttingEdge)->nextEdge;
// the cutting edge is its own next edge // the cutting edge is its own next edge
// this means edgeOnSearchLoop will already be correct // this means edgeOnSearchLoop will already be correct
if (nextIndex == surfaceBuilder->cuttingEdge.edgeIndex) { if (nextIndex == surfaceBuilder->cuttingEdge) {
return 1; return 1;
} }
if (!portalSurfaceFindCurrentFace(surfaceBuilder, forPoint, &currentEdge)) { currentEdge = portalSurfaceFindCurrentFace(surfaceBuilder, forPoint, currentEdge);
if (currentEdge == NO_EDGE_CONNECTION) {
return 0; return 0;
} }
@ -333,13 +322,13 @@ int portalSurfaceNewVertex(struct PortalSurfaceBuilder* surfaceBuilder, struct V
return newVertexIndex; return newVertexIndex;
} }
int portalSurfaceNewEdge(struct PortalSurfaceBuilder* surfaceBuilder, int isLoopEdge, struct OriginalEdgeMapping* originalEdge) { int portalSurfaceNewEdge(struct PortalSurfaceBuilder* surfaceBuilder, int isLoopEdge, int originalEdge) {
while (surfaceBuilder->checkForEdgeReuse < surfaceBuilder->currentEdge) { while (surfaceBuilder->checkForEdgeReuse < surfaceBuilder->currentEdge) {
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->checkForEdgeReuse); struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->checkForEdgeReuse);
if (edge->nextEdge == NO_EDGE_CONNECTION && edge->nextEdgeReverse == NO_EDGE_CONNECTION) { if (edge->nextEdge == NO_EDGE_CONNECTION) {
surfaceBuilder->isLoopEdge[surfaceBuilder->checkForEdgeReuse] = isLoopEdge; surfaceBuilder->isLoopEdge[surfaceBuilder->checkForEdgeReuse] = isLoopEdge;
surfaceBuilder->originalEdgeIndex[surfaceBuilder->checkForEdgeReuse] = *originalEdge; surfaceBuilder->originalEdgeIndex[surfaceBuilder->checkForEdgeReuse] = originalEdge;
return surfaceBuilder->checkForEdgeReuse; return surfaceBuilder->checkForEdgeReuse;
} }
@ -353,7 +342,7 @@ int portalSurfaceNewEdge(struct PortalSurfaceBuilder* surfaceBuilder, int isLoop
int newEdgeIndex = surfaceBuilder->currentEdge; int newEdgeIndex = surfaceBuilder->currentEdge;
surfaceBuilder->isLoopEdge[surfaceBuilder->currentEdge] = isLoopEdge; surfaceBuilder->isLoopEdge[surfaceBuilder->currentEdge] = isLoopEdge;
surfaceBuilder->originalEdgeIndex[newEdgeIndex] = *originalEdge; surfaceBuilder->originalEdgeIndex[newEdgeIndex] = originalEdge;
++surfaceBuilder->currentEdge; ++surfaceBuilder->currentEdge;
++surfaceBuilder->checkForEdgeReuse; ++surfaceBuilder->checkForEdgeReuse;
return newEdgeIndex; return newEdgeIndex;
@ -399,21 +388,17 @@ void portalSurfaceLerpVtx(struct PortalSurfaceBuilder* surfaceBuilder, int aInde
result->v.cn[3] = (short)mathfLerp(a->v.cn[3], b->v.cn[3], lerp); result->v.cn[3] = (short)mathfLerp(a->v.cn[3], b->v.cn[3], lerp);
} }
void portalSurfaceCalcVertex(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* loopEdge, int resultIndex) { void portalSurfaceCalcVertex(struct PortalSurfaceBuilder* surfaceBuilder, int loopEdge, int resultIndex) {
struct SurfaceEdgeWithSide originalEdge; int originalEdge = surfaceBuilder->originalEdgeIndex[loopEdge];
struct OriginalEdgeMapping originalEdgeMapping = surfaceBuilder->originalEdgeIndex[loopEdge->edgeIndex];
SB_ORIGINAL_EDGE_TO_EDGE_WITH_SIDE(loopEdge->isReverse ? originalEdgeMapping.originalEdgeReverse : originalEdgeMapping.originalEdge, &originalEdge);
struct SurfaceEdge* originalEdgePtr = &surfaceBuilder->original->edges[originalEdge.edgeIndex]; struct SurfaceEdge* originalEdgePtr = &surfaceBuilder->original->edges[originalEdge];
struct SurfaceEdgeWithSide nextEdge; int nextEdge = originalEdgePtr->nextEdge;
nextEdge.edgeIndex = SB_GET_NEXT_EDGE(originalEdgePtr, originalEdge.isReverse);
struct SurfaceEdge* nextEdgePtr = &surfaceBuilder->original->edges[nextEdge.edgeIndex]; struct SurfaceEdge* nextEdgePtr = &surfaceBuilder->original->edges[nextEdge];
nextEdge.isReverse = nextEdgePtr->prevEdgeReverse == originalEdge.edgeIndex;
int aIndex = SB_GET_CURRENT_POINT(originalEdgePtr, originalEdge.isReverse); int aIndex = originalEdgePtr->pointIndex;
int bIndex = SB_GET_NEXT_POINT(originalEdgePtr, originalEdge.isReverse); int bIndex = nextEdgePtr->pointIndex;
int cIndex = SB_GET_NEXT_POINT(nextEdgePtr, nextEdge.isReverse); int cIndex = surfaceBuilder->original->edges[nextEdgePtr->nextEdge].pointIndex;
struct Vector3 barycentericCoords; struct Vector3 barycentericCoords;
@ -445,134 +430,146 @@ void portalSurfaceCalcVertex(struct PortalSurfaceBuilder* surfaceBuilder, struct
result->v.cn[3] = (short)vector3EvalBarycentric1D(&barycentericCoords, a->v.cn[3], b->v.cn[3], c->v.cn[3]); result->v.cn[3] = (short)vector3EvalBarycentric1D(&barycentericCoords, a->v.cn[3], b->v.cn[3], c->v.cn[3]);
} }
int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, struct Vector2s16* point) { int portalSurfaceSplitEdgeWithVertex(struct PortalSurfaceBuilder* surfaceBuilder, int edge, int newVertexIndex) {
struct SurfaceEdge* existingEdge = portalSurfaceGetEdge(surfaceBuilder, edge);
int newEdgeIndex = portalSurfaceNewEdge(surfaceBuilder, 0, surfaceBuilder->originalEdgeIndex[edge]);
if (newEdgeIndex == -1) {
return 0;
}
struct SurfaceEdge* newEdge = portalSurfaceGetEdge(surfaceBuilder, newEdgeIndex);
newEdge->pointIndex = newVertexIndex;
int newReverseEdgeIndex = NO_EDGE_CONNECTION;
struct SurfaceEdge* newReverseEdge = NULL;
struct SurfaceEdge* existingReverseEdge = NULL;
if (existingEdge->reverseEdge != NO_EDGE_CONNECTION) {
newReverseEdgeIndex = portalSurfaceNewEdge(surfaceBuilder, 0, surfaceBuilder->originalEdgeIndex[existingEdge->reverseEdge]);
if (newReverseEdgeIndex == -1) {
return 0;
}
newReverseEdge = portalSurfaceGetEdge(surfaceBuilder, newReverseEdgeIndex);
newEdge->reverseEdge = newReverseEdgeIndex;
newReverseEdge->reverseEdge = newEdgeIndex;
newReverseEdge->pointIndex = newVertexIndex;
existingReverseEdge = portalSurfaceGetEdge(surfaceBuilder, existingEdge->reverseEdge);
} else {
newEdge->reverseEdge = NO_EDGE_CONNECTION;
}
newEdge->nextEdge = existingEdge->nextEdge;
newEdge->prevEdge = edge;
existingEdge->nextEdge = newEdgeIndex;
portalSurfaceGetEdge(surfaceBuilder, newEdge->nextEdge)->prevEdge = newEdgeIndex;
if (newReverseEdge) {
newReverseEdge->nextEdge = existingReverseEdge->nextEdge;
newReverseEdge->prevEdge = existingEdge->reverseEdge;
existingReverseEdge->nextEdge = newReverseEdgeIndex;
portalSurfaceGetEdge(surfaceBuilder, newReverseEdge->nextEdge)->prevEdge = newReverseEdgeIndex;
}
return 1;
}
int portalSurfaceSplitEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edge, struct Vector2s16* point) {
int newVertexIndex = portalSurfaceNewVertex(surfaceBuilder, point); int newVertexIndex = portalSurfaceNewVertex(surfaceBuilder, point);
if (newVertexIndex == -1) { if (newVertexIndex == -1) {
return -1; return -1;
} }
struct SurfaceEdge* existingEdge = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex);
struct SurfaceEdgeWithSide nextEdge; struct SurfaceEdge* existingEdge = portalSurfaceGetEdge(surfaceBuilder, edge);
struct SurfaceEdgeWithSide prevReverseEdge; struct SurfaceEdge* nextExistingEdge = portalSurfaceGetEdge(surfaceBuilder, existingEdge->nextEdge);
int hasReverseEdge = existingEdge->nextEdgeReverse != NO_EDGE_CONNECTION; portalSurfaceLerpVtx(surfaceBuilder, existingEdge->pointIndex, nextExistingEdge->pointIndex, newVertexIndex);
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge); if (!portalSurfaceSplitEdgeWithVertex(surfaceBuilder, edge, newVertexIndex)) {
if (hasReverseEdge) {
prevReverseEdge = *edge;
prevReverseEdge.isReverse = !prevReverseEdge.isReverse;
portalSurfacePrevEdge(surfaceBuilder, &prevReverseEdge, &prevReverseEdge);
}
int newEdgeIndex = portalSurfaceNewEdge(surfaceBuilder, 0, &surfaceBuilder->originalEdgeIndex[edge->edgeIndex]);
if (newEdgeIndex == -1) {
return -1; return -1;
} }
portalSurfaceLerpVtx(surfaceBuilder, SB_GET_CURRENT_POINT(existingEdge, edge->isReverse), SB_GET_NEXT_POINT(existingEdge, edge->isReverse), newVertexIndex);
struct SurfaceEdge* newEdge = portalSurfaceGetEdge(surfaceBuilder, newEdgeIndex);
SB_SET_NEXT_POINT(newEdge, edge->isReverse, SB_GET_NEXT_POINT(existingEdge, edge->isReverse));
SB_SET_CURRENT_POINT(newEdge, edge->isReverse, newVertexIndex);
SB_SET_NEXT_EDGE(newEdge, edge->isReverse, SB_GET_NEXT_EDGE(existingEdge, edge->isReverse));
SB_SET_PREV_EDGE(newEdge, edge->isReverse, edge->edgeIndex);
SB_SET_NEXT_EDGE(newEdge, !edge->isReverse, hasReverseEdge ? edge->edgeIndex : NO_EDGE_CONNECTION);
SB_SET_PREV_EDGE(newEdge, !edge->isReverse, hasReverseEdge ? SB_GET_PREV_EDGE(existingEdge, !edge->isReverse) : NO_EDGE_CONNECTION);
SB_SET_NEXT_POINT(existingEdge, edge->isReverse, newVertexIndex);
SB_SET_NEXT_EDGE(existingEdge, edge->isReverse, newEdgeIndex);
if (hasReverseEdge) {
SB_SET_PREV_EDGE(existingEdge, !edge->isReverse, newEdgeIndex);
}
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex);
SB_SET_PREV_EDGE(nextEdgePtr, nextEdge.isReverse, newEdgeIndex);
if (hasReverseEdge) {
struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevReverseEdge.edgeIndex);
SB_SET_NEXT_EDGE(prevEdgePtr, prevReverseEdge.isReverse, newEdgeIndex);
}
#if VERIFY_INTEGRITY #if VERIFY_INTEGRITY
if (!portalSurfaceIsWellFormed(surfaceBuilder)) { if (!portalSurfaceIsWellFormed(surfaceBuilder)) {
return -1; return 0;
} }
#endif #endif
return newVertexIndex; return newVertexIndex;
} }
int portalSurfaceConnectToPoint(struct PortalSurfaceBuilder* surfaceBuilder, int pointIndex, struct SurfaceEdgeWithSide* edge, int isLoopEdge) { int portalSurfaceConnectToPoint(struct PortalSurfaceBuilder* surfaceBuilder, int pointIndex, int edgeIndex, int isLoopEdge) {
struct OriginalEdgeMapping originalEdge = surfaceBuilder->originalEdgeIndex[surfaceBuilder->edgeOnSearchLoop.edgeIndex]; int originalEdge = surfaceBuilder->originalEdgeIndex[surfaceBuilder->edgeOnSearchLoop];
if (surfaceBuilder->edgeOnSearchLoop.isReverse) { int newEdge = portalSurfaceNewEdge(surfaceBuilder, isLoopEdge, originalEdge);
originalEdge.originalEdge = originalEdge.originalEdgeReverse;
} else { if (newEdge == -1) {
originalEdge.originalEdgeReverse = originalEdge.originalEdge; return 0;
} }
int newEdge = portalSurfaceNewEdge(surfaceBuilder, isLoopEdge, &originalEdge); int newReverseEdge = portalSurfaceNewEdge(surfaceBuilder, isLoopEdge, originalEdge);
if (newEdge == -1) { if (newEdge == -1) {
return 0; return 0;
} }
struct SurfaceEdge* newEdgePtr = portalSurfaceGetEdge(surfaceBuilder, newEdge); struct SurfaceEdge* newEdgePtr = portalSurfaceGetEdge(surfaceBuilder, newEdge);
struct SurfaceEdge* newReverseEdgePtr = portalSurfaceGetEdge(surfaceBuilder, newReverseEdge);
newEdgePtr->reverseEdge = newReverseEdge;
newReverseEdgePtr->reverseEdge = newEdge;
if (surfaceBuilder->hasEdge) { if (surfaceBuilder->hasEdge) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, surfaceBuilder->cuttingEdge);
portalSurfaceNextEdge(surfaceBuilder, &surfaceBuilder->cuttingEdge, &nextEdge);
struct SurfaceEdge* cuttingEdgePtr = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->cuttingEdge.edgeIndex); struct SurfaceEdge* cuttingEdgePtr = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->cuttingEdge);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex); struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
newEdgePtr->aIndex = SB_GET_NEXT_POINT(cuttingEdgePtr, surfaceBuilder->cuttingEdge.isReverse); newEdgePtr->pointIndex = nextEdgePtr->pointIndex;
newEdgePtr->prevEdge = surfaceBuilder->cuttingEdge.edgeIndex; newEdgePtr->prevEdge = surfaceBuilder->cuttingEdge;
newEdgePtr->nextEdgeReverse = nextEdge.edgeIndex; newReverseEdgePtr->nextEdge = nextEdge;
SB_SET_NEXT_EDGE(cuttingEdgePtr, surfaceBuilder->cuttingEdge.isReverse, newEdge); cuttingEdgePtr->nextEdge = newEdge;
SB_SET_PREV_EDGE(nextEdgePtr, nextEdge.isReverse, newEdge); nextEdgePtr->prevEdge = newReverseEdge;
} else { } else {
newEdgePtr->prevEdge = newEdge; newEdgePtr->prevEdge = newReverseEdge;
newEdgePtr->nextEdgeReverse = newEdge; newReverseEdgePtr->nextEdge = newEdge;
newEdgePtr->aIndex = surfaceBuilder->startingPoint; newEdgePtr->pointIndex = surfaceBuilder->startingPoint;
} }
newEdgePtr->bIndex = pointIndex; newReverseEdgePtr->pointIndex = pointIndex;
if (edge) { if (edgeIndex != NO_EDGE_CONNECTION) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, edgeIndex);
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex); struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edgeIndex);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex); struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
newEdgePtr->nextEdge = nextEdge.edgeIndex; newEdgePtr->nextEdge = nextEdge;
newEdgePtr->prevEdgeReverse = edge->edgeIndex; newReverseEdgePtr->prevEdge = edgeIndex;
SB_SET_NEXT_EDGE(edgePtr, edge->isReverse, newEdge); edgePtr->nextEdge = newReverseEdge;
SB_SET_PREV_EDGE(nextEdgePtr, nextEdge.isReverse, newEdge); nextEdgePtr->prevEdge = newEdge;
} else { } else {
newEdgePtr->nextEdge = newEdge; newEdgePtr->nextEdge = newReverseEdge;
newEdgePtr->prevEdgeReverse = newEdge; newReverseEdgePtr->prevEdge = newEdge;
} }
surfaceBuilder->hasEdge = 1; surfaceBuilder->hasEdge = 1;
surfaceBuilder->cuttingEdge.edgeIndex = newEdge; surfaceBuilder->cuttingEdge = newEdge;
surfaceBuilder->cuttingEdge.isReverse = 0;
#if VERIFY_INTEGRITY #if VERIFY_INTEGRITY
if (!portalSurfaceIsWellFormed(surfaceBuilder)) { if (!portalSurfaceIsWellFormed(surfaceBuilder)) {
return -1; return 0;
} }
#endif #endif
@ -582,7 +579,7 @@ int portalSurfaceConnectToPoint(struct PortalSurfaceBuilder* surfaceBuilder, int
#define COLLAPSE_DISTANCE 8 #define COLLAPSE_DISTANCE 8
struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* pointA, struct Vector2s16* pointB, int isFinalPoint) { struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* pointA, struct Vector2s16* pointB, int isFinalPoint) {
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop; int currentEdge = surfaceBuilder->edgeOnSearchLoop;
struct Vector2s16 pointDir; struct Vector2s16 pointDir;
vector2s16Sub(pointB, pointA, &pointDir); vector2s16Sub(pointB, pointA, &pointDir);
@ -592,27 +589,24 @@ struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilde
for (iteration = 0; for (iteration = 0;
iteration < MAX_INTERSECT_LOOPS && ( iteration < MAX_INTERSECT_LOOPS && (
iteration == 0 || iteration == 0 ||
currentEdge.edgeIndex != surfaceBuilder->edgeOnSearchLoop.edgeIndex || currentEdge != surfaceBuilder->edgeOnSearchLoop
currentEdge.isReverse != surfaceBuilder->edgeOnSearchLoop.isReverse ); (currentEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge)), ++iteration) {
); portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &currentEdge), ++iteration) {
if (!isFinalPoint && surfaceBuilder->isLoopEdge[currentEdge.edgeIndex]) { if (!isFinalPoint && surfaceBuilder->isLoopEdge[currentEdge]) {
continue; continue;
} }
struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex); struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
struct Vector2s16* edgeA = portalSurfaceGetVertex(surfaceBuilder, SB_GET_CURRENT_POINT(edge, currentEdge.isReverse)); int nextPointIndex = surfaceBuilder->edges[edge->nextEdge].pointIndex;
struct Vector2s16* edgeB = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(edge, currentEdge.isReverse));
struct Vector2s16* edgeA = portalSurfaceGetVertex(surfaceBuilder, edge->pointIndex);
struct Vector2s16* edgeB = portalSurfaceGetVertex(surfaceBuilder, nextPointIndex);
struct Vector2s16 intersectionPoint; struct Vector2s16 intersectionPoint;
enum IntersectionType intersectType = portalSurfaceIntersect(pointA, &pointDir, edgeA, edgeB, &intersectionPoint); enum IntersectionType intersectType = portalSurfaceIntersect(pointA, &pointDir, edgeA, edgeB, &intersectionPoint);
if (intersectionPoint.equalTest == pointA->equalTest) {
continue;
}
if (intersectType == IntersectionTypePoint) { if (intersectType == IntersectionTypePoint) {
int newPointIndex; int newPointIndex;
@ -625,20 +619,28 @@ struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilde
} }
if (intersectionPoint.equalTest == edgeA->equalTest) { if (intersectionPoint.equalTest == edgeA->equalTest) {
newPointIndex = SB_GET_CURRENT_POINT(edge, currentEdge.isReverse); newPointIndex = edge->pointIndex;
portalSurfaceFindCurrentFace(surfaceBuilder, pointA, &currentEdge); currentEdge = portalSurfaceFindCurrentFace(surfaceBuilder, pointA, currentEdge);
if (currentEdge == NO_EDGE_CONNECTION) {
return NULL;
}
} else if (intersectionPoint.equalTest == edgeB->equalTest) { } else if (intersectionPoint.equalTest == edgeB->equalTest) {
newPointIndex = SB_GET_NEXT_POINT(edge, currentEdge.isReverse); newPointIndex = nextPointIndex;
portalSurfaceFindCurrentFace(surfaceBuilder, pointA, &currentEdge); currentEdge = portalSurfaceFindCurrentFace(surfaceBuilder, pointA, currentEdge);
if (currentEdge == NO_EDGE_CONNECTION) {
return NULL;
}
} else { } else {
newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, &intersectionPoint); newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, currentEdge, &intersectionPoint);
if (newPointIndex == -1) { if (newPointIndex == -1) {
return NULL; return NULL;
} }
} }
if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, &currentEdge, 1)) { if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, currentEdge, 1)) {
return NULL; return NULL;
} }
@ -650,13 +652,13 @@ struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilde
int newPointIndex; int newPointIndex;
if (intersectionPoint.equalTest == edgeA->equalTest) { if (intersectionPoint.equalTest == edgeA->equalTest) {
newPointIndex = SB_GET_CURRENT_POINT(edge, currentEdge.isReverse); newPointIndex = edge->pointIndex;
portalSurfacePrevEdge(surfaceBuilder, &currentEdge, &surfaceBuilder->cuttingEdge); surfaceBuilder->cuttingEdge = portalSurfacePrevEdge(surfaceBuilder, currentEdge);
} else if (intersectionPoint.equalTest == edgeB->equalTest) { } else if (intersectionPoint.equalTest == edgeB->equalTest) {
newPointIndex = SB_GET_NEXT_POINT(edge, currentEdge.isReverse); newPointIndex = nextPointIndex;
surfaceBuilder->cuttingEdge = currentEdge; surfaceBuilder->cuttingEdge = currentEdge;
} else { } else {
newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, &intersectionPoint); newPointIndex = portalSurfaceSplitEdge(surfaceBuilder, currentEdge, &intersectionPoint);
if (newPointIndex == -1) { if (newPointIndex == -1) {
return NULL; return NULL;
@ -674,9 +676,9 @@ struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilde
int newPointIndex = portalSurfaceNewVertex(surfaceBuilder, pointB); int newPointIndex = portalSurfaceNewVertex(surfaceBuilder, pointB);
portalSurfaceCalcVertex(surfaceBuilder, &surfaceBuilder->edgeOnSearchLoop, newPointIndex); portalSurfaceCalcVertex(surfaceBuilder, surfaceBuilder->edgeOnSearchLoop, newPointIndex);
if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, NULL, 1)) { if (!portalSurfaceConnectToPoint(surfaceBuilder, newPointIndex, NO_EDGE_CONNECTION, 1)) {
return NULL; return NULL;
} }
@ -684,17 +686,19 @@ struct Vector2s16* portalSurfaceIntersectEdgeWithLoop(struct PortalSurfaceBuilde
} }
int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* point) { int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder, struct Vector2s16* point) {
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->edgeOnSearchLoop; int currentEdge = surfaceBuilder->edgeOnSearchLoop;
struct Vector2s16* edgeA = portalSurfaceGetVertex(surfaceBuilder, SB_GET_CURRENT_POINT(portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex), currentEdge.isReverse)); struct Vector2s16* edgeA = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, currentEdge)->pointIndex);
for (int iteration = 0; iteration < MAX_INTERSECT_LOOPS; ++iteration) { for (int iteration = 0; iteration < MAX_INTERSECT_LOOPS; ++iteration) {
if (iteration > 0 && currentEdge.edgeIndex == surfaceBuilder->edgeOnSearchLoop.edgeIndex && currentEdge.isReverse == surfaceBuilder->edgeOnSearchLoop.isReverse) { if (iteration > 0 && currentEdge == surfaceBuilder->edgeOnSearchLoop) {
// finished searching loop // finished searching loop
break; break;
} }
struct Vector2s16* edgeB = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex), currentEdge.isReverse)); struct SurfaceEdge* edge = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
struct Vector2s16* edgeB = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, edge->nextEdge)->pointIndex);
struct Vector2s16 edgeDir; struct Vector2s16 edgeDir;
vector2s16Sub(edgeB, edgeA, &edgeDir); vector2s16Sub(edgeB, edgeA, &edgeDir);
@ -704,11 +708,11 @@ int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder,
surfaceBuilder->hasConnected = 1; surfaceBuilder->hasConnected = 1;
if (point->equalTest == edgeA->equalTest) { if (point->equalTest == edgeA->equalTest) {
portalSurfacePrevEdge(surfaceBuilder, &currentEdge, &surfaceBuilder->cuttingEdge); surfaceBuilder->cuttingEdge = portalSurfacePrevEdge(surfaceBuilder, currentEdge);
} else if (point->equalTest == edgeB->equalTest) { } else if (point->equalTest == edgeB->equalTest) {
surfaceBuilder->cuttingEdge = currentEdge; surfaceBuilder->cuttingEdge = currentEdge;
} else { } else {
if (portalSurfaceSplitEdge(surfaceBuilder, &currentEdge, point) == -1) { if (portalSurfaceSplitEdge(surfaceBuilder, currentEdge, point) == -1) {
return 0; return 0;
} }
@ -721,34 +725,32 @@ int portalSurfaceFindStartingPoint(struct PortalSurfaceBuilder* surfaceBuilder,
} }
edgeA = edgeB; edgeA = edgeB;
struct SurfaceEdgeWithSide nextEdge; currentEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge);
currentEdge = nextEdge;
} }
surfaceBuilder->hasEdge = 0; surfaceBuilder->hasEdge = 0;
surfaceBuilder->hasConnected = 0; surfaceBuilder->hasConnected = 0;
surfaceBuilder->startingPoint = portalSurfaceNewVertex(surfaceBuilder, point); surfaceBuilder->startingPoint = portalSurfaceNewVertex(surfaceBuilder, point);
portalSurfaceCalcVertex(surfaceBuilder, &surfaceBuilder->edgeOnSearchLoop, surfaceBuilder->startingPoint); portalSurfaceCalcVertex(surfaceBuilder, surfaceBuilder->edgeOnSearchLoop, surfaceBuilder->startingPoint);
return 1; return 1;
} }
int portalSurfaceJoinInnerLoopToOuterLoop(struct PortalSurfaceBuilder* surfaceBuilder) { int portalSurfaceJoinInnerLoopToOuterLoop(struct PortalSurfaceBuilder* surfaceBuilder) {
struct SurfaceEdge* outerLoopEdge = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->edgeOnSearchLoop.edgeIndex); struct SurfaceEdge* outerLoopEdge = portalSurfaceGetEdge(surfaceBuilder, surfaceBuilder->edgeOnSearchLoop);
struct Vector2s16* outerLoopPoint = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(outerLoopEdge, surfaceBuilder->edgeOnSearchLoop.isReverse)); struct Vector2s16* outerLoopPoint = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, outerLoopEdge->nextEdge)->pointIndex);
struct SurfaceEdgeWithSide currentEdge = surfaceBuilder->cuttingEdge; int currentEdge = surfaceBuilder->cuttingEdge;
struct SurfaceEdgeWithSide nextEdge; int nextEdge;
struct SurfaceEdgeWithSide closestEdge; int closestEdge;
int closestDistance = 0x7FFFFFFF; int closestDistance = 0x7FFFFFFF;
while (portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge), nextEdge.edgeIndex != surfaceBuilder->cuttingEdge.edgeIndex) { while ((nextEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge)), nextEdge != surfaceBuilder->cuttingEdge) {
struct Vector2s16* edgePoint = portalSurfaceGetVertex( struct Vector2s16* edgePoint = portalSurfaceGetVertex(
surfaceBuilder, surfaceBuilder,
SB_GET_NEXT_POINT(portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex), currentEdge.isReverse) portalSurfaceNextPoint(surfaceBuilder, currentEdge)
); );
int edgeDistance = vector2s16DistSqr(outerLoopPoint, edgePoint); int edgeDistance = vector2s16DistSqr(outerLoopPoint, edgePoint);
@ -762,42 +764,36 @@ int portalSurfaceJoinInnerLoopToOuterLoop(struct PortalSurfaceBuilder* surfaceBu
} }
surfaceBuilder->cuttingEdge = closestEdge; surfaceBuilder->cuttingEdge = closestEdge;
return portalSurfaceConnectToPoint(surfaceBuilder, SB_GET_NEXT_POINT(outerLoopEdge, surfaceBuilder->edgeOnSearchLoop.isReverse), &surfaceBuilder->edgeOnSearchLoop, 0); return portalSurfaceConnectToPoint(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, outerLoopEdge->nextEdge)->pointIndex, surfaceBuilder->edgeOnSearchLoop, 0);
} }
int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value) { int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value) {
return ((surfaceBuilder->edgeFlags[edge->edgeIndex] & (edge->isReverse ? value << 4 : value))) != 0; return (surfaceBuilder->edgeFlags[edgeIndex] & value) != 0;
} }
void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value) { void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value) {
surfaceBuilder->edgeFlags[edge->edgeIndex] |= edge->isReverse ? value << 4 : value; surfaceBuilder->edgeFlags[edgeIndex] |= value;
} }
void portalSurfaceMarkLoopAsUsed(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edgeOnLoop) { void portalSurfaceMarkLoopAsUsed(struct PortalSurfaceBuilder* surfaceBuilder, int edgeOnLoop) {
struct SurfaceEdgeWithSide currentEdge = *edgeOnLoop; int currentEdge = edgeOnLoop;
int iteration; int iteration;
for (iteration = 0; iteration < MAX_SEARCH_ITERATIONS && (iteration == 0 || currentEdge.edgeIndex != edgeOnLoop->edgeIndex || currentEdge.isReverse != edgeOnLoop->isReverse); ++iteration) { for (iteration = 0; iteration < MAX_SEARCH_ITERATIONS && (iteration == 0 || currentEdge != edgeOnLoop); ++iteration) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge);
portalSurfaceSetFlag(surfaceBuilder, &currentEdge, SurfaceEdgeFlagsUsed); portalSurfaceSetFlag(surfaceBuilder, currentEdge, SurfaceEdgeFlagsUsed);
if (currentEdge.isReverse) { surfaceBuilder->edges[currentEdge].nextEdge = NO_EDGE_CONNECTION;
surfaceBuilder->edges[currentEdge.edgeIndex].nextEdgeReverse = NO_EDGE_CONNECTION; surfaceBuilder->edges[currentEdge].prevEdge = NO_EDGE_CONNECTION;
surfaceBuilder->edges[currentEdge.edgeIndex].prevEdgeReverse = NO_EDGE_CONNECTION;
} else {
surfaceBuilder->edges[currentEdge.edgeIndex].nextEdge = NO_EDGE_CONNECTION;
surfaceBuilder->edges[currentEdge.edgeIndex].prevEdge = NO_EDGE_CONNECTION;
}
struct SurfaceEdge* surfaceEdge = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex); struct SurfaceEdge* surfaceEdge = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
// since this function clears out nextEdge and prevEdge // since this function clears out nextEdge and prevEdge
// portalSurfaceNextEdge will fail after the loop as been // portalSurfaceNextEdge will fail after the loop as been
// marked. If this check fails the loop is finished // marked. If this check fails the loop is finished
if (surfaceEdge->prevEdge != currentEdge.edgeIndex && surfaceEdge->prevEdgeReverse != currentEdge.edgeIndex) { if (surfaceEdge->prevEdge != currentEdge) {
return; return;
} }
@ -808,12 +804,10 @@ void portalSurfaceMarkLoopAsUsed(struct PortalSurfaceBuilder* surfaceBuilder, st
void portalSurfaceMarkHoleAsUsed(struct PortalSurfaceBuilder* surfaceBuilder) { void portalSurfaceMarkHoleAsUsed(struct PortalSurfaceBuilder* surfaceBuilder) {
for (int i = 0; i < surfaceBuilder->currentEdge; ++i) { for (int i = 0; i < surfaceBuilder->currentEdge; ++i) {
if (surfaceBuilder->isLoopEdge[i]) { if (surfaceBuilder->isLoopEdge[i]) {
struct SurfaceEdgeWithSide edgeOnLoop; int reverseEdge = surfaceBuilder->edges[i].reverseEdge;
edgeOnLoop.edgeIndex = i;
edgeOnLoop.isReverse = 1;
if (!portalSurfaceHasFlag(surfaceBuilder, &edgeOnLoop, SurfaceEdgeFlagsUsed)) { if (!portalSurfaceHasFlag(surfaceBuilder, reverseEdge, SurfaceEdgeFlagsUsed)) {
portalSurfaceMarkLoopAsUsed(surfaceBuilder, &edgeOnLoop); portalSurfaceMarkLoopAsUsed(surfaceBuilder, reverseEdge);
} }
} }
} }
@ -823,44 +817,41 @@ void portalSurfaceMarkHoleAsUsed(struct PortalSurfaceBuilder* surfaceBuilder) {
surfaceBuilder->checkForEdgeReuse = 0; surfaceBuilder->checkForEdgeReuse = 0;
} }
int portalSurfaceConnectEdges(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* from, struct SurfaceEdgeWithSide* to, struct SurfaceEdgeWithSide* newEdge) { int portalSurfaceConnectEdges(struct PortalSurfaceBuilder* surfaceBuilder, int from, int to) {
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, to->edgeIndex); struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, to);
surfaceBuilder->cuttingEdge = *from; surfaceBuilder->cuttingEdge = from;
surfaceBuilder->hasEdge = 1; surfaceBuilder->hasEdge = 1;
if (!portalSurfaceConnectToPoint(surfaceBuilder, SB_GET_NEXT_POINT(nextEdgePtr, to->isReverse), to, 0)) { if (!portalSurfaceConnectToPoint(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, nextEdgePtr->nextEdge)->pointIndex, to, 0)) {
return 0; return NO_EDGE_CONNECTION;
} }
*newEdge = surfaceBuilder->cuttingEdge; return surfaceBuilder->cuttingEdge;
return 1;
} }
int portalSurfaceTriangulateLoop(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edgeOnLoop) { int portalSurfaceTriangulateLoop(struct PortalSurfaceBuilder* surfaceBuilder, int edgeOnLoop) {
if (portalSurfaceHasFlag(surfaceBuilder, edgeOnLoop, SurfaceEdgeFlagsTriangulated)) { if (portalSurfaceHasFlag(surfaceBuilder, edgeOnLoop, SurfaceEdgeFlagsTriangulated)) {
return 1; return 1;
} }
struct SurfaceEdgeWithSide currentEdge = *edgeOnLoop; int currentEdge = edgeOnLoop;
int iteration = 0; int iteration = 0;
struct SurfaceEdge* currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex); struct SurfaceEdge* currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
// Find the starting point // Find the starting point
while (!IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, SB_GET_CURRENT_POINT(currentEdgePtr, currentEdge.isReverse)) || IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, SB_GET_NEXT_POINT(currentEdgePtr, currentEdge.isReverse))) { while (!IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, currentEdgePtr->pointIndex) || IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, currentEdgePtr->nextEdge)->pointIndex)) {
++iteration; ++iteration;
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &currentEdge); currentEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex); currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
if (iteration == MAX_SEARCH_ITERATIONS || (currentEdge.edgeIndex == edgeOnLoop->edgeIndex && currentEdge.isReverse == edgeOnLoop->isReverse)) { if (iteration == MAX_SEARCH_ITERATIONS || currentEdge == edgeOnLoop) {
if (iteration == 3) { if (iteration == 3) {
// already a triangle // already a triangle
struct SurfaceEdgeWithSide nextEdge;
struct SurfaceEdgeWithSide prevEdge;
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge); int nextEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
portalSurfacePrevEdge(surfaceBuilder, &currentEdge, &prevEdge); int prevEdge = portalSurfacePrevEdge(surfaceBuilder, currentEdge);
portalSurfaceSetFlag(surfaceBuilder, &currentEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, currentEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &nextEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, nextEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &prevEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, prevEdge, SurfaceEdgeFlagsTriangulated);
return 1; return 1;
} }
@ -870,27 +861,24 @@ int portalSurfaceTriangulateLoop(struct PortalSurfaceBuilder* surfaceBuilder, st
} }
for (iteration = 0; iteration < MAX_SEARCH_ITERATIONS; ++iteration) { for (iteration = 0; iteration < MAX_SEARCH_ITERATIONS; ++iteration) {
currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge.edgeIndex); currentEdgePtr = portalSurfaceGetEdge(surfaceBuilder, currentEdge);
struct Vector2s16* edgePointA = portalSurfaceGetVertex(surfaceBuilder, SB_GET_CURRENT_POINT(currentEdgePtr, currentEdge.isReverse)); struct Vector2s16* edgePointA = portalSurfaceGetVertex(surfaceBuilder, currentEdgePtr->pointIndex);
struct Vector2s16* edgePointB = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(currentEdgePtr, currentEdge.isReverse)); struct Vector2s16* edgePointB = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceGetEdge(surfaceBuilder, currentEdgePtr->nextEdge)->pointIndex);
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, currentEdge);
struct SurfaceEdgeWithSide prevEdge; int prevEdge = portalSurfacePrevEdge(surfaceBuilder, currentEdge);
portalSurfaceNextEdge(surfaceBuilder, &currentEdge, &nextEdge); int prevPointIndex = portalSurfaceGetEdge(surfaceBuilder, prevEdge)->pointIndex;
portalSurfacePrevEdge(surfaceBuilder, &currentEdge, &prevEdge);
struct Vector2s16* nextPoint = portalSurfaceGetVertex(surfaceBuilder, portalSurfaceNextPoint(surfaceBuilder, nextEdge));
int prevPointIndex = SB_GET_CURRENT_POINT(portalSurfaceGetEdge(surfaceBuilder, prevEdge.edgeIndex), prevEdge.isReverse);
struct Vector2s16* nextPoint = portalSurfaceGetVertex(surfaceBuilder, SB_GET_NEXT_POINT(portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex), nextEdge.isReverse));
struct Vector2s16* prevPoint = portalSurfaceGetVertex(surfaceBuilder, prevPointIndex); struct Vector2s16* prevPoint = portalSurfaceGetVertex(surfaceBuilder, prevPointIndex);
// check if finished // check if finished
if (nextPoint == prevPoint) { if (nextPoint == prevPoint) {
portalSurfaceSetFlag(surfaceBuilder, &currentEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, currentEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &nextEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, nextEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &prevEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, prevEdge, SurfaceEdgeFlagsTriangulated);
return 1; return 1;
} }
@ -902,49 +890,47 @@ int portalSurfaceTriangulateLoop(struct PortalSurfaceBuilder* surfaceBuilder, st
vector2s16Sub(nextPoint, edgePointB, &nextEdgeDir); vector2s16Sub(nextPoint, edgePointB, &nextEdgeDir);
vector2s16Sub(edgePointB, prevPoint, &prevEdgeDir); vector2s16Sub(edgePointB, prevPoint, &prevEdgeDir);
struct SurfaceEdgeWithSide nextCurrentEdge; int nextCurrentEdge;
if (IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, prevPointIndex) && vector2s16Cross(&prevEdgeDir, &nextEdgeDir) > vector2s16Cross(&edgeDir, &nextEdgeDir)) { if (IS_ORIGINAL_VERTEX_INDEX(surfaceBuilder, prevPointIndex) && vector2s16Cross(&prevEdgeDir, &nextEdgeDir) > vector2s16Cross(&edgeDir, &nextEdgeDir)) {
struct SurfaceEdgeWithSide prevPrevEdge; int prevPrevEdge = portalSurfacePrevEdge(surfaceBuilder, prevEdge);
portalSurfacePrevEdge(surfaceBuilder, &prevEdge, &prevPrevEdge);
if (!portalSurfaceConnectEdges(surfaceBuilder, &prevPrevEdge, &currentEdge, &nextCurrentEdge)) { nextCurrentEdge = portalSurfaceConnectEdges(surfaceBuilder, prevPrevEdge, currentEdge);
if (nextCurrentEdge == NO_EDGE_CONNECTION) {
return 0; return 0;
} }
portalSurfaceSetFlag(surfaceBuilder, &prevEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, prevEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &currentEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, currentEdge, SurfaceEdgeFlagsTriangulated);
} else { } else {
if (!portalSurfaceConnectEdges(surfaceBuilder, &prevEdge, &nextEdge, &nextCurrentEdge)) { nextCurrentEdge = portalSurfaceConnectEdges(surfaceBuilder, prevEdge, nextEdge);
if (nextCurrentEdge == NO_EDGE_CONNECTION) {
return 0; return 0;
} }
portalSurfaceSetFlag(surfaceBuilder, &currentEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, currentEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, &nextEdge, SurfaceEdgeFlagsTriangulated); portalSurfaceSetFlag(surfaceBuilder, nextEdge, SurfaceEdgeFlagsTriangulated);
} }
currentEdge = nextCurrentEdge; currentEdge = nextCurrentEdge;
nextCurrentEdge.isReverse = !nextCurrentEdge.isReverse; nextCurrentEdge = portalSurfaceReverseEdge(surfaceBuilder, nextCurrentEdge);
portalSurfaceSetFlag(surfaceBuilder, &nextCurrentEdge, SurfaceEdgeFlagsTriangulated);
portalSurfaceSetFlag(surfaceBuilder, nextCurrentEdge, SurfaceEdgeFlagsTriangulated);
} }
return 0; return 0;
} }
int portalSurfaceTriangulate(struct PortalSurfaceBuilder* surfaceBuilder) { int portalSurfaceTriangulate(struct PortalSurfaceBuilder* surfaceBuilder) {
struct SurfaceEdgeWithSide edge;
for (int i = 0; i < surfaceBuilder->currentEdge; ++i) { for (int i = 0; i < surfaceBuilder->currentEdge; ++i) {
edge.edgeIndex = i; if (portalSurfaceGetEdge(surfaceBuilder, i)->nextEdge == NO_EDGE_CONNECTION) {
continue;
for (edge.isReverse = 0; edge.isReverse < 2; ++edge.isReverse) { }
if (SB_GET_NEXT_EDGE(portalSurfaceGetEdge(surfaceBuilder, edge.edgeIndex), edge.isReverse) == NO_EDGE_CONNECTION) {
continue;
}
if (!portalSurfaceTriangulateLoop(surfaceBuilder, &edge)) { if (!portalSurfaceTriangulateLoop(surfaceBuilder, i)) {
return 0; return 0;
}
} }
} }
@ -966,11 +952,10 @@ int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop
surfaceBuilder.currentEdge = surface->edgeCount; surfaceBuilder.currentEdge = surface->edgeCount;
surfaceBuilder.checkForEdgeReuse = surface->edgeCount; surfaceBuilder.checkForEdgeReuse = surface->edgeCount;
surfaceBuilder.edgeFlags = stackMalloc(sizeof(u8) * edgeCapacity); surfaceBuilder.edgeFlags = stackMalloc(sizeof(u8) * edgeCapacity);
surfaceBuilder.originalEdgeIndex = stackMalloc(sizeof(struct OriginalEdgeMapping) * edgeCapacity); surfaceBuilder.originalEdgeIndex = stackMalloc(sizeof(u8) * edgeCapacity);
for (int i = 0; i < surface->edgeCount; ++i) { for (int i = 0; i < surface->edgeCount; ++i) {
surfaceBuilder.originalEdgeIndex[i].originalEdge = i; surfaceBuilder.originalEdgeIndex[i] = i;
surfaceBuilder.originalEdgeIndex[i].originalEdgeReverse = i | 0x80;
} }
surfaceBuilder.gfxVertices = stackMalloc(sizeof(Vtx) * (surface->vertexCount + ADDITIONAL_EDGE_CAPACITY)); surfaceBuilder.gfxVertices = stackMalloc(sizeof(Vtx) * (surface->vertexCount + ADDITIONAL_EDGE_CAPACITY));
@ -981,7 +966,9 @@ int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop
struct Vector2s16* prev = &loop[0]; struct Vector2s16* prev = &loop[0];
if (!portalSurfaceFindEnclosingFace(surface, prev, &surfaceBuilder.edgeOnSearchLoop)) { surfaceBuilder.edgeOnSearchLoop = portalSurfaceFindEnclosingFace(surface, prev);
if (surfaceBuilder.edgeOnSearchLoop == -1) {
goto error; goto error;
} }
@ -1011,13 +998,16 @@ int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop
struct SurfaceEdge* firstEdge = portalSurfaceGetEdge(&surfaceBuilder, firstEdgeIndex); struct SurfaceEdge* firstEdge = portalSurfaceGetEdge(&surfaceBuilder, firstEdgeIndex);
struct SurfaceEdge* lastEdge = portalSurfaceGetEdge(&surfaceBuilder, lastEdgeIndex); struct SurfaceEdge* lastEdge = portalSurfaceGetEdge(&surfaceBuilder, lastEdgeIndex);
if (firstEdge->reverseEdge != NO_EDGE_CONNECTION) {
struct SurfaceEdge* firstEdgeReverse = portalSurfaceGetEdge(&surfaceBuilder, firstEdge->reverseEdge);
firstEdgeReverse->nextEdge = lastEdgeIndex;
firstEdgeReverse->pointIndex = firstEdge->pointIndex;
}
firstEdge->prevEdge = lastEdgeIndex; firstEdge->prevEdge = lastEdgeIndex;
firstEdge->nextEdgeReverse = lastEdgeIndex;
lastEdge->nextEdge = firstEdgeIndex; lastEdge->nextEdge = firstEdgeIndex;
lastEdge->prevEdgeReverse = firstEdgeIndex; lastEdge->prevEdge = firstEdgeIndex;
lastEdge->bIndex = firstEdge->aIndex;
--surfaceBuilder.currentVertex; --surfaceBuilder.currentVertex;

View file

@ -5,32 +5,6 @@
#define PORTAL_SURFACE_OVERLAP 0x10000 #define PORTAL_SURFACE_OVERLAP 0x10000
#define SB_GET_NEXT_EDGE(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->nextEdgeReverse : (surfaceEdge)->nextEdge)
#define SB_GET_PREV_EDGE(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->prevEdgeReverse : (surfaceEdge)->prevEdge)
#define SB_GET_CURRENT_POINT(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->bIndex : (surfaceEdge->aIndex))
#define SB_GET_NEXT_POINT(surfaceEdge, isReverse) ((isReverse) ? (surfaceEdge)->aIndex : (surfaceEdge->bIndex))
#define SB_SET_NEXT_EDGE(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->nextEdgeReverse = (value); else (surfaceEdge)->nextEdge = (value); } while (0)
#define SB_SET_PREV_EDGE(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->prevEdgeReverse = (value); else (surfaceEdge)->prevEdge = (value); } while (0)
#define SB_SET_CURRENT_POINT(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->bIndex = (value); else (surfaceEdge)->aIndex = (value); } while (0)
#define SB_SET_NEXT_POINT(surfaceEdge, isReverse, value) do { if (isReverse) (surfaceEdge)->aIndex = (value); else (surfaceEdge)->bIndex = (value); } while (0)
struct SurfaceEdgeWithSide {
int edgeIndex;
int isReverse;
};
#define SB_ORIGINAL_EDGE_TO_EDGE_WITH_SIDE(originalEdge, edge) do { (edge)->edgeIndex = (originalEdge) & 0x7F; (edge)->isReverse = ((originalEdge) & 0x80) != 0; } while (0)
#define SB_PACK_ORIGINALEDGE(edge) (((edge)->edgeIndex & 0x7F) | ((edge)->isReverse) ? 0x80 : 0x00)
struct OriginalEdgeMapping {
u8 originalEdge;
u8 originalEdgeReverse;
};
enum SurfaceEdgeFlags { enum SurfaceEdgeFlags {
SurfaceEdgeFlagsUsed = (1 << 0), SurfaceEdgeFlagsUsed = (1 << 0),
SurfaceEdgeFlagsTriangulated = (1 << 1), SurfaceEdgeFlagsTriangulated = (1 << 1),
@ -49,12 +23,12 @@ struct PortalSurfaceBuilder {
u8* isLoopEdge; u8* isLoopEdge;
u8* edgeFlags; u8* edgeFlags;
struct OriginalEdgeMapping* originalEdgeIndex; u8* originalEdgeIndex;
struct SurfaceEdgeWithSide edgeOnSearchLoop; u8 edgeOnSearchLoop;
union { union {
// set when hasEdge is true // set when hasEdge is true
struct SurfaceEdgeWithSide cuttingEdge; u8 cuttingEdge;
// set when hasEdge is false // set when hasEdge is false
int startingPoint; int startingPoint;
}; };
@ -65,11 +39,11 @@ struct PortalSurfaceBuilder {
}; };
int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop, struct PortalSurface* result); int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop, struct PortalSurface* result);
int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value); int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value);
void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value); void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value);
struct SurfaceEdge* portalSurfaceGetEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex); struct SurfaceEdge* portalSurfaceGetEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
void portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* nextEdge); int portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
void portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* prevEdge); int portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
#endif #endif

View file

@ -4,43 +4,37 @@
#define GFX_VERTEX_CACHE_SIZE 32 #define GFX_VERTEX_CACHE_SIZE 32
void gfxBuilderFillTriangle(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge) { void gfxBuilderFillTriangle(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder, int edge) {
struct SurfaceEdgeWithSide nextEdge; int nextEdge = portalSurfaceNextEdge(surfaceBuilder, edge);
struct SurfaceEdgeWithSide prevEdge; int prevEdge = portalSurfacePrevEdge(surfaceBuilder, edge);
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge);
portalSurfacePrevEdge(surfaceBuilder, edge, &prevEdge);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex); struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex); struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevEdge.edgeIndex); struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevEdge);
portalSurfaceSetFlag(surfaceBuilder, edge, SurfaceEdgeFlagsFilled); portalSurfaceSetFlag(surfaceBuilder, edge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, &nextEdge, SurfaceEdgeFlagsFilled); portalSurfaceSetFlag(surfaceBuilder, nextEdge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, &prevEdge, SurfaceEdgeFlagsFilled); portalSurfaceSetFlag(surfaceBuilder, prevEdge, SurfaceEdgeFlagsFilled);
struct GfxTraingleIndices* triangle = &gfxBuilder->triangles[gfxBuilder->triangleCount]; struct GfxTraingleIndices* triangle = &gfxBuilder->triangles[gfxBuilder->triangleCount];
triangle->indices[0] = SB_GET_CURRENT_POINT(edgePtr, edge->isReverse); triangle->indices[0] = edgePtr->pointIndex;
triangle->indices[1] = SB_GET_CURRENT_POINT(nextEdgePtr, nextEdge.isReverse); triangle->indices[1] = nextEdgePtr->pointIndex;
triangle->indices[2] = SB_GET_CURRENT_POINT(prevEdgePtr, prevEdge.isReverse); triangle->indices[2] = prevEdgePtr->pointIndex;
++gfxBuilder->triangleCount; ++gfxBuilder->triangleCount;
} }
void gfxBuilderCollectTriangles(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder) { void gfxBuilderCollectTriangles(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder) {
struct SurfaceEdgeWithSide edge; for (int edge = 0; edge < surfaceBuilder->currentEdge; ++edge) {
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge);
for (edge.edgeIndex = 0; edge.edgeIndex < surfaceBuilder->currentEdge; ++edge.edgeIndex) { if (edgePtr->nextEdge == NO_EDGE_CONNECTION) {
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge.edgeIndex); continue;
}
for (edge.isReverse = 0; edge.isReverse < 2; ++edge.isReverse) { if (!portalSurfaceHasFlag(surfaceBuilder, edge, SurfaceEdgeFlagsFilled)) {
if (SB_GET_NEXT_EDGE(edgePtr, edge.isReverse) == NO_EDGE_CONNECTION) { gfxBuilderFillTriangle(gfxBuilder, surfaceBuilder, edge);
continue;
}
if (!portalSurfaceHasFlag(surfaceBuilder, &edge, SurfaceEdgeFlagsFilled)) {
gfxBuilderFillTriangle(gfxBuilder, surfaceBuilder, &edge);
}
} }
} }
} }

View file

@ -124,6 +124,9 @@ void sceneInitNoPauseMenu(struct Scene* scene, int mainMenuMode) {
playerGivePortalGun(&scene->player, PlayerHasSecondPortalGun); playerGivePortalGun(&scene->player, PlayerHasSecondPortalGun);
} }
playerGivePortalGun(&scene->player, PlayerHasFirstPortalGun);
playerGivePortalGun(&scene->player, PlayerHasSecondPortalGun);
portalInit(&scene->portals[0], 0); portalInit(&scene->portals[0], 0);
portalInit(&scene->portals[1], PortalFlagsOddParity); portalInit(&scene->portals[1], PortalFlagsOddParity);

View file

@ -72,9 +72,8 @@ local function calculate_portal_single_surface(mesh, mesh_display_list)
sk_definition_writer.add_definition(mesh.name .. '_portal_mesh', 'struct Vector2s16[]', '_geo', vertices) sk_definition_writer.add_definition(mesh.name .. '_portal_mesh', 'struct Vector2s16[]', '_geo', vertices)
local edge_use_count = {} local edges = {}
local edge_direction = {} local edge_for_points = {}
local edge_order = {}
for _, face in pairs(mesh.faces) do for _, face in pairs(mesh.faces) do
local edge_keys = {} local edge_keys = {}
@ -84,92 +83,50 @@ local function calculate_portal_single_surface(mesh, mesh_display_list)
local next_index = face[index_index % #face + 1] local next_index = face[index_index % #face + 1]
local key = level_edge_key(current_index, next_index) local key = level_edge_key(current_index, next_index)
table.insert(edge_keys, key)
if (edge_use_count[key]) then local edge_index = #edges
edge_use_count[key] = edge_use_count[key] + 1 local next_index
table.insert(is_reverse_edge, true) local prev_index
if index_index == 1 then
next_index = edge_index + 1
prev_index = edge_index + #face - 1
elseif index_index == #face then
next_index = edge_index - #face + 1
prev_index = edge_index - 1
else else
edge_use_count[key] = 1 next_index = edge_index + 1
edge_direction[key] = { prev_index = edge_index - 1
a = current_index,
b = next_index,
edge_index = -1,
next_edge_key = -1,
prev_edge_key = -1,
next_edge_reverse_key = -1,
prev_edge_reverse_key = -1,
}
table.insert(is_reverse_edge, false)
table.insert(edge_order, key)
end
end
local prev_key = edge_keys[#edge_keys]
-- connect faces in a loop
for index, key in pairs(edge_keys) do
local next_key = edge_keys[index % #edge_keys + 1]
local edge = edge_direction[key]
if (is_reverse_edge[index]) then
edge.next_edge_reverse_key = next_key
edge.prev_edge_reverse_key = prev_key
else
edge.next_edge_key = next_key
edge.prev_edge_key = prev_key
end end
prev_key = key local edge = {
pointIndex = current_index - 1,
nextEdge = next_index,
prevEdge = prev_index,
reverseEdge = 0xFF
}
table.insert(edges, edge)
if edge_for_points[key] then
local reverseEdge = edges[edge_for_points[key] + 1]
reverseEdge.reverseEdge = edge_index
edge.reverseEdge = edge_for_points[key]
edge_for_points[key] = nil
else
edge_for_points[key] = edge_index
end
end end
end end
-- edges go first
table.sort(edge_order, function(a, b)
local edge_diff = edge_use_count[a] - edge_use_count[b]
if edge_diff ~= 0 then
return edge_diff < 0
end
if edge_direction[a].a ~= edge_direction[b].a then
return edge_direction[a].a < edge_direction[b].a
end
-- this is an attempt to make edges that are near each other
-- show up in memory near each other to improve cache
-- performance
return edge_direction[a].b < edge_direction[b].b
end)
local edge_index = 0
for _, key in pairs(edge_order) do
edge_direction[key].edge_index = edge_index
edge_index = edge_index + 1
end
local edges = {}
for _, key in pairs(edge_order) do
local indices = edge_direction[key];
table.insert(edges, {
indices.a - 1,
indices.b - 1,
get_edge_index(edge_direction, indices.next_edge_key),
get_edge_index(edge_direction, indices.prev_edge_key),
get_edge_index(edge_direction, indices.next_edge_reverse_key),
get_edge_index(edge_direction, indices.prev_edge_reverse_key),
});
end
sk_definition_writer.add_definition(mesh.name .. "_portal_edges", "struct SurfaceEdge[]", "_geo", edges) sk_definition_writer.add_definition(mesh.name .. "_portal_edges", "struct SurfaceEdge[]", "_geo", edges)
return { return {
vertices = sk_definition_writer.reference_to(vertices, 1), vertices = sk_definition_writer.reference_to(vertices, 1),
edges = sk_definition_writer.reference_to(edges, 1), edges = sk_definition_writer.reference_to(edges, 1),
edgeCount = #edge_order, edgeCount = #edges,
vertexCount = #vertices, vertexCount = #vertices,
shouldCleanup = 0, shouldCleanup = 0,