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>
// 0 = disable, 1 = record, 2 = playback
#define CONTROLLER_LOG_CONTROLLER_DATA 0
#define CONTROLLER_LOG_CONTROLLER_DATA 2
#if CONTROLLER_LOG_CONTROLLER_DATA
#include "../debugger/serial.h"

View file

@ -172,6 +172,7 @@ int portalSurfaceCutNewHole(struct Portal* portal, int portalIndex) {
struct PortalSurface newSurface;
if (!portalSurfacePokeHole(currentSurface, scaledLoop, &newSurface)) {
portalSurfacePokeHole(currentSurface, scaledLoop, &newSurface);
return 0;
}
@ -180,10 +181,26 @@ int portalSurfaceCutNewHole(struct Portal* portal, int portalIndex) {
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) {
if ((portals[1].flags & PortalFlagsNeedsNewHole) != 0 || (
portals[0].portalSurfaceIndex == portals[1].portalSurfaceIndex && (portals[0].flags & PortalFlagsNeedsNewHole) != 0
)) {
if ((portals[1].flags & PortalFlagsNeedsNewHole) != 0 || portalNeedsToRemoveSecondPortal(portals)) {
portalSurfaceRevert(1);
portals[1].flags |= PortalFlagsNeedsNewHole;
}

View file

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

View file

@ -14,12 +14,10 @@
#define NO_EDGE_CONNECTION 0xFF
struct SurfaceEdge {
u8 aIndex;
u8 bIndex;
u8 pointIndex;
u8 nextEdge;
u8 prevEdge;
u8 nextEdgeReverse;
u8 prevEdgeReverse;
u8 reverseEdge;
};
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);
void portalSurfaceRevert(int portalIndex);
void portalSurfaceCheckCleanupQueue();
int portalSurfaceGetSurfaceIndex(int portalIndex);
#endif

View file

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

View file

@ -5,32 +5,6 @@
#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 {
SurfaceEdgeFlagsUsed = (1 << 0),
SurfaceEdgeFlagsTriangulated = (1 << 1),
@ -49,12 +23,12 @@ struct PortalSurfaceBuilder {
u8* isLoopEdge;
u8* edgeFlags;
struct OriginalEdgeMapping* originalEdgeIndex;
u8* originalEdgeIndex;
struct SurfaceEdgeWithSide edgeOnSearchLoop;
u8 edgeOnSearchLoop;
union {
// set when hasEdge is true
struct SurfaceEdgeWithSide cuttingEdge;
u8 cuttingEdge;
// set when hasEdge is false
int startingPoint;
};
@ -65,11 +39,11 @@ struct PortalSurfaceBuilder {
};
int portalSurfacePokeHole(struct PortalSurface* surface, struct Vector2s16* loop, struct PortalSurface* result);
int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value);
void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge, enum SurfaceEdgeFlags value);
int portalSurfaceHasFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value);
void portalSurfaceSetFlag(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex, enum SurfaceEdgeFlags value);
struct SurfaceEdge* portalSurfaceGetEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
void portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* nextEdge);
void portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* currentEdge, struct SurfaceEdgeWithSide* prevEdge);
int portalSurfaceNextEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
int portalSurfacePrevEdge(struct PortalSurfaceBuilder* surfaceBuilder, int edgeIndex);
#endif

View file

@ -4,43 +4,37 @@
#define GFX_VERTEX_CACHE_SIZE 32
void gfxBuilderFillTriangle(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder, struct SurfaceEdgeWithSide* edge) {
struct SurfaceEdgeWithSide nextEdge;
struct SurfaceEdgeWithSide prevEdge;
portalSurfaceNextEdge(surfaceBuilder, edge, &nextEdge);
portalSurfacePrevEdge(surfaceBuilder, edge, &prevEdge);
void gfxBuilderFillTriangle(struct GfxBuilderState* gfxBuilder, struct PortalSurfaceBuilder* surfaceBuilder, int edge) {
int nextEdge = portalSurfaceNextEdge(surfaceBuilder, edge);
int prevEdge = portalSurfacePrevEdge(surfaceBuilder, edge);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge->edgeIndex);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge.edgeIndex);
struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevEdge.edgeIndex);
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge);
struct SurfaceEdge* nextEdgePtr = portalSurfaceGetEdge(surfaceBuilder, nextEdge);
struct SurfaceEdge* prevEdgePtr = portalSurfaceGetEdge(surfaceBuilder, prevEdge);
portalSurfaceSetFlag(surfaceBuilder, edge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, &nextEdge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, &prevEdge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, nextEdge, SurfaceEdgeFlagsFilled);
portalSurfaceSetFlag(surfaceBuilder, prevEdge, SurfaceEdgeFlagsFilled);
struct GfxTraingleIndices* triangle = &gfxBuilder->triangles[gfxBuilder->triangleCount];
triangle->indices[0] = SB_GET_CURRENT_POINT(edgePtr, edge->isReverse);
triangle->indices[1] = SB_GET_CURRENT_POINT(nextEdgePtr, nextEdge.isReverse);
triangle->indices[2] = SB_GET_CURRENT_POINT(prevEdgePtr, prevEdge.isReverse);
triangle->indices[0] = edgePtr->pointIndex;
triangle->indices[1] = nextEdgePtr->pointIndex;
triangle->indices[2] = prevEdgePtr->pointIndex;
++gfxBuilder->triangleCount;
}
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) {
struct SurfaceEdge* edgePtr = portalSurfaceGetEdge(surfaceBuilder, edge.edgeIndex);
if (edgePtr->nextEdge == NO_EDGE_CONNECTION) {
continue;
}
for (edge.isReverse = 0; edge.isReverse < 2; ++edge.isReverse) {
if (SB_GET_NEXT_EDGE(edgePtr, edge.isReverse) == NO_EDGE_CONNECTION) {
continue;
}
if (!portalSurfaceHasFlag(surfaceBuilder, &edge, SurfaceEdgeFlagsFilled)) {
gfxBuilderFillTriangle(gfxBuilder, surfaceBuilder, &edge);
}
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, PlayerHasFirstPortalGun);
playerGivePortalGun(&scene->player, PlayerHasSecondPortalGun);
portalInit(&scene->portals[0], 0);
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)
local edge_use_count = {}
local edge_direction = {}
local edge_order = {}
local edges = {}
local edge_for_points = {}
for _, face in pairs(mesh.faces) do
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 key = level_edge_key(current_index, next_index)
table.insert(edge_keys, key)
if (edge_use_count[key]) then
edge_use_count[key] = edge_use_count[key] + 1
table.insert(is_reverse_edge, true)
local edge_index = #edges
local next_index
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
edge_use_count[key] = 1
edge_direction[key] = {
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
next_index = edge_index + 1
prev_index = edge_index - 1
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
-- 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)
return {
vertices = sk_definition_writer.reference_to(vertices, 1),
edges = sk_definition_writer.reference_to(edges, 1),
edgeCount = #edge_order,
edgeCount = #edges,
vertexCount = #vertices,
shouldCleanup = 0,