Massive refactor

This commit is contained in:
jaburns
2020-10-27 11:07:42 -06:00
parent 48ab192e17
commit fcb6b5b431
85 changed files with 207 additions and 168 deletions
+415
View File
@@ -0,0 +1,415 @@
// CUSTOM/PATCH
#include "../shim.h"
#include "surface_collision.h"
#include "../include/surface_terrains.h"
#include "../../load_surfaces.h"
/**
* Iterate through the list of ceilings and find the first ceiling over a given point.
*/
static struct Surface *find_ceil_from_list( s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
struct Surface *ceil = NULL;
ceil = NULL;
// Stay in this loop until out of ceilings.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y >= -0.01f ) continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
z2 = surf->vertex2[2];
x2 = surf->vertex2[0];
// Checking if point is in bounds of the triangle laterally.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) > 0) {
continue;
}
// Slight optimization by checking these later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) > 0) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) > 0) {
continue;
}
// // Determine if checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera != 0) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// }
// // Ignore camera only surfaces.
// else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// continue;
// }
{
f32 nx = surf->normal.x;
f32 ny = surf->normal.y;
f32 nz = surf->normal.z;
f32 oo = surf->originOffset;
f32 height;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
continue;
}
// Find the ceil height at the specific point.
height = -(x * nx + nz * z + oo) / ny;
// Checks for ceiling interaction with a 78 unit buffer.
//! (Exposed Ceilings) Because any point above a ceiling counts
// as interacting with a ceiling, ceilings far below can cause
// "invisible walls" that are really just exposed ceilings.
if (y - (height - -78.0f) > 0.0f) {
continue;
}
if( height < *pheight )
{
*pheight = height;
ceil = surf;
}
}
}
//! (Surface Cucking) Since only the first ceil is returned and not the lowest,
// lower ceilings can be "cucked" by higher ceilings.
return ceil;
}
/**
* Iterate through the list of floors and find the first floor under a given point.
*/
static struct Surface *find_floor_from_list( s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
f32 nx, ny, nz;
f32 oo;
f32 height;
struct Surface *floor = NULL;
// Iterate through the list of floors until there are no more floors.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y <= 0.01f ) continue;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
x2 = surf->vertex2[0];
z2 = surf->vertex2[2];
// Check that the point is within the triangle bounds.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 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) {
continue;
}
if ((z3 - z) * (x1 - x3) - (x3 - x) * (z1 - z3) < 0) {
continue;
}
// // Determine if we are checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera != 0) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// }
// // If we are not checking for the camera, ignore camera only floors.
// else if (surf->type == SURFACE_CAMERA_BOUNDARY) {
// 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;
// Checks for floor interaction with a 78 unit buffer.
if (y - (height + -78.0f) < 0.0f) {
continue;
}
if( height > *pheight )
{
*pheight = height;
floor = surf;
}
}
//! (Surface Cucking) Since only the first floor is returned and not the highest,
// higher floors can be "cucked" by lower floors.
return floor;
}
static s32 find_wall_collisions_from_list( struct WallCollisionData *data) {
register struct Surface *surf;
register f32 offset;
register f32 radius = data->radius;
register f32 x = data->x;
register f32 y = data->y + data->offsetY;
register f32 z = data->z;
register f32 px, pz;
register f32 w1, w2, w3;
register f32 y1, y2, y3;
s32 numCols = 0;
// Max collision radius = 200
if (radius > 200.0f) {
radius = 200.0f;
}
// Stay in this loop until out of walls.
int count = loaded_surface_get_count();
for( int i = 0; i < count; ++i ) {
surf = loaded_surface_get_at_index(i);
// Do the check normally done in add_surface_to_cell
if( surf->normal.y < -0.01f || surf->normal.y > 0.01f ) continue;
if( surf->normal.x < -0.707f || surf->normal.x > 0.707f ) {
surf->flags |= SURFACE_FLAG_X_PROJECTION;
}
// Exclude a large number of walls immediately to optimize.
if (y < surf->lowerY || y > surf->upperY) {
continue;
}
offset = surf->normal.x * x + surf->normal.y * y + surf->normal.z * z + surf->originOffset;
if (offset < -radius || offset > radius) {
continue;
}
px = x;
pz = z;
//! (Quantum Tunneling) Due to issues with the vertices walls choose and
// the fact they are floating point, certain floating point positions
// along the seam of two walls may collide with neither wall or both walls.
if (surf->flags & SURFACE_FLAG_X_PROJECTION) {
w1 = -surf->vertex1[2]; w2 = -surf->vertex2[2]; w3 = -surf->vertex3[2];
y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1];
if (surf->normal.x > 0.0f) {
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) > 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) > 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) > 0.0f) {
continue;
}
} else {
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) < 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) < 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) < 0.0f) {
continue;
}
}
} else {
w1 = surf->vertex1[0]; w2 = surf->vertex2[0]; w3 = surf->vertex3[0];
y1 = surf->vertex1[1]; y2 = surf->vertex2[1]; y3 = surf->vertex3[1];
if (surf->normal.z > 0.0f) {
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) > 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) > 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) > 0.0f) {
continue;
}
} else {
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) < 0.0f) {
continue;
}
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) < 0.0f) {
continue;
}
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) < 0.0f) {
continue;
}
}
}
// Determine if checking for the camera or not.
// if (gCheckingSurfaceCollisionsForCamera) {
// if (surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) {
// continue;
// }
// } else {
// // Ignore camera only surfaces.
// if (surf->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 an object can pass through a vanish cap wall, pass through.
// if (gCurrentObject != NULL
// && (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)) {
// continue;
// }
// }
// }
//! (Wall Overlaps) Because this doesn't update the x and z local variables,
// multiple walls can push mario more than is required.
data->x += surf->normal.x * (radius - offset);
data->z += surf->normal.z * (radius - offset);
//! (Unreferenced Walls) Since this only returns the first four walls,
// this can lead to wall interaction being missed. Typically unreferenced walls
// come from only using one wall, however.
if (data->numWalls < 4) {
data->walls[data->numWalls++] = surf;
}
numCols++;
}
return numCols;
}
s32 f32_find_wall_collision(f32 *xPtr, f32 *yPtr, f32 *zPtr, f32 offsetY, f32 radius)
{
struct WallCollisionData collision;
s32 numCollisions = 0;
collision.offsetY = offsetY;
collision.radius = radius;
collision.x = *xPtr;
collision.y = *yPtr;
collision.z = *zPtr;
collision.numWalls = 0;
numCollisions = find_wall_collisions(&collision);
*xPtr = collision.x;
*yPtr = collision.y;
*zPtr = collision.z;
return numCollisions;
}
s32 find_wall_collisions(struct WallCollisionData *colData)
{
s32 numCollisions = 0;
s16 x = colData->x;
s16 z = colData->z;
colData->numWalls = 0;
if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) {
return numCollisions;
}
if (z <= -LEVEL_BOUNDARY_MAX || z >= LEVEL_BOUNDARY_MAX) {
return numCollisions;
}
numCollisions += find_wall_collisions_from_list(colData);
return numCollisions;
}
f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil)
{
f32 height = CELL_HEIGHT_LIMIT;
*pceil = find_ceil_from_list( posX, posY, posZ, &height );
return height;
}
struct FloorGeometry sFloorGeo;
f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometry **floorGeo)
{
struct Surface *floor;
f32 floorHeight = find_floor(xPos, yPos, zPos, &floor);
*floorGeo = NULL;
if (floor != NULL) {
sFloorGeo.normalX = floor->normal.x;
sFloorGeo.normalY = floor->normal.y;
sFloorGeo.normalZ = floor->normal.z;
sFloorGeo.originOffset = floor->originOffset;
*floorGeo = &sFloorGeo;
}
return floorHeight;
}
f32 find_floor_height(f32 x, f32 y, f32 z)
{
f32 height = FLOOR_LOWER_LIMIT;
find_floor_from_list( x, y, z, &height );
return height;
}
f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor)
{
f32 height = FLOOR_LOWER_LIMIT;
*pfloor = find_floor_from_list( xPos, yPos, zPos, &height );
return height;
}
f32 find_water_level(f32 x, f32 z)
{
return -10000.0f;
}
f32 find_poison_gas_level(f32 x, f32 z)
{
return -10000.0f;
}