Added extended bounds

This commit is contained in:
MysterD 2022-04-06 08:40:22 -07:00
parent f9cb7f3e82
commit a58130b9f6
13 changed files with 199 additions and 128 deletions

View file

@ -226,7 +226,9 @@ s32 DynOS_Level_GetCourse(s32 aLevel) {
const void *DynOS_Level_GetScript(s32 aLevel) {
DynOS_Level_Init();
return DynOS_Lvl_Get("level_castle_inside_entry"); // DO NOT COMMIT
if (aLevel != LEVEL_WDW) {
return DynOS_Lvl_Get(""); // DO NOT COMMIT
}
return sDynosLevelScripts[aLevel];
}

View file

@ -33,11 +33,13 @@
#endif
// Static assertions
#ifndef __cplusplus
#ifdef __GNUC__
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#else
#define STATIC_ASSERT(cond, msg) typedef char GLUE2(static_assertion_failed, __LINE__)[(cond) ? 1 : -1]
#endif
#endif
// Align to 8-byte boundary for DMA requirements
#ifdef __GNUC__

View file

@ -1,8 +1,8 @@
#ifndef SEGMENTS_H
#define SEGMENTS_H
#ifdef BETTERCAMERA
#define USE_EXT_RAM
#ifndef LINKER
#include "segment_symbols.h"
#endif
/*
@ -15,53 +15,19 @@
* linker script syntax.
*/
#ifndef USE_EXT_RAM /* Default: Runs out of memory quickly when importing custom assets. */
#define SEG_POOL_START 0x8005C000
#define SEG_POOL_END SEG_BUFFERS
#define SEG_GODDARD 0x8016F000
#define SEG_BUFFERS 0x801C1000
#ifdef VERSION_EU
#define SEG_MAIN 0x80241800 // TODO: Investigate why it's different?
#elif defined(VERSION_SH)
#define SEG_MAIN 0x80249000
#else
#define SEG_MAIN 0x80246000
#endif
#ifdef VERSION_EU
#define SEG_ENGINE 0x8036FF00
#else
#define SEG_ENGINE 0x80378800
#endif
#define SEG_FRAMEBUFFERS 0x8038F800
#ifndef USE_EXT_RAM
#define RAM_END 0x80400000
#else /* Use Expansion Pak space for pool. */
#define RAM_END 0x80800000
#endif
/*
* Workaround for running out of pool space due to
* importing large custom content.
*/
#define SEG_BUFFERS 0x8005C000 // 0x0085000 in size
#ifdef BETTERCAMERA
#define SEG_MAIN 0x800F1000 // 0x0132800 in size
#define SEG_ENGINE 0x80223800 // 0x0017000 in size
#define SEG_FRAMEBUFFERS 0x8023A800 // 0x0070800 in size
#define SEG_POOL_START 0x802AB000 // 0x0165000 in size
#else
#define SEG_MAIN 0x800E1000 // 0x0132800 in size
#define SEG_ENGINE 0x80213800 // 0x0017000 in size
#define SEG_FRAMEBUFFERS 0x8022A800 // 0x0070800 in size
#define SEG_POOL_START 0x8029B000 // 0x0165000 in size
#endif
#define SEG_POOL_END 0x80800000
#define SEG_POOL_END_4MB 0x80400000 // For the error message screen enhancement.
#define SEG_GODDARD SEG_POOL_START + 0x113000
#endif
#define POOL_SIZE RAM_END - SEG_POOL_START
#endif // SEGMENTS_H

77
sm64.ld
View file

@ -1,8 +1,8 @@
OUTPUT_ARCH (mips)
/* include/segments.h defines SEG_POOL_START, SEG_POOL_END, SEG_BUFFERS,
* SEG_GODDARD, SEG_MAIN, SEG_ENGINE, SEG_FRAMEBUFFERS */
#define LINKER /* Removes externs from preprocessed script */
#include "segments.h"
#undef LINKER
#define BEGIN_SEG(name, addr) \
_##name##SegmentStart = ADDR(.name); \
@ -79,7 +79,31 @@ SECTIONS
BEGIN_NOLOAD(zbuffer) {
BUILD_DIR/src/buffers/zbuffer.o(.bss*);
}
END_NOLOAD(zbuffer)
. = _zbufferSegmentNoloadEnd;
BEGIN_NOLOAD(buffers)
{
BUILD_DIR/src/buffers/buffers.o(.bss*);
BUILD_DIR/src/audio/globals_start.o(.bss*);
BUILD_DIR/src/audio/synthesis.o(.bss*);
BUILD_DIR/src/audio/heap.o(.bss*);
BUILD_DIR/src/audio/load.o(.bss*);
BUILD_DIR/src/audio/data.o(.bss*);
BUILD_DIR/src/audio*.o(.bss*);
#ifdef VERSION_EU
. = ALIGN(0x200);
#else
. = ALIGN(0x1000);
#endif
BUILD_DIR/src/buffers/gfx_output_buffer.o(.bss*);
}
END_NOLOAD(buffers)
/*ASSERT((. <= SEG_MAIN), "Error: buffers segment extended into main")*/
. = _buffersSegmentNoloadEnd;
/* lib/src/__osDevMgrMain.c and lib/src/osCreateViManager.c contain infinite
* loops compiled without -g, which cause the return statements and the .o
* files themselves to be aligned to 32-byte boundaries. But the linker
@ -87,7 +111,7 @@ SECTIONS
* only to 16 bytes, in some cases misaligning them. We force the same to
* happen using the SUBALIGN directive. This is harmless; the alignment is
* just an optimization. */
BEGIN_SEG(main, SEG_MAIN) SUBALIGN(16)
BEGIN_SEG(main, .) SUBALIGN(16)
{
BUILD_DIR/asm/entry.o(.text);
BUILD_DIR/src/game/crash_screen.o(.text);
@ -743,9 +767,11 @@ SECTIONS
_mainSegmentNoloadSizeLo = SIZEOF (.main.noload) & 0xffff;
_mainSegmentNoloadSizeHi = SIZEOF (.main.noload) >> 16;
ASSERT((. <= SEG_ENGINE), "Error: main segment extended into engine.")
/*ASSERT((. <= SEG_ENGINE), "Error: main segment extended into engine.")*/
BEGIN_SEG(engine, SEG_ENGINE)
. = _mainSegmentNoloadEnd;
BEGIN_SEG(engine, .)
{
BUILD_DIR/src/engine/math_util.o(.text);
BUILD_DIR/src/engine/graph_node.o(.text);
@ -801,18 +827,22 @@ SECTIONS
BUILD_DIR/src/game/object_helpers.o(.bss*);
#endif
BUILD_DIR/src/engine*.o(.bss*);
. = ALIGN(0x40);
}
END_NOLOAD(engine)
ASSERT((. <= SEG_FRAMEBUFFERS), "Error: engine segment extended into framebuffers.")
/*ASSERT((. <= SEG_FRAMEBUFFERS), "Error: engine segment extended into framebuffers.")*/
. = SEG_FRAMEBUFFERS;
. = _engineSegmentNoloadEnd;
BEGIN_NOLOAD(framebuffers)
{
BUILD_DIR/src/buffers/framebuffers.o(.bss*);
}
END_NOLOAD(framebuffers)
__mainPoolStart = .;
__mainPoolSize = RAM_END - .;
__expansionRamStart = 0x80400000;
ASSERT((. <= __expansionRamStart), "Error: RDRAM expanded into Expansion RAM, despite Expansion RAM not being defined.")
@ -949,40 +979,9 @@ SECTIONS
}
END_NOLOAD(goddard)
ASSERT((. <= SEG_POOL_END), "Error: extended past pool end.")
ASSERT((. <= (SEG_POOL_START + POOL_SIZE)), "Error: extended past pool end.")
. = SEG_BUFFERS;
BEGIN_NOLOAD(buffers)
{
BUILD_DIR/src/buffers/buffers.o(.bss*);
BUILD_DIR/src/audio/globals_start.o(.bss*);
#ifndef VERSION_SH
BUILD_DIR/src/audio/synthesis.o(.bss*);
BUILD_DIR/src/audio/heap.o(.bss*);
#endif
BUILD_DIR/src/audio/load.o(.bss*);
#ifdef VERSION_SH
BUILD_DIR/src/audio/unk_shindou_audio_file.o(.bss*);
#else
BUILD_DIR/src/audio/data.o(.bss*);
#endif
BUILD_DIR/src/audio*.o(.bss*);
#ifdef VERSION_EU
. = ALIGN(0x200);
#else
. = ALIGN(0x1000);
#endif
#ifdef VERSION_SH
. = . + 0xB000;
#endif
BUILD_DIR/src/buffers/gfx_output_buffer.o(.bss*);
}
END_NOLOAD(buffers)
#ifndef VERSION_SH
ASSERT((. <= SEG_MAIN), "Error: buffers segment extended into main")
#endif
/* 0x268020 0x268020-0 [0] */
BEGIN_SEG(intro, 0x14000000)
{

View file

@ -0,0 +1,81 @@
#ifndef __EXTENDED_BOUNDS_H__
#define __EXTENDED_BOUNDS_H__
/*
Better Extended Bounds by anonymous_moose
Thanks to someone2639 for the shiftable segments patch
Thanks to Wiseguy for the Surface Pool Full error code and 4x bounds fix
0: Regular bounds
Same as vanilla sm64, boundaries are (-8192 to 8191)
16x16 collision cells.
1: 2x extended bounds
level boundaries are twice as big (-16384 to 16383)
Collision calculations remain as fast as vanilla, at the cost of using more RAM.
32x32 collision cells.
2: Regular bounds (performance)
Same boundaries as vanilla (-8192 to 8191), but with twice the amount of collision cells
Trades more RAM usage for faster collision calculations.
32x32 collision cells.
3: 4x extended bounds
level boundaries are 4 times as big (-32768 to 32767)
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
#include "macros.h"
//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 8200
//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 22000
//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
#endif
#ifndef __cplusplus
STATIC_ASSERT(LEVEL_BOUNDARY_MAX != 0, "You must set a valid extended bounds mode!");
#endif
#define NUM_CELLS (2 * LEVEL_BOUNDARY_MAX / CELL_SIZE)
#define NOT_ENOUGH_ROOM_FOR_SURFACES (1 << 0)
#define NOT_ENOUGH_ROOM_FOR_NODES (1 << 1)
#endif // __EXTENDED_BOUNDS_H__

View file

@ -947,23 +947,23 @@ void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f
void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized_dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length)
{
// Skip if OOB
if (cellX >= 0 && cellX <= 0xF && cellZ >= 0 && cellZ <= 0xF)
{
// Iterate through each surface in this partition
if (normalized_dir[1] > -0.99f)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (normalized_dir[1] < 0.99f)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
// Skip if OOB
if (cellX >= 0 && cellX <= NUM_CELLS && cellZ >= 0 && cellZ <= NUM_CELLS)
{
// Iterate through each surface in this partition
if (normalized_dir[1] > -0.99f)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
if (normalized_dir[1] < 0.99f)
{
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length);
}
}
void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos)
@ -995,9 +995,9 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve
// Don't do DDA if straight down
if (normalized_dir[1] >= 1.0f || normalized_dir[1] <= -1.0f)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length);
return;
}
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length);
return;
}
// increase collision checking precision (normally 1)
f32 precision = 3;
@ -1013,7 +1013,7 @@ void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Ve
for (i = 0; i < step && *hit_surface == NULL; i++)
{
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length);
find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length);
// Move cell coordinate
fCellX += dx;

View file

@ -5,10 +5,8 @@
#include "types.h"
// Range level area is 16384x16384 (-8192 to +8192 in x and z)
#define LEVEL_BOUNDARY_MAX 0x2000 // 8192
#include "engine/extended_bounds.h"
#define CELL_SIZE (1 << 10) // 0x400
#define CELL_HEIGHT_LIMIT 20000
#define FLOOR_LOWER_LIMIT -11000

View file

@ -40,6 +40,8 @@ s16 sSurfacePoolSize;
u8 unused8038EEA8[0x30];
u8 gSurfacePoolError = 0;
/**
* Allocate the part of the surface node pool to contain a surface node.
*/
@ -52,7 +54,11 @@ static struct SurfaceNode *alloc_surface_node(void) {
//! A bounds check! If there's more surface nodes than 7000 allowed,
// we, um...
// Perhaps originally just debug feedback?
if (gSurfaceNodesAllocated >= 7000) {
if (gSurfaceNodesAllocated >= SURFACE_NODE_POOL_SIZE) {
gSurfacePoolError |= NOT_ENOUGH_ROOM_FOR_NODES;
return NULL;
} else {
gSurfacePoolError &= ~NOT_ENOUGH_ROOM_FOR_NODES;
}
return node;
@ -71,7 +77,10 @@ static struct Surface *alloc_surface(void) {
// we, um...
// Perhaps originally just debug feedback?
if (gSurfacesAllocated >= sSurfacePoolSize) {
gSurfacePoolError |= NOT_ENOUGH_ROOM_FOR_SURFACES;
return NULL;
} else {
gSurfacePoolError &= ~NOT_ENOUGH_ROOM_FOR_SURFACES;
}
surface->type = 0;
@ -114,6 +123,7 @@ static void clear_static_surfaces(void) {
*/
static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surface *surface) {
struct SurfaceNode *newNode = alloc_surface_node();
if (newNode == NULL) { return; }
struct SurfaceNode *list;
s16 surfacePriority;
s16 priority;
@ -201,7 +211,7 @@ static s16 max_3(s16 a0, s16 a1, s16 a2) {
* time). This function determines the lower cell for a given x/z position.
* @param coord The coordinate to test
*/
static s16 lower_cell_index(s16 coord) {
static s16 lower_cell_index(s32 coord) {
s16 index;
// Move from range [-0x2000, 0x2000) to [0, 0x4000)
@ -233,7 +243,7 @@ static s16 lower_cell_index(s16 coord) {
* time). This function determines the upper cell for a given x/z position.
* @param coord The coordinate to test
*/
static s16 upper_cell_index(s16 coord) {
static s16 upper_cell_index(s32 coord) {
s16 index;
// Move from range [-0x2000, 0x2000) to [0, 0x4000)
@ -536,8 +546,8 @@ static void load_environmental_regions(s16 **data) {
* Allocate some of the main pool for surfaces (2300 surf) and for surface nodes (7000 nodes).
*/
void alloc_surface_pools(void) {
sSurfacePoolSize = 2300;
sSurfaceNodePool = main_pool_alloc(7000 * sizeof(struct SurfaceNode), MEMORY_POOL_LEFT);
sSurfacePoolSize = SURFACE_POOL_SIZE;
sSurfaceNodePool = main_pool_alloc(SURFACE_NODE_POOL_SIZE * sizeof(struct SurfaceNode), MEMORY_POOL_LEFT);
sSurfacePool = main_pool_alloc(sSurfacePoolSize * sizeof(struct Surface), MEMORY_POOL_LEFT);
gCCMEnteredSlide = 0;

View file

@ -6,6 +6,8 @@
#include "surface_collision.h"
#include "types.h"
extern u8 gSurfacePoolError;
#define NUM_CELLS (2 * LEVEL_BOUNDARY_MAX / CELL_SIZE)
#define NUM_CELLS_INDEX (NUM_CELLS - 1)

View file

@ -885,21 +885,21 @@ void pan_ahead_of_player(struct Camera *c) {
vec3f_add(c->focus, pan);
}
s16 find_in_bounds_yaw_wdw_bob_thi(Vec3f pos, Vec3f origin, s16 yaw) {
switch (gCurrLevelArea) {
case AREA_WDW_MAIN:
yaw = clamp_positions_and_find_yaw(pos, origin, 4508.f, -3739.f, 4508.f, -3739.f);
break;
case AREA_BOB:
yaw = clamp_positions_and_find_yaw(pos, origin, 8000.f, -8000.f, 7050.f, -8000.f);
break;
case AREA_THI_HUGE:
yaw = clamp_positions_and_find_yaw(pos, origin, 8192.f, -8192.f, 8192.f, -8192.f);
break;
case AREA_THI_TINY:
yaw = clamp_positions_and_find_yaw(pos, origin, 2458.f, -2458.f, 2458.f, -2458.f);
break;
}
s16 find_in_bounds_yaw_wdw_bob_thi(UNUSED Vec3f pos, UNUSED Vec3f origin, s16 yaw) {
// switch (gCurrLevelArea) {
// case AREA_WDW_MAIN:
// yaw = clamp_positions_and_find_yaw(pos, origin, 4508.f, -3739.f, 4508.f, -3739.f);
// break;
// case AREA_BOB:
// yaw = clamp_positions_and_find_yaw(pos, origin, 8000.f, -8000.f, 7050.f, -8000.f);
// break;
// case AREA_THI_HUGE:
// yaw = clamp_positions_and_find_yaw(pos, origin, 8192.f, -8192.f, 8192.f, -8192.f);
// break;
// case AREA_THI_TINY:
// yaw = clamp_positions_and_find_yaw(pos, origin, 2458.f, -2458.f, 2458.f, -2458.f);
// break;
// }
return yaw;
}

View file

@ -8,6 +8,7 @@
#include "level_update.h"
#include "camera.h"
#include "print.h"
#include "engine/surface_load.h"
#include "ingame_menu.h"
#include "hud.h"
#include "segment2.h"
@ -523,5 +524,15 @@ void render_hud(void) {
if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER && showHud) {
render_hud_timer();
}
if (gSurfacePoolError & NOT_ENOUGH_ROOM_FOR_SURFACES)
{
print_text(10, 40, "SURFACE POOL FULL");
}
if (gSurfacePoolError & NOT_ENOUGH_ROOM_FOR_NODES)
{
print_text(10, 60, "SURFACE NODE POOL FULL");
}
}
}

View file

@ -144,7 +144,7 @@ void setup_mesg_queues(void) {
void alloc_pool(void) {
void *start = (void *) SEG_POOL_START;
void *end = (void *) SEG_POOL_END;
void *end = (void *) (SEG_POOL_START + POOL_SIZE);
main_pool_init(start, end);
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);

View file

@ -2003,12 +2003,12 @@ s32 cur_obj_within_12k_bounds(void) {
}
void cur_obj_move_using_vel_and_gravity(void) {
if (cur_obj_within_12k_bounds()) {
//if (cur_obj_within_12k_bounds()) {
o->oPosX += o->oVelX;
o->oPosZ += o->oVelZ;
o->oVelY += o->oGravity; //! No terminal velocity
o->oPosY += o->oVelY;
}
//}
}
void cur_obj_move_using_fvel_and_gravity(void) {