Automatically calculate SURFACE_POOL_SIZE and SURFACE_NODE_POOL_SIZE

This commit is contained in:
Arceveti
2021-09-29 16:38:36 -07:00
parent d1ed598480
commit 4fe6b323e7
5 changed files with 62 additions and 74 deletions

View File

@@ -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__

View File

@@ -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);

View File

@@ -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
}
/**

View File

@@ -8,8 +8,6 @@
extern u8 gSurfacePoolError;
#define NUM_CELLS_INDEX (NUM_CELLS - 1)
struct SurfaceNode
{
struct SurfaceNode *next;

View File

@@ -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++)
{