diff --git a/src/engine/extended_bounds.h b/src/engine/extended_bounds.h index 591a183e..14897859 100644 --- a/src/engine/extended_bounds.h +++ b/src/engine/extended_bounds.h @@ -22,59 +22,49 @@ Collision calculations remain as fast as vanilla, at the cost of using far more RAM (16 times vanilla). 64x64 collision cells. - If you see "SURFACE POOL FULL" or "SURFACE NODE POOL FULL" in game, you should increase SURFACE_POOL_SIZE or SURFACE_NODE_POOL_SIZE, respectively, or reduce the amount of collision surfaces in your level. */ -//for the static assert macro +// For the static assert macro #include "macros.h" -//set this to the extended bounds mode you want, then do "make clean". +// Set this to the extended bounds mode you want, then do "make clean". #define EXTENDED_BOUNDS_MODE 1 -//the maximum amount of collision surfaces (static and dynamic combined) -//8200 should work fine for a 2x extended stage, the vanilla value is 2300 -#define SURFACE_POOL_SIZE 4000 +// Don't touch the stuff past this point unless you know what you're doing! -//make this approximately (amount of collision cells) + (SURFACE_POOL_SIZE * 3) -//22000 should work fine for a 2x extended stage, the vanilla value is 7000 -#define SURFACE_NODE_POOL_SIZE 12000 - - - - - -//don't touch the stuff past this point unless you know what you're doing! - -//default value to check if the user set a proper extended bounds mode -#define LEVEL_BOUNDARY_MAX 0x0000 - -#if EXTENDED_BOUNDS_MODE == 0 - #undef LEVEL_BOUNDARY_MAX // Undefine the old value to avoid compiler warnings - #define LEVEL_BOUNDARY_MAX 0x2000L - #define CELL_SIZE 0x400 -#elif EXTENDED_BOUNDS_MODE == 1 - #undef LEVEL_BOUNDARY_MAX - #define LEVEL_BOUNDARY_MAX 0x4000L - #define CELL_SIZE 0x400 -#elif EXTENDED_BOUNDS_MODE == 2 - #undef LEVEL_BOUNDARY_MAX - #define LEVEL_BOUNDARY_MAX 0x2000L - #define CELL_SIZE 0x200 -#elif EXTENDED_BOUNDS_MODE == 3 - #undef LEVEL_BOUNDARY_MAX - #define LEVEL_BOUNDARY_MAX 0x8000L - #define CELL_SIZE 0x400 +#if EXTENDED_BOUNDS_MODE == 0 // 1x, normal cell size + #define LEVEL_BOUNDARY_MAX 0x2000L // 8192 + #define CELL_SIZE 0x400 // 1024, NUM_CELLS = 16 +#elif EXTENDED_BOUNDS_MODE == 1 // 2x, normal cell size + #define LEVEL_BOUNDARY_MAX 0x4000L // 16384 + #define CELL_SIZE 0x400 // 1024, NUM_CELLS = 32 +#elif EXTENDED_BOUNDS_MODE == 2 // 1x, smaller cell size + #define LEVEL_BOUNDARY_MAX 0x2000L // 8192 + #define CELL_SIZE 0x200 // 512, NUM_CELLS = 32 +#elif EXTENDED_BOUNDS_MODE == 3 // 4x, normal cell size + #define LEVEL_BOUNDARY_MAX 0x8000L // 32768 + #define CELL_SIZE 0x400 // 1024, NUM_CELLS = 64 #endif -STATIC_ASSERT(LEVEL_BOUNDARY_MAX != 0, "You must set a valid extended bounds mode!"); +STATIC_ASSERT((EXTENDED_BOUNDS_MODE >= 0 && EXTENDED_BOUNDS_MODE <= 3), "You must set a valid extended bounds mode!"); -#define NUM_CELLS (2 * LEVEL_BOUNDARY_MAX / CELL_SIZE) +// The amount of cells in each axis in an area. +#define NUM_CELLS (2 * LEVEL_BOUNDARY_MAX / CELL_SIZE) +// The maximum amount of collision surfaces (static and dynamic combined) +#define SURFACE_POOL_SIZE (LEVEL_BOUNDARY_MAX / 2) // Vanilla: 2300. Modes: 0: 4096, 1: 8192, 2: 8192, 3: 16384 +// How many SurfaceNodes can fit in Surface. This is done so that the maximum sizes for both can contain the same amount. +#define SURFACE_NODE_STRUCT_DIFF 3.5 // = (56 / 16) = (sizeof(struct Surface) / sizeof(struct SurfaceNode)) +// The maximum amount of SurfaceNodes (static and dynamic combined) +#define SURFACE_NODE_POOL_SIZE (s32)(SURFACE_POOL_SIZE * SURFACE_NODE_STRUCT_DIFF) // Vanilla: 7000. Modes: 0: 14336, 1: 28672, 2: 28672, 3: 57344 +// Flags for error messages #define NOT_ENOUGH_ROOM_FOR_SURFACES (1 << 0) #define NOT_ENOUGH_ROOM_FOR_NODES (1 << 1) +// Use this to convert game units to cell coordinates +#define GET_CELL_COORD(p) ((((p) + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & (NUM_CELLS - 1)); #endif // __EXTENDED_BOUNDS_H__ diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 791b61e3..c86a39cb 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -158,10 +158,9 @@ s32 find_wall_collisions(struct WallCollisionData *colData) { return numCollisions; } - // World (level) consists of a 16x16 grid. Find where the collision is on - // the grid (round toward -inf) - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + // World (level) consists of a 16x16 grid. Find where the collision is on the grid (round toward -inf) + cellX = GET_CELL_COORD(x); + cellZ = GET_CELL_COORD(z); // Check for surfaces belonging to objects. node = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; @@ -285,8 +284,8 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { } // Each level is split into cells to limit load, find the appropriate cell. - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellX = GET_CELL_COORD(x); + cellZ = GET_CELL_COORD(z); // Check for surfaces belonging to objects. surfaceList = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; @@ -458,8 +457,8 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl s32 z = zPos; // Each level is split into cells to limit load, find the appropriate cell. - s32 cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - s32 cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + s32 cellX = GET_CELL_COORD(x); + s32 cellZ = GET_CELL_COORD(z); surfaceList = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; floor = find_floor_from_list(surfaceList, x, y, z, &floorHeight); @@ -500,8 +499,8 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { return height; } // Each level is split into cells to limit load, find the appropriate cell. - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellX = GET_CELL_COORD(x); + cellZ = GET_CELL_COORD(z); // Check for surfaces that are a part of level geometry. surfaceList = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; floor = find_floor_from_list(surfaceList, x, y, z, &height); @@ -556,8 +555,8 @@ f32 find_water_floor(s32 xPos, s32 yPos, s32 zPos, struct Surface **pfloor) { if (is_outside_level_bounds(x, z)) return height; // Each level is split into cells to limit load, find the appropriate cell. - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellX = GET_CELL_COORD(x); + cellZ = GET_CELL_COORD(z); // Check for surfaces that are a part of level geometry. surfaceList = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WATER].next; @@ -741,26 +740,28 @@ void debug_surface_list_info(f32 xPos, f32 zPos) { s32 numFloors = 0; s32 numWalls = 0; s32 numCeils = 0; + s32 x = xPos; + s32 z = zPos; - s32 cellX = (xPos + LEVEL_BOUNDARY_MAX) / CELL_SIZE; - s32 cellZ = (zPos + LEVEL_BOUNDARY_MAX) / CELL_SIZE; + s32 cellX = GET_CELL_COORD(x); + s32 cellZ = GET_CELL_COORD(z); - list = gStaticSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_FLOORS].next; + list = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; numFloors += surface_list_length(list); - list = gDynamicSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_FLOORS].next; + list = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; numFloors += surface_list_length(list); - list = gStaticSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_WALLS].next; + list = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; numWalls += surface_list_length(list); - list = gDynamicSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_WALLS].next; + list = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next; numWalls += surface_list_length(list); - list = gStaticSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_CEILS].next; + list = gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; numCeils += surface_list_length(list); - list = gDynamicSurfacePartition[cellZ & NUM_CELLS_INDEX][cellX & NUM_CELLS_INDEX][SPATIAL_PARTITION_CEILS].next; + list = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next; numCeils += surface_list_length(list); print_debug_top_down_mapinfo("area %x", cellZ * NUM_CELLS + cellX); diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index d96e2004..acd6e2c6 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -153,7 +153,7 @@ static void add_surface_to_cell(s32 dynamic, s32 cellX, s32 cellZ, struct Surfac } /** - * Every level is split into 16 * 16 cells of surfaces (to limit computing + * Every level is split into CELL_SIZE * CELL_SIZE cells of surfaces (to limit computing * time). This function determines the lower cell for a given x/z position. * @param coord The coordinate to test */ @@ -185,7 +185,7 @@ static s32 lower_cell_index(s32 coord) { } /** - * Every level is split into 16 * 16 cells of surfaces (to limit computing + * Every level is split into CELL_SIZE * CELL_SIZE cells of surfaces (to limit computing * time). This function determines the upper cell for a given x/z position. * @param coord The coordinate to test */ @@ -208,8 +208,8 @@ static s32 upper_cell_index(s32 coord) { index++; } - if (index > NUM_CELLS_INDEX) { - index = NUM_CELLS_INDEX; + if (index > (NUM_CELLS - 1)) { + index = (NUM_CELLS - 1); } // Potentially < 0, but since lower index is >= 0, not exploitable @@ -430,11 +430,10 @@ static TerrainData *read_vertex_data(TerrainData **data) { * Loads in special environmental regions, such as water, poison gas, and JRB fog. */ static void load_environmental_regions(TerrainData **data) { - s32 numRegions; s32 i; gEnvironmentRegions = *data; - numRegions = *(*data)++; + s32 numRegions = *(*data)++; for (i = 0; i < numRegions; i++) { *data += 5; @@ -518,9 +517,9 @@ u32 get_area_terrain_size(TerrainData *data) { void load_area_terrain(s32 index, TerrainData *data, RoomData *surfaceRooms, s16 *macroObjects) { s32 terrainLoadType; TerrainData *vertexData = NULL; - #if PUPPYPRINT_DEBUG +#if PUPPYPRINT_DEBUG OSTime first = osGetTime(); - #endif +#endif // Initialize the data for this. gEnvironmentRegions = NULL; @@ -568,9 +567,9 @@ void load_area_terrain(s32 index, TerrainData *data, RoomData *surfaceRooms, s16 gNumStaticSurfaceNodes = gSurfaceNodesAllocated; gNumStaticSurfaces = gSurfacesAllocated; - #if PUPPYPRINT_DEBUG - collisionTime[perfIteration] += osGetTime()-first; - #endif +#if PUPPYPRINT_DEBUG + collisionTime[perfIteration] += osGetTime() - first; +#endif } /** diff --git a/src/engine/surface_load.h b/src/engine/surface_load.h index 7cffe2e4..5ba5ac46 100644 --- a/src/engine/surface_load.h +++ b/src/engine/surface_load.h @@ -8,8 +8,6 @@ extern u8 gSurfacePoolError; -#define NUM_CELLS_INDEX (NUM_CELLS - 1) - struct SurfaceNode { struct SurfaceNode *next; diff --git a/src/game/debug_box.c b/src/game/debug_box.c index 1b9ca87f..cc014e1e 100644 --- a/src/game/debug_box.c +++ b/src/game/debug_box.c @@ -221,8 +221,8 @@ void iterate_surfaces_visual(s32 x, s32 z, Vtx *verts) { return; } - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + s32 cellX = GET_CELL_COORD(x); + s32 cellZ = GET_CELL_COORD(z); for (i = 0; i < 8; i++) { switch (i) { @@ -350,8 +350,8 @@ s32 iterate_surface_count(s32 x, s32 z) return 0; } - cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; - cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & NUM_CELLS_INDEX; + cellX = GET_CELL_COORD(x); + cellZ = GET_CELL_COORD(z); for (i = 0; i < 8; i++) {