From 5fe1a69f514009d097d665ca37a3e238749bbbc2 Mon Sep 17 00:00:00 2001 From: Arceveti <73617174+Arceveti@users.noreply.github.com> Date: Fri, 15 Oct 2021 11:53:35 -0700 Subject: [PATCH] Slight find_floor/ceil optimization --- src/engine/surface_collision.c | 74 +++++++++++++++++++++------------- src/engine/surface_collision.h | 3 +- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 6b10f7a1b..68240ab54 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -209,15 +209,32 @@ void add_ceil_margin(s32 *x, s32 *z, Vec3s target1, Vec3s target2, f32 margin) { *z += (diff_z * invDenom); } +static s32 check_within_ceil_triangle_bounds(s32 x, s32 z, struct Surface *surf, const f32 margin) { + Vec3i vx, vz; + 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(&vx[1], &vz[1], surf->vertex3, surf->vertex1, margin); + // Checking if point is in bounds of the triangle laterally. + if ((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0]) > 0) return FALSE; + // Slight optimization by checking these later. + vx[2] = surf->vertex3[0]; + vz[2] = surf->vertex3[2]; + if (surf->type != SURFACE_HANGABLE) add_ceil_margin(&vx[2], &vz[2], surf->vertex1, surf->vertex2, margin); + 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; +} + /** * 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) { - const f32 margin = 1.5f; register struct Surface *surf, *ceil = NULL; - Vec3i vx, vz; - f32 height; - s16 type; + register f32 height, ny; + SurfaceType type = SURFACE_DEFAULT; *pheight = CELL_HEIGHT_LIMIT; // Stay in this loop until out of ceilings. while (surfaceNode != NULL) { @@ -233,22 +250,15 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32 continue; } if (y > surf->upperY) continue; - 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(&vx[1], &vz[1], surf->vertex3, surf->vertex1, margin); - // Checking if point is in bounds of the triangle laterally. - if ((vz[0] - z) * (vx[1] - vx[0]) - (vx[0] - x) * (vz[1] - vz[0]) > 0) continue; - // Slight optimization by checking these later. - vx[2] = surf->vertex3[0]; - vz[2] = surf->vertex3[2]; - if (surf->type != SURFACE_HANGABLE) add_ceil_margin(&vx[2], &vz[2], surf->vertex1, surf->vertex2, margin); - if ((vz[1] - z) * (vx[2] - vx[1]) - (vx[1] - x) * (vz[2] - vz[1]) > 0) continue; - if ((vz[2] - z) * (vx[0] - vx[2]) - (vx[2] - x) * (vz[0] - vz[2]) > 0) continue; - // Find the ceil height at the specific point. - height = get_surface_height_at_location(x, z, surf); + if (!check_within_ceil_triangle_bounds(x, z, surf, 1.5f)) continue; + ny = surf->normal.y; + if (ny > NEAR_ONE) { + // If the surface is flat, use the height of the first vertex. + height = surf->vertex1[1]; + } else { + // Find the height of the ceil at the given location. + height = get_surface_height_at_location_ny(x, z, surf, ny); + } if (height > *pheight) continue; // Checks for ceiling interaction if (y > height) continue; @@ -325,7 +335,7 @@ f32 unused_obj_find_floor_height(struct Object *obj) { return find_floor(obj->oPosX, obj->oPosY, obj->oPosZ, &floor); } -static s32 check_within_triangle_bounds(s32 x, s32 z, struct Surface *surf) { +static s32 check_within_floor_triangle_bounds(s32 x, s32 z, struct Surface *surf) { register Vec3i vx, vz; vx[0] = surf->vertex1[0]; vz[0] = surf->vertex1[2]; @@ -344,8 +354,8 @@ static s32 check_within_triangle_bounds(s32 x, s32 z, struct Surface *surf) { */ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { register struct Surface *surf, *floor = NULL; - f32 height; - s16 type = SURFACE_DEFAULT; + register f32 height, ny; + register SurfaceType type = SURFACE_DEFAULT; *pheight = FLOOR_LOWER_LIMIT; f32 bufferY = (y + 78.0f); // Iterate through the list of floors until there are no more floors. @@ -360,14 +370,20 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // Determine if we are checking for the camera or not. if (gCollisionFlags & COLLISION_FLAG_CAMERA) { if ((surf->flags & SURFACE_FLAG_NO_CAM_COLLISION) || SURFACE_IS_NEW_WATER(type)) continue; - } else if (surf->type == SURFACE_CAMERA_BOUNDARY) { + } else if (type == SURFACE_CAMERA_BOUNDARY) { continue; // If we are not checking for the camera, ignore camera only floors. } if (y < (surf->lowerY - 30)) continue; // Check that the point is within the triangle bounds. - if (!check_within_triangle_bounds(x, z, surf)) continue; - // Find the height of the floor at a given location. - height = get_surface_height_at_location(x, z, surf); + if (!check_within_floor_triangle_bounds(x, z, surf)) continue; + ny = surf->normal.y; + if (ny > NEAR_ONE) { + // If the surface is flat, use the height of the first vertex. + height = surf->vertex1[1]; + } else { + // Find the height of the floor at the given location. + height = get_surface_height_at_location_ny(x, z, surf, ny); + } if (height < *pheight) continue; // Checks for floor interaction with a 78 unit buffer. if (bufferY < height) continue; @@ -397,7 +413,7 @@ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 surf = bottomSurfaceNode->surface; bottomSurfaceNode = bottomSurfaceNode->next; - if (surf->type != SURFACE_NEW_WATER_BOTTOM || !check_within_triangle_bounds(x, z, surf)) continue; + if (surf->type != SURFACE_NEW_WATER_BOTTOM || !check_within_floor_triangle_bounds(x, z, surf)) continue; curBottomHeight = get_surface_height_at_location(x, z, surf); @@ -413,7 +429,7 @@ struct Surface *find_water_floor_from_list(struct SurfaceNode *surfaceNode, s32 surf = topSurfaceNode->surface; topSurfaceNode = topSurfaceNode->next; - if ((surf->type == SURFACE_NEW_WATER_BOTTOM) || !check_within_triangle_bounds(x, z, surf)) continue; + if ((surf->type == SURFACE_NEW_WATER_BOTTOM) || !check_within_floor_triangle_bounds(x, z, surf)) continue; curHeight = get_surface_height_at_location(x, z, surf); diff --git a/src/engine/surface_collision.h b/src/engine/surface_collision.h index 81a2a4bf2..bfa63ca31 100644 --- a/src/engine/surface_collision.h +++ b/src/engine/surface_collision.h @@ -15,7 +15,8 @@ #define is_outside_level_bounds(xPos, zPos) (((xPos) <= -LEVEL_BOUNDARY_MAX) || ((xPos) >= LEVEL_BOUNDARY_MAX) || ((zPos) <= -LEVEL_BOUNDARY_MAX) || ((zPos) >= LEVEL_BOUNDARY_MAX)) -#define get_surface_height_at_location(xPos, zPos, surf) (-((xPos) * (surf)->normal.x + (surf)->normal.z * (zPos) + (surf)->originOffset) / (surf)->normal.y) +#define get_surface_height_at_location(xPos, zPos, surf) (-(((xPos) * (surf)->normal.x) + ((surf)->normal.z * (zPos)) + (surf)->originOffset) / (surf)->normal.y) +#define get_surface_height_at_location_ny(xPos, zPos, surf, ny) (-(((xPos) * (surf)->normal.x) + ((surf)->normal.z * (zPos)) + (surf)->originOffset) / ny) #define SURFACE_YAW(s) (atan2s(((s)->normal.z), ((s)->normal.x)))