Clean up surface_collision a bit

This commit is contained in:
Arceveti
2021-09-21 11:59:54 -07:00
parent fba2fb8b27
commit bd9165686d
2 changed files with 97 additions and 160 deletions

View File

@@ -44,9 +44,8 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc
register f32 invDenom;
register f32 v, w;
register f32 margin_radius = (radius - 1.0f);
register TerrainData type = SURFACE_DEFAULT;
s32 numCols = 0;
// #if EXTENDED_BOUNDS_MODE
// const float down_scale = (1.0f / gWorldScale);
// radius *= down_scale;
@@ -55,73 +54,56 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc
// z *= down_scale;
// margin_radius *= down_scale;
// #endif
// Max collision radius = 200
if (radius > 200.0f) {
radius = 200.0f;
}
// Stay in this loop until out of walls.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
surf = surfaceNode->surface;
surfaceNode = surfaceNode->next;
type = surf->type;
// Exclude a large number of walls immediately to optimize.
if (pos[1] < surf->lowerY || pos[1] > surf->upperY) {
continue;
}
offset = (surf->normal.x * pos[0]) + (surf->normal.y * pos[1]) + (surf->normal.z * pos[2]) + surf->originOffset;
if (offset < -radius || offset > radius) {
continue;
}
if ((type == SURFACE_NEW_WATER) || (type == SURFACE_NEW_WATER_BOTTOM)) continue;
// Determine if checking for the camera or not.
if (gCheckingSurfaceCollisionsForCamera) {
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
continue;
}
} else {
// Ignore camera only surfaces.
if (surf->type == SURFACE_CAMERA_BOUNDARY || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
if (type == SURFACE_CAMERA_BOUNDARY) {
continue;
}
// If an object can pass through a vanish cap wall, pass through.
if (surf->type == SURFACE_VANISH_CAP_WALLS) {
if (type == SURFACE_VANISH_CAP_WALLS && gCurrentObject != NULL) {
// If an object can pass through a vanish cap wall, pass through.
if (gCurrentObject != NULL
&& (gCurrentObject->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE)) {
if (gCurrentObject->activeFlags & ACTIVE_FLAG_MOVE_THROUGH_GRATE) {
continue;
}
// If Mario has a vanish cap, pass through the vanish cap wall.
if (gCurrentObject != NULL && gCurrentObject == gMarioObject
&& (gMarioState->flags & MARIO_VANISH_CAP)) {
if (gCurrentObject == gMarioObject && (gMarioState->flags & MARIO_VANISH_CAP)) {
continue;
}
}
}
v0[0] = (f32)(surf->vertex2[0] - surf->vertex1[0]);
v0[1] = (f32)(surf->vertex2[1] - surf->vertex1[1]);
v0[2] = (f32)(surf->vertex2[2] - surf->vertex1[2]);
v1[0] = (f32)(surf->vertex3[0] - surf->vertex1[0]);
v1[1] = (f32)(surf->vertex3[1] - surf->vertex1[1]);
v1[2] = (f32)(surf->vertex3[2] - surf->vertex1[2]);
v2[0] = pos[0] - (f32)surf->vertex1[0];
v2[1] = pos[1] - (f32)surf->vertex1[1];
v2[2] = pos[2] - (f32)surf->vertex1[2];
if (pos[1] < surf->lowerY || pos[1] > surf->upperY) {
continue;
}
// Dot of normal and pos, + origin offset
offset = (surf->normal.x * pos[0]) + (surf->normal.y * pos[1]) + (surf->normal.z * pos[2]) + surf->originOffset;
if (offset < -radius || offset > radius) {
continue;
}
vec3_diff(v0, surf->vertex2, surf->vertex1);
vec3_diff(v1, surf->vertex3, surf->vertex1);
vec3_diff(v2, pos, surf->vertex1);
// Face
d00 = (v0[0] * v0[0]) + (v0[1] * v0[1]) + (v0[2] * v0[2]);
d01 = (v0[0] * v1[0]) + (v0[1] * v1[1]) + (v0[2] * v1[2]);
d11 = (v1[0] * v1[0]) + (v1[1] * v1[1]) + (v1[2] * v1[2]);
d20 = (v2[0] * v0[0]) + (v2[1] * v0[1]) + (v2[2] * v0[2]);
d21 = (v2[0] * v1[0]) + (v2[1] * v1[1]) + (v2[2] * v1[2]);
d00 = vec3_dot(v0, v0);
d01 = vec3_dot(v0, v1);
d11 = vec3_dot(v1, v1);
d20 = vec3_dot(v2, v0);
d21 = vec3_dot(v2, v1);
invDenom = 1.0f / ((d00 * d11) - (d01 * d01));
v = ((d11 * d20) - (d01 * d21)) * invDenom;
if (v < 0.0f || v > 1.0f) {
@@ -134,22 +116,14 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc
pos[0] += surf->normal.x * (radius - offset);
pos[2] += surf->normal.z * (radius - offset);
goto hasCollision;
edge_1_2:
if (offset < 0) continue;
CALC_OFFSET(v0, goto edge_1_3);
edge_1_3:
CALC_OFFSET(v1, goto edge_2_3);
edge_2_3:
// Edge 2-3
v1[0] = (f32)(surf->vertex3[0] - surf->vertex2[0]);
v1[1] = (f32)(surf->vertex3[1] - surf->vertex2[1]);
v1[2] = (f32)(surf->vertex3[2] - surf->vertex2[2]);
v2[0] = pos[0] - (f32)surf->vertex2[0];
v2[1] = pos[1] - (f32)surf->vertex2[1];
v2[2] = pos[2] - (f32)surf->vertex2[2];
vec3_diff(v1, surf->vertex3, surf->vertex2);
vec3_diff(v2, pos, surf->vertex2);
CALC_OFFSET(v1, continue);
check_collision:
invDenom = offset / invDenom;
@@ -166,19 +140,15 @@ static s32 find_wall_collisions_from_list(struct SurfaceNode *surfaceNode, struc
if (data->numWalls < MAX_REFEREMCED_WALLS) {
data->walls[data->numWalls++] = surf;
}
numCols++;
}
// #if EXTENDED_BOUNDS_MODE
// x *= gWorldScale;
// y *= gWorldScale;
// z *= gWorldScale;
// #endif
data->x = pos[0];
data->z = pos[2];
return numCols;
}
@@ -222,10 +192,7 @@ s32 find_wall_collisions(struct WallCollisionData *colData) {
colData->numWalls = 0;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
return numCollisions;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
if (is_outside_level_bounds(x, z)) {
return numCollisions;
}
@@ -243,7 +210,7 @@ s32 find_wall_collisions(struct WallCollisionData *colData) {
numCollisions += find_wall_collisions_from_list(node, colData);
// Increment the debug tracker.
gNumCalls.wall += 1;
gNumCalls.wall++;
#if PUPPYPRINT_DEBUG
collisionTime[perfIteration] += osGetTime()-first;
@@ -286,64 +253,59 @@ void add_ceil_margin(s32 *x, s32 *z, Vec3s target1, Vec3s target2, f32 margin) {
* Iterate through the list of ceilings and find the first ceiling over a given point.
*/
static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
s32 x1, z1, x2, z2, x3, z3;
f32 nx, ny, nz, oo, height;
const f32 margin = 1.5f;
register struct Surface *surf;
Vec3i vx, vz;
f32 height;
struct Surface *ceil = NULL;
*pheight = CELL_HEIGHT_LIMIT;
// Stay in this loop until out of ceilings.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
surfaceNode = surfaceNode->next;
if (y > surf->upperY)
if (y > surf->upperY) {
continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
if (surf->type != SURFACE_HANGABLE) {
add_ceil_margin(&x1, &z1, surf->vertex2, surf->vertex3, margin);
}
z2 = surf->vertex2[2];
x2 = surf->vertex2[0];
vx[0] = surf->vertex1[0];
vz[0] = surf->vertex1[2];
if (surf->type != SURFACE_HANGABLE) {
add_ceil_margin(&vx[0], &vz[0], surf->vertex2, surf->vertex3, margin);
}
vx[1] = surf->vertex2[0];
vz[1] = surf->vertex2[2];
if (surf->type != SURFACE_HANGABLE) {
add_ceil_margin(&x2, &z2, surf->vertex3, surf->vertex1, margin);
add_ceil_margin(&vx[1], &vz[1], surf->vertex3, surf->vertex1, margin);
}
// Checking if point is in bounds of the triangle laterally.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) > 0) {
if ((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0]) > 0) {
continue;
}
// Slight optimization by checking these later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
vx[2] = surf->vertex3[0];
vz[2] = surf->vertex3[2];
if (surf->type != SURFACE_HANGABLE) {
add_ceil_margin(&x3, &z3, surf->vertex1, surf->vertex2, margin);
add_ceil_margin(&vx[2], &vz[2], surf->vertex1, surf->vertex2, margin);
}
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) > 0) {
if ((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1]) > 0) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) > 0) {
if ((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2]) > 0) {
continue;
}
// Determine if checking for the camera or not.
if (gCheckingSurfaceCollisionsForCamera != 0) {
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
continue;
}
}
// Ignore camera only surfaces.
else if (surf->type == SURFACE_CAMERA_BOUNDARY || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
if (surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
continue;
}
nx = surf->normal.x;
ny = surf->normal.y;
nz = surf->normal.z;
oo = surf->originOffset;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
if (gCheckingSurfaceCollisionsForCamera) {
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
continue;
}
} else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// Ignore camera only surfaces.
continue;
}
// Find the ceil height at the specific point.
height = -(x * nx + nz * z + oo) / ny;
height = get_surface_height_at_location(x, z, surf);
if (height > *pheight) {
continue;
}
@@ -382,10 +344,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) {
z = posZ;
*pceil = NULL;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
return height;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
if (is_outside_level_bounds(x, z)) {
return height;
}
@@ -409,7 +368,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) {
*pceil = ceil;
// Increment the debug tracker.
gNumCalls.ceil += 1;
gNumCalls.ceil++;
#if PUPPYPRINT_DEBUG
collisionTime[perfIteration] += osGetTime()-first;
@@ -436,31 +395,32 @@ f32 unused_obj_find_floor_height(struct Object *obj) {
*/
static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
f32 nx, ny, nz, oo, height;
register Vec3i vx, vz;
f32 height;
struct Surface *floor = NULL;
*pheight = FLOOR_LOWER_LIMIT;
// Iterate through the list of floors until there are no more floors.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
surfaceNode = surfaceNode->next;
if (y < surf->lowerY - 30)
if (y < surf->lowerY - 30) {
continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
x2 = surf->vertex2[0];
z2 = surf->vertex2[2];
}
vx[0] = surf->vertex1[0];
vz[0] = surf->vertex1[2];
vx[1] = surf->vertex2[0];
vz[1] = surf->vertex2[2];
// Check that the point is within the triangle bounds.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) {
if ((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0]) < 0) {
continue;
}
// To slightly save on computation time, set this later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) {
vx[2] = surf->vertex3[0];
vz[2] = surf->vertex3[2];
if ((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1]) < 0) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) < 0) {
if ((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2]) < 0) {
continue;
}
// Determine if we are checking for the camera or not.
@@ -468,21 +428,12 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION || surf->type == SURFACE_NEW_WATER || surf->type == SURFACE_NEW_WATER_BOTTOM) {
continue;
}
}
// If we are not checking for the camera, ignore camera only floors.
else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
} else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// If we are not checking for the camera, ignore camera only floors.
continue;
}
nx = surf->normal.x;
ny = surf->normal.y;
nz = surf->normal.z;
oo = surf->originOffset;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
continue;
}
// Find the height of the floor at a given location.
height = -(x * nx + nz * z + oo) / ny;
height = get_surface_height_at_location(x, z, surf);
if (height < *pheight) {
continue;
}
@@ -501,33 +452,23 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
static s16 check_within_triangle_bounds(s32 x, s32 z, struct Surface *surf) {
register s32 x1, z1, x2, z2, x3, z3;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
x2 = surf->vertex2[0];
z2 = surf->vertex2[2];
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) return FALSE;
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) return FALSE;
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) < 0) return FALSE;
register Vec3i vx, vz;
vx[0] = surf->vertex1[0];
vz[0] = surf->vertex1[2];
vx[1] = surf->vertex2[0];
vz[1] = surf->vertex2[2];
if ((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0]) < 0) return FALSE;
vx[2] = surf->vertex3[0];
vz[2] = surf->vertex3[2];
if ((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1]) < 0) return FALSE;
if ((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2]) < 0) return FALSE;
return TRUE;
}
// Find the height of the floor at a given location
static f32 get_floor_height_at_location(s32 x, s32 z, struct Surface *surf) {
return -(x * surf->normal.x + surf->normal.z * z + surf->originOffset) / surf->normal.y;
}
/**
* Iterate through the list of water floors and find the first water floor under a given point.
*/
struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z,
s32 *pheight) {
struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, s32 *pheight) {
register struct Surface *surf;
struct Surface *floor = NULL;
struct SurfaceNode *topSurfaceNode = surfaceNode;
@@ -543,7 +484,7 @@ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32
if (surf->type != SURFACE_NEW_WATER_BOTTOM || !check_within_triangle_bounds(x, z, surf)) continue;
curBottomHeight = get_floor_height_at_location(x, z, surf);
curBottomHeight = get_surface_height_at_location(x, z, surf);
if (curBottomHeight < y - 78.0f) continue;
if (curBottomHeight >= y - 78.0f) bottomHeight = curBottomHeight;
@@ -557,7 +498,7 @@ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32
if (surf->type == SURFACE_NEW_WATER_BOTTOM || !check_within_triangle_bounds(x, z, surf)) continue;
curHeight = get_floor_height_at_location(x, z, surf);
curHeight = get_surface_height_at_location(x, z, surf);
if (bottomHeight != FLOOR_LOWER_LIMIT && curHeight > bottomHeight) continue;
@@ -632,13 +573,7 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
*pfloor = NULL;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
#if PUPPYPRINT_DEBUG
collisionTime[perfIteration] += osGetTime()-first;
#endif
return height;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
if (is_outside_level_bounds(x, z)) {
#if PUPPYPRINT_DEBUG
collisionTime[perfIteration] += osGetTime()-first;
#endif
@@ -675,7 +610,7 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
// If a floor was missed, increment the debug counter.
if (floor == NULL) {
gNumFindFloorMisses += 1;
gNumFindFloorMisses++;
}
if (dynamicHeight > height) {
@@ -686,7 +621,7 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) {
*pfloor = floor;
// Increment the debug tracker.
gNumCalls.floor += 1;
gNumCalls.floor++;
#if PUPPYPRINT_DEBUG
collisionTime[perfIteration] += osGetTime()-first;
@@ -710,10 +645,7 @@ s32 find_water_floor(s32 xPos, s32 yPos, s32 zPos, struct Surface **pfloor) {
s32 y = yPos;
s32 z = zPos;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
return height;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
if (is_outside_level_bounds(x, z)) {
return height;
}

View File

@@ -11,8 +11,13 @@
#define FLOOR_LOWER_LIMIT -11000
#define FLOOR_LOWER_LIMIT_MISC (FLOOR_LOWER_LIMIT + 1000)
// same as FLOOR_LOWER_LIMIT_MISC, explicitly for shadow.c
// It doesn't match if ".0" is removed or ".f" is added
#define FLOOR_LOWER_LIMIT_SHADOW (FLOOR_LOWER_LIMIT + 1000.0)
#define FLOOR_LOWER_LIMIT_SHADOW (FLOOR_LOWER_LIMIT + 1000)
#define is_outside_level_bounds(x, z) (((x) <= -LEVEL_BOUNDARY_MAX) || ((x) >= LEVEL_BOUNDARY_MAX) || ((z) <= -LEVEL_BOUNDARY_MAX) || ((z) >= LEVEL_BOUNDARY_MAX))
#define get_surface_height_at_location(x, z, surf) (-((x) * (surf)->normal.x + (surf)->normal.z * (z) + (surf)->originOffset) / (surf)->normal.y);
#define SURFACE_YAW(s) (atan2s(((s)->normal.z), ((s)->normal.x)))
struct WallCollisionData
{