Compare commits

..

59 Commits

Author SHA1 Message Date
thecozies
83fea6d310 v2.0.3 2022-07-19 11:35:48 -05:00
gheskett
8698cc0f89 Bugfix: patch_audio_bank crash (hopefully) resolved for good 2022-07-15 00:25:18 -04:00
Mr-Wiseguy
62d6ee135f HackerSM64 2.0.2 release 2022-06-28 09:43:19 -04:00
thecozies
3d330e0b84 Merge pull request #387 from HackerN64/develop/2.0.1
HackerSM64 2.0.2 Release
2022-06-28 08:40:54 -05:00
Arceveti
1691e48326 Fix inverted tilting pyramids when platform displacement 2 is disabled (#397) 2022-06-28 09:30:49 -04:00
Reonu
e5af0e8ca5 Add :Zone_Identifier files to gitignore (#428) 2022-06-28 09:28:54 -04:00
Mr-Wiseguy
cf570b4406 Added dcache coherency emulation test that disables instant input if passed (fixes Ares) (#427) 2022-06-28 12:57:14 +01:00
Reonu
1012fb7957 Add extra hud defines (#409)
* Added extra HUD defines

* moved the defines to hud.h
2022-06-27 22:17:44 -04:00
Reonu
aa1a48afeb Fix shindou audio bzero size (#426) 2022-06-27 22:15:47 -04:00
Mr-Wiseguy
5e1258e806 Merge branch 'master' into develop/2.0.1 2022-06-17 01:11:34 -04:00
Arceveti
c938bbf407 Add missing check for 9 vert shadows in LEGACY_SHADOW_IDS ifdef (#406)
* Add missing check for 9 vert shadows in LEGACY_SHADOW_IDS ifdef

* Add legacy shadow ids to ShadowType enum
2022-06-09 15:52:10 +01:00
KazeEmanuar
a1ab7c51f0 Made raycasts not hit backfaces
* Update name of lighting engine branch in readme
2022-06-09 10:04:58 -04:00
Arceveti
4cfbc656a9 Re-implement FALL_DAMAGE_HEIGHT_SMALL usage in play_far_fall_sound (#407) 2022-05-19 17:12:28 -04:00
Arceveti
fe6aee22e1 Remove redundant snufit offset vector (fixes gcc11 compiler warning) (#395) 2022-05-02 15:36:59 -04:00
Arceveti
ad3aa42eff Fix construct_float by changing addiu to ori (#394) 2022-05-02 14:56:04 -04:00
Mr-Wiseguy
031cc24fa6 New profiler (#390)
* Implemented new lightweight CPU/RDP profiler

* Integrated new profiler into puppyprint debug and improved profiler visuals, removed existing puppyprint profiling code
2022-05-01 00:42:58 -04:00
thecozies
8d06db06e1 Added specific extracted assets to gitignore (#386)
* Added specific extracted assets to gitignore

* Add .orig files to gitignore

Co-authored-by: Arceveti <73617174+Arceveti@users.noreply.github.com>

Co-authored-by: Arceveti <73617174+Arceveti@users.noreply.github.com>
2022-04-28 17:50:27 +03:00
Arceveti
642a85fec6 Fix build warnings & errors when building non-US versions (#305)
* Fix build warnings & errors when building non-US versions

* Revert ADSR_STATE_LOOP change in adsr_update in effects.c + add fallthrough comments + clean up ifdefs

* null initialization for loadedPool in heap.c

* Better placement of null initialization of arg0 in alloc_bank_or_seq
2022-04-15 12:46:17 -04:00
Reonu
3092929822 Tie JRB dark skybox with ENABLE_VANILLA_LEVEL_SPECIFIC_CHECKS (#378)
The JRB skybox is darkened if you haven't collected JRB's first star. This behaviour should be under `ENABLE_VANILLA_LEVEL_SPECIFIC_CHECKS`
2022-04-14 18:53:11 -04:00
CrashOveride95
51f8ccfbb0 Comment out username printing during debug builds because people use their real names on their computers
I still wanna give people the option so
2022-04-10 17:37:14 -04:00
CrashOveride95
2118234f9b Remove datetime from version.c to make debug builds reproducible 2022-04-10 17:37:14 -04:00
Gregory Heskett
ac0299e5b5 Bugfix: 2x+ skyboxes given insufficient memory space (#372) 2022-03-30 18:41:22 -04:00
Fazana
f98d43c9de Puppycamera hotfixes (#367)
* fixed some embarassing typos
2022-03-27 03:20:28 -04:00
someone2639
bf8ea238e5 Fix some bad comment descriptions in math_util (#328) 2022-03-25 13:23:34 -04:00
Mr-Wiseguy
b3cb639e6e Fixed makefile issue causing audio files to be compiled with different flags the first time they're built (#318) 2022-03-18 14:15:08 -04:00
Arceveti
12595397cd Fix OBJECTS_REJ build error & warning + silhouette incompatibility (#324)
* Fix OBJECTS_REJ build error & warning

* Fix Mario rendering
2022-03-18 11:03:39 -07:00
Arceveti
65eb5a755f Reimplement 'FIX_WATER_RINGS' (#325)
* Reimplement 'FIX_WATER_RINGS'
2022-03-18 11:02:38 -07:00
Gregory Heskett
eaf9d3e4f9 Merge pull request #352 from gheskett/develop/mingw-custom-audio-fix
Fix custom audio files not compiling under MinGW (in case it ever matters)
2022-03-18 12:47:54 -05:00
Arceveti
8cfd9af4ee Uncomment the last gSPPopMatrix in render_hud_cannon_reticle (#351) 2022-03-15 17:38:38 -04:00
gheskett
3f0143ec0f Fix custom audio files not compiling under MinGW (in case it ever matters) 2022-03-13 18:57:17 -04:00
tuxlovesyou
33b2a07759 Added LOAD_MIO0_TEXTURE alias for backwards-compatibility (#349)
Sometimes tools like Fast64 will export script.c files with
LOAD_MIO0_TEXTURE() macro "calls" even when you have "YAY0" toggled
under the export menu.  To keep this from being a roadblock for
compilation, LOAD_MIO0_TEXTURE() is defined in this commit as an alias
to the LOAD_YAY0_TEXTURE() macro! :-)
2022-03-11 22:10:46 -05:00
axollyon
a0e8600776 Saves default conf on boot now, simplify condition (#321) 2022-03-08 08:49:10 -06:00
Arceveti
4265019923 Fix NON_STOP_STARS & bhvCelebrationStar related issues with Bowser keys (#299)
Fix NON_STOP_STARS issues & bhvCelebrationStar related issues with Bowser keys
2022-01-22 14:07:55 -08:00
Reonu
ad91c636ad Update name of lighting engine branch in readme
sorry for pushing to master :(((((((((((((
2022-01-22 11:11:51 +02:00
Arceveti
730f020b6d Fix formatting inconsistencies in config files (#303)
Fix formatting inconsistencies in config files
2022-01-21 20:00:25 -08:00
Arceveti
483b72e7da Fix render menu buttons functions (#300) 2022-01-19 14:41:14 -08:00
Arceveti
36d41a7f94 Renamed HackerSM64 modified assets so they don't conflict with vanilla assets (#293) 2022-01-16 21:30:06 -08:00
Arceveti
af34a81c06 Fix credits text ifdef (#301) 2022-01-16 21:29:06 -08:00
Mr-Wiseguy
3fac5ad059 Downgraded from F3DZEX2.08J to F3DZEX2.08I so that point lighting works on Jabo (#313)
* Downgraded from F3DZEX2.08J to F3DZEX2.08I so that point lighting works on Jabo

* Swapped to MM's rspboot to fix bug caused by MM's F3DZEX2
2022-01-15 01:09:34 -05:00
Arceveti
6ba4fcdba1 Set oDrawingDistance to 4500 for WF breakable walls (#304) 2022-01-14 19:38:10 -08:00
Arceveti
38c6e456f1 Fix level enum conflict with 99+ levels (#307) 2022-01-14 19:37:56 -08:00
Mr-Wiseguy
7b58f63cbc Merge pending master hotfixes into 2.0.2 #311 2022-01-14 22:25:09 -05:00
Mr-Wiseguy
475e039f8a Fixed hackersm64 using a ucode that never existed (#309) 2022-01-15 03:13:40 +00:00
Arceveti
2329786f88 Make CLEARRAM mandatory (#297) 2022-01-12 15:00:22 -08:00
Arceveti
ca9f7967c8 Merge pull request #285 from Reonu/develop/arceveti/2.0.1/mr_i_iris_clipping
Fix wrong Y offset for Mr. I iris
2022-01-11 14:01:25 -08:00
Arceveti
1b66355249 Merge pull request #284 from Reonu/develop/arceveti/2.0.1/jp_baserom_requirement
JP Baserom is no longer required for US build
2022-01-10 20:52:31 -08:00
Arceveti
0789cf118e Only extract assets from JP/EU/SH roms if they exist 2022-01-10 20:50:37 -08:00
Arceveti
1b37e627bc Merge pull request #283 from Reonu/develop/arceveti/2.0.1/no_getting_buried_compiler_warning
Fix build warning when NO_GETTING_BURIED is enabled
2022-01-10 20:31:38 -08:00
Arceveti
886d9841a8 Better Mr. I offset fix 2022-01-10 18:27:08 -08:00
Mr-Wiseguy
25951363b7 Increment version hotfix 2022-01-07 14:14:47 -05:00
Mr-Wiseguy
797f9fa223 Reverted moving the buffers to fix pool issues 2022-01-07 13:54:04 -05:00
Arceveti
3d24cdee18 Merge pull request #280 from Reonu/develop/arceveti/2.0.1/hardcoded_cos_values
Fix hardcoded cos values in sm64.h
2022-01-07 00:00:59 -08:00
Arceveti
c9523aaa0b Fix wrong Y offset for Mr. I iris 2022-01-04 23:31:39 -08:00
Arceveti
84bbd2ae14 JP Baserom is no longer required for US build 2022-01-04 22:55:19 -08:00
Arceveti
9caafc54eb Fix build warning when NO_GETTING_BURIED is enabled 2022-01-04 22:18:35 -08:00
Arceveti
feff004ef9 Fix hardcoded cos values in sm64.h 2022-01-02 18:46:31 -08:00
Reonu
9d7d56989e New lighting engine branch name in readme 2022-01-01 23:47:08 +00:00
thecozies
f3e61a31aa HackerSM64 v2.0.0
* buffers: refresh 15 and revert to base decomp

* behavior script

* color helper functions

* extended bounds

* egeo_layout

* fixed model ids

* camera conf improved

* message panel ucode small

* graph node

* level script

* mathutil updates

* mathutil updates (allow unused funcs)

* behaviors a - beta_fish

* Add librtc and fix some data declarations

* Move GRUCODE define to proper location in makefile

* Refresh 15

* extra

* Make ROM name smaller and change messages printed on build a bit

* Fix console (lol)

* Update UNF to latest master

* Make ucode load from .o's (and also fix Super3D)

* Fix crash with rumble + custom mario model

* graph node and mathutil

* removed behaviors

* Ldtob documentation

* _Putfld labeling

* area

* behavior actions

* camera

* debug updates

* bubbles

* envfx snow

* farcall helpers

* game init

* geo misc

* hud

* only check if VC on render init

* ingame menu

* revert goddard to base decomp

* insn disasm

* interaction documentation

* level geo

* level update defines

* macro special objects formatting changes

* main.h documentation

* map parser documentation & formatting

* airborne documentation

* mario actions automatic documentation

* mario actions cutscene documentation

* mario actions moving documentation and options

* mario actions object documentation and options

* mario stationary documentation

* mario submerged documentation

* mario misc documentation

* mario step: ledge grab fixes and documentation

* mario documentation

* memory.h documentation

* moving textures

* object behaviors

* object collision

* fix flamethrower bug

* object helpers

* object list processor documentation

* paintings

* platform displacement

* print / printf

* puppycam absf

* puppyprint updates and formatting changes

* rendering graph node performance optimizations

* rumble opt and doc

* hqvm back to ultrasm64

* save file documentation and unlock defines

* s2d engine

* reset various files to ultrasm64

* file select

* intro geo documentation

* screen transition documentation

* segment2.h

* shadow overhaul

* skybox refactor

* sound init: clean up define usage + documentation

* spawn object optimizations and documentation

* spawn sound cleanup

* sram to ultrasm64

* star select cleanup

* title screen cleanup

* dialogs / text

* rename stomp smoke

* stomp smoke -> small water splash

* updated README

* compilation flags

* optimized file positions + support function/data sections

* surface collision performance improvements

* surface load optimizations

* camera conf documentation

* Allow easier command for opening puppyprint debug

* Rearranged framebuffers & fixed puppyprint console printing

* Fix shadow scaling and shifting

* Fix SILHOUETTE, OBJECTS_REJ, and ucode loading, also clean up render phase system a bit.

* Fixed build with BETTER_HANGING off

* Clean up OBJECTS_REJ ifdefs

* Fix duplicate comment & graph render layers/flags bitmask

* Fixed build with BETTER_HANGING off

* Fix Fast64 importing by reverting sSegmentTable change

* Readded missing functions that caused build errors with Mario head enabled

* Fixed clang compilation issues

* Add INTER mode for geo_update_layer_transparency

* Fix build warnings

* bugfix: miscalculation in obj_turn_toward_object

* Some puppytech fixes

* Further Puppycamera fixes

* Fix BUGFIX_DIALOG_TIME_STOP

Fixes #136

* Fix sliding platform bparams

* Add LEGACY_SHADOW_IDS define for Fast64 compatibility

* Apply suggested changes

* Better find_in_bounds_yaw_wdw_bob_thi ifdef

* Fix build warnings for unused functions

* Fixed stale reference bug from obj_mark_for_deletion change

* Fixed incorrect digit for 100s #145

* Change groundpound-fix define and functionality to just disable bonking

* Fixed puppyroll #134

* Adjust height value for terrain angle to kick in

* fixed hi score flashing

* Remove menudata backup (#131)

Not considered important enough to keep

* Fix fread() build warning

* Add COURSE_NUM_TO_INDEX to save_file_get_star_flags check in bhv_unagi_init

* Fix approach_s16 return value

* Use boolean defines for oCapDoScaleVertically

* Make the door lock a part of the key door model to eliminate z-fighting, also reduce z fighting on numbered doors with AUTO_LOD enabled.

* Move flames to LAYER_TRANSPARENT_INTER

* Resolved some compiler warnings and added FALL_THROUGH define (#168)

* Address some more compiler warnings with different define toggles

* Remove unnecessary fallthrough attribute

* fixed geo_process_billboard floating point exception

* Allow water to face any direction

* Initialize focOffset so that BBH doesn't crash

* Removed superfluous RDP commands when switching microcodes which would override scissor

* Set OBJ_FLAG_DONT_CALC_COLL_DIST on bhvUkikiCage

* Fix rumble build

* Fixed UNLOCK_FPS strobing

* Update src/game/object_helpers.c

Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>

* Update src/game/object_helpers.c

Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>

* Fix LEGACY_SHADOW_IDS id conflict

* Use the vanilla default value for rotating fire bars if bparam2 is 0

* START_LEVEL safeguard

* Fix some drawing distance issues caused by AUTO_COLLISION_DISTANCE

* Fix rumble build

* Fixed spline poll code using the wrong values for keyframes

* Update readme with better credits

Better credits for individual contributors

* add arthur

* added falco and moose

* add fazana

* le funny typo

* added S2DEX engine to credits

* silhouette + axo + ratio

* remove specific callouts + add auto col distance

* Update data/behavior_data.c

Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>

* Update data/behavior_data.c

Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>

* Update data/behavior_data.c

Co-authored-by: thecozies <79979276+thecozies@users.noreply.github.com>

* Revert formatting changes to match vanilla decomp

* Re-implement Y buffer for find_ceil

* Re-implement POWER_STARS_HEAL for normal Power Stars

* Start level comment & exit course comment/collapse

* utilize reonucam technique for FAST_VERTICAL_CAMERA_MOVEMENT

* Fix "MAX_REFERENCED_WALLS" typo

* Allow stop_and_set_height_to_floor to work at any height if Mario is teleporting (#213)

* Revert stop_and_set_height_to_floor to vanilla

Fixes #208

* Fixed sAudioEnabled so that it disables audio CPU processing as well

* Fixed puppyprint debug RDP us calculations

* Renamed sAudioEnabled to gAudioEnabled

* Replaced mtxf_to_mtx_asm with an equivalent implementation that supports WORLD_SCALE

* Moved extended bounds and world scale configuration to a new config_world.h file

* Default all objects to non-rej (#227)

Fixes #221 (Default all objects to non-rej)

* Fix #221

* Fix VISUAL_DEBUG breaking/crashing when OBJECTS_REJ is disabled (#211)

* Fix VISUAL_DEBUG breaking/crashing when OBJECTS_REJ is disabled

* Change vtl decrement in visual_surface_display from 6 to 3

Fixes #207

* Make area in SL igloo wider to prevent a softlock (#233)

Fixes #210

* Fix coin formation coins being deleted if they spawn in the middle of a floor, also fix TTM slide coin position (#232)

Fixes #201

* Make UNLOCK_ALL apply to more things

* Fix wrong ifdef/ifndef in bhv_invisible_objects_under_bridge_init

* Change chain chomp load/unload distances depending on number of segments (#237)

Fixes #192

* added WATER_PLUNGE_UPWARP define

* Add reonucam patch (#239)

* added reonucam patch
Fixes #218

* Fix how shadows handle water/transparency/height (#228)

* Fix how shadows handle water/transparency/height

* Change shadow check for flying carpets from a level specific check to a oPlatformOnTrackType check

Fixes #179

* added reonucam credit

* delete unnecesary patches

* Apply suggested changes

* murdered more patches

* UNLOCK_ALL unlocks the cap boxes

* UNLOCK_ALL unlocks cap boxes (slightly more epic edition)

* revert ceil buffer

* Renamed HD_INTRO_TEXTURES define, separated intro floombas

* prevent double definition of floombas

* actually prevent floomba redefinition

* Develop/refactor  default defines (#242)

* Changed default config options

* Added build dir to includePaths for pngs

* disable NO_SLEEP by default

* Disable puppyprint by default

Sorry fazana 😔

* fix typos

* add comment about BETTER_REVERB console perf

* disable blue coin switch retry by default

* Update config_audio.h

Co-authored-by: Reonu <danileon95@gmail.com>
Co-authored-by: Mr-Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com>

* revert air step line to vanilla to fix bitfs scaling platform issue (#247)

Fixes #200

* Fix stuttering on thin slopes (#248)

* Fix stuttering on thin slopes

* Revert vec3f_find_ceil calls to vanilla

* Rename vec3f_find_ceil to find_mario_ceil

* Update src/engine/surface_collision.h

Fixes #249

* Swap static and dynamic surface checks back to vanilla order (#253)

* Swap static and dynamic surface checks back to vanilla order

* re-enable DISABLE_ALL config

Fixes #251 #252

* Fixed save and quitting while in widescreen (#257)

* Fixed save and quitting while in widescreen

* use define for the level

* all my homies hate ifdefs

* skip wall offsets < 0 (#255)

Fixes #255

* #264: Document non-stop stars' issues (#267)

* #264: Document non-stop stars' issues

* Update include/config/config_game.h

* nonstop vanilla comment

* derive margin_radius from radius after capping at 200 (#266)

Fixes #259

* Config cleanup/refactor (#269)

* Moved puppyprint define to graphics / rearranged some debug defines for ease of access

* Moved compatibility safeguards to config_safeguards.h

* spacing and comment formatting

* #272 Move GFX_POOL_SIZE to config_graphics.h

* disable EASIER_DIALOG_TRIGGER by default

* prevent redefining warnings

* small ifdef typo

* changed ifndef to undefs

Fixes #262
Fixes #272

* Improved movement config documentation related to turning around (#271)

Fixes #270

* rename CUSTOM_DEBUG, add comments (#275)

* Update README.md (#277)

* v2.0.0

Co-authored-by: CrashOveride95 <crashoveride953@gmail.com>
Co-authored-by: Arceveti <73617174+Arceveti@users.noreply.github.com>
Co-authored-by: n64 <n64>
Co-authored-by: Fazana <52551480+FazanaJ@users.noreply.github.com>
Co-authored-by: Mr-Wiseguy <mrwiseguyromhacking@gmail.com>
Co-authored-by: aglab2 <aglab3@gmail.com>
Co-authored-by: gheskett <gheskett@gmail.com>
Co-authored-by: Reonu <danileon95@gmail.com>
Co-authored-by: Axollyon <20480418+Axollyon@users.noreply.github.com>
Co-authored-by: Mr-Wiseguy <68165316+Mr-Wiseguy@users.noreply.github.com>
2021-12-30 16:57:51 +00:00
Reonu
3a558060ab Add Wiseguy as a code owner
*flexes pushing to master privileges*
2021-12-19 19:11:17 +00:00
136 changed files with 4556 additions and 3912 deletions

2126
.gitignore vendored

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
"${workspaceFolder}/include/n64/**",
"${workspaceFolder}/include/**",
"${workspaceFolder}/textures/**",
"${workspaceFolder}/build/us_n64/**",
"${workspaceFolder}/**"
],
"forcedInclude": [
@@ -24,7 +25,7 @@
"TARGET_N64=1",
"VERSION_US=1",
"F3DEX_GBI_2=1",
"F3DZEX_GBI_2=1",
"F3DZEX_NON_GBI_2=1",
"F3DEX_GBI_SHARED=1",
"NON_MATCHING=1",
"AVOID_UB=1"

View File

@@ -4,6 +4,7 @@
# These owners will be the default owners for everything in the repo.
* @Reonu
* @thecozies
* @Mr-Wiseguy
# Order is important. The last matching pattern has the most precedence.
# So if a pull request only touches javascript files, only these owners

View File

@@ -108,7 +108,7 @@ else ifeq ($(GRUCODE),l3dex2) # Line3DEX2
else ifeq ($(GRUCODE),f3dex2pl) # Fast3DEX2_PosLight
DEFINES += F3DEX2PL_GBI=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),f3dzex) # Fast3DZEX (2.08J / Animal Forest - Dōbutsu no Mori)
DEFINES += F3DZEX_GBI_2=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
DEFINES += F3DZEX_NON_GBI_2=1 F3DEX_GBI_2=1 F3DEX_GBI_SHARED=1
else ifeq ($(GRUCODE),super3d) # Super3D
$(warning Super3D is experimental. Try at your own risk.)
DEFINES += SUPER3D_GBI=1 F3D_NEW=1
@@ -323,11 +323,25 @@ ifeq ($(filter clean distclean print-%,$(MAKECMDGOALS)),)
ifeq ($(NOEXTRACT),0)
DUMMY != $(PYTHON) extract_assets.py $(VERSION) >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets)
$(error Failed to extract assets from US ROM)
endif
DUMMY != $(PYTHON) extract_assets.py jp >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets)
ifneq (,$(wildcard baserom.jp.z64))
DUMMY != $(PYTHON) extract_assets.py jp >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from JP ROM)
endif
endif
ifneq (,$(wildcard baserom.eu.z64))
DUMMY != $(PYTHON) extract_assets.py eu >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from EU ROM)
endif
endif
ifneq (,$(wildcard baserom.sh.z64))
DUMMY != $(PYTHON) extract_assets.py sh >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to extract assets from SH ROM)
endif
endif
endif
@@ -616,7 +630,8 @@ $(BUILD_DIR)/src/usb/usb.o: CFLAGS += -Wno-unused-variable -Wno-sign-compare -Wn
$(BUILD_DIR)/src/usb/debug.o: OPT_FLAGS := -O0
$(BUILD_DIR)/src/usb/debug.o: CFLAGS += -Wno-unused-parameter -Wno-maybe-uninitialized
# File specific opt flags
$(BUILD_DIR)/src/audio/*.o: OPT_FLAGS := -Os -fno-jump-tables
$(BUILD_DIR)/src/audio/heap.o: OPT_FLAGS := -Os -fno-jump-tables
$(BUILD_DIR)/src/audio/synthesis.o: OPT_FLAGS := -Os -fno-jump-tables
$(BUILD_DIR)/src/engine/surface_collision.o: OPT_FLAGS := $(COLLISION_OPT_FLAGS)
$(BUILD_DIR)/src/engine/math_util.o: OPT_FLAGS := $(MATH_UTIL_OPT_FLAGS)

View File

@@ -1,43 +1,44 @@
# ![](https://i.imgur.com/CeOukzk.gif) HackerSM64 ![](https://i.imgur.com/s0LUbTo.gif)
**AFTER CLONING THE REPO, CHECK OUT THE `include/config.h` FILE BEFORE ANYTHING ELSE! IT THERE'S A LOT OF STUFF IN THIS REPO THAT CAN BE TOGGLED THERE.**
**AFTER CLONING THE REPO, CHECK OUT THE `include/config` FOLDER BEFORE ANYTHING ELSE! THERE'S A LOT OF STUFF IN THIS REPO THAT CAN BE TOGGLED THERE.**
HackerSM64 now has a discord server! https://discord.gg/brETAakcXr
This repo needs BOTH an US ROM and a JP ROM in order to build. Place baserom.us.z64 in the repo as usual and ALSO place baserom.jp.z64
This repo requires BOTH a US ROM and a JP ROM in order to build. Place baserom.us.z64 in the repo as usual and ALSO include baserom.jp.z64.
This repo needs gcc in order to be able to build it. To install it, run `sudo apt install gcc-mips-linux-gnu`
This is a fork of the ultrasm64 repo by CrashOveride which includes the following commonly used patches (patches marked with `*` are toggleable in `config.h`):
This is a fork of the ultrasm64 repo by CrashOveride which includes the following commonly used patches (patches marked with `*` are toggleable in the config files):
**Credits**
- **ArcticJaguar725**: Most audio configuration and layout changes, colored ia4 text, floombas, a bunch of random bugfixes, and more
- **ArcticJaguar725**: Most audio configuration and layout changes, colored ia4 text, floombas, various bugfixes, and more
- **CowQuack**: Adjustable skybox sizes, area-specific skybox function
- **thecozies**: Water surface types, general maintenance, and time
- **MrComit**: General use object defines, JUMP_KICK_FIX, LEDGE_GRABS_CHECK_SLOPE_ANGLE
- **aglab2**: bugfixes (particularly puppycam), refactor stuff
- **aglab2**: Bugfixes (particularly puppycam), refactor stuff
- **someone2639**: math.s and crash screen disam, stack trace, map packing, shiftable segments 2, S2DEX engine
- **Arthurtilly**: Platform Displacement 2
- **Fazana**: PuppyLib, ucode swapping, Audio load time optimisations (with Arctic), general hacker qol improvements, visual debug
- **Reonu**: Starting the project/repo, widescreen, various defines for hacker QoL
- **JoshDuMan**: decomp guy, general assistance
- **Arceveti**: silhouette, shadow optimisation, better hanging, breath meter
- **Fazana**: PuppyLib, ucode swapping, audio load time optimisations (with Arctic), general hacker qol improvements, visual debug
- **Reonu**: Starting the project/repo, widescreen, reonucam, various defines for hacker QoL
- **JoshDuMan**: Decomp guy, general assistance
- **Arceveti**: Silhouette, shadow optimisation, better hanging, breath meter
- **axollyon**: Console testing, bugfixes, idea-guying, and had a hand in silhouettes
- **Wiseguy**: silhouette, graph node optimisations, instant input patch, cake screen fix, segmented code support, and various optimizations/fixes
- **Wiseguy**: World scale reimplementation, silhouette, graph node optimisations, instant input patch, cake screen fix, segmented code support, and various optimizations/fixes
- **Kaze**: Graph node optimisations, automatic optimal collision distance
- **Pyro Jay**: Texture improvements, repo banner art, some QoL stuff
- **CrashOveride**: creating the `ultrasm64` repo
- **falcobuster**: coordinate overflow fix (world scale), ASM version of extended bounds
- **CrashOveride**: creating the [ultrasm64](https://github.com/CrashOveride95/ultrasm64) repo
- **falcobuster**: Original coordinate overflow fix (world scale), ASM version of extended bounds
- **anonymous_moose**: porting falco's extended bounds to decomp
- **tuxlovesyou**: `LOAD_MIO0_TEXTURE` macro and moral support
Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
**Lighting Engine by Wiseguy**
- Lighting Engine is available on a separate branch `(lighting-engine)`. Instructions on how to use it are in the readme of that branch.
- Lighting Engine is available on a separate branch ([base/lighting-engine](https://github.com/Reonu/HackerSM64/tree/base/lighting-engine)). Instructions on how to use it are in the readme of that branch.
- Alternatively, the main repo has `Puppylights` available, which is a more lightweight, but limited lighting library intended to be used to modify existing light properties. You can look at `puppylights.c` to find out how to use it.
**Puppycam**
- Puppycam is available on the master branch now, you can toogle it in config.h. *
- Puppycam is available on the master branch now, you can toggle it in `config/config_camera.h`. *
**Collision:**
- Slope fix and exposed ceilings fix
@@ -45,11 +46,11 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
- Jump kick fix *
- Configurable wallkick angle, in degrees *
- Possibility of disabling BLJs *
- Hanging fix (mario can grab hangable ceilings from any state, instead of only jump or double jump) *
- Hanging fix (Mario can grab hangable ceilings from any state, instead of only jump or double jump) *
- Increased maximum pole length (The game will read bparam1 and bparam2 together as a single value, so you can have a very long pole) *
- Platform Displacement 2 by Arthurtilly *
- Water Surface Type patch by thecozies
- Better Wall Collision With Rounded Corners by FramePerfection, merged by Cheezepin & Arceveti
- Better wall collision with rounded corners by FramePerfection, merged by Cheezepin & Arceveti
- Automatically calculate the optimal collision distance for an object based on its vertices, by Kaze *
**Common Hack Changes:**
@@ -62,8 +63,8 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
- Removed course-specific camera processing *
- You can increase the number of frames that you have to perform a firsty *
- Ability to set Mario's movement speed when hanging from a ceiling *
- Tighter hanging controls (mario will face the direction of the analog stick directly while hanging from a ceiling) *
- reonucam3: custom camera by me. This is included as a .patch file in the enhancements folder, you need to apply it if you want this camera.
- Tighter hanging controls (Mario will face the direction of the analog stick directly while hanging from a ceiling) *
- reonucam3: custom camera by Reonu. This is included as a .patch file in the enhancements folder, you need to apply it if you want this camera.
This video shows a rundown of the features: https://youtu.be/TQNkznX9Z3k
- Ability to disable Mario getting suck in snow or sand
@@ -72,34 +73,34 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
- Debug mode: prints mario's coordinates, angle and speed, and a FPS counter.
- Automatic console/emulator detection. If emulator is detected, LODs are disabled. *
- Ability to configure whether there's a 100 coin star at all and how many coins are required to spawn it *
- Ability to easily change the warp that EXIT COURSE takes you to via config.h, or disable it entirely. *
- 16 bit model IDs by someone2639. This means you can have up to 65536 models (lol). You can set the maximum number of model IDs in `config.h`.
- Ability to easily change the warp that EXIT COURSE takes you to via `config/config_menu.h`, or disable it entirely. *
- 16 bit model IDs by someone2639. This means you can have up to 65536 models (lol). You can set the maximum number of model IDs in `config/config_game.h`.
- Apply_patch.sh improved
- Removed the ifdef hell in `file_select.c` and `ingame_menu.c`
- Added Blake's custom function for object model stuff: `obj_set_model` and `obj_has_model`
- Added function to get the model ID from an object: `obj_get_model_id` (by Arceveti)
- The "far" variable is now u16, allowing you to increase the farclip (the max distance at which geometry is rendered). However, when increasing the farclip, make sure to increase the nearclip by the same ratio, or rendering will break on console and LLE plugins.
- Many general use defines for object struct members, meant for use in custom object behaviors. Check `object_fields.h` for more info on this. (By MrComit)
- Many general use defines for object struct members, meant for use in custom object behaviors. Check `include/object_fields.h` for more info on this. (By MrComit)
- Included `actors/group0.c` in `behavior_data.c`
- The internal ROM name is now set with a define in `config.h` to make it simpler
- The internal ROM name is now set with a define in `config/config_rom.h` to make it simpler
- There is a `gIsConsole` variable that is 1 when running on console and 0 when running on emulator. This way you can wrap your code in a console check.
- Expanded audio heap allows for a larger concurrent note count and the importing of more m64 sequences and sound banks (By ArcticJaguar725) *
- You can set a test level in config.h in order to boot straight into it, so you can quickly test the level you're working on. *
- Allows all surfaces in the game to have a `force` parameter. Activating this doesn't REQUIRE you to set `force` for every surface: If you don't set, it will default to 0x0000 rather than crashing. Increases RAM usage of collision. *
- You can set a test level in `config/config_debug.h` in order to boot straight into it, so you can quickly test the level you're working on. *
- Allow all surfaces in the game to have a `force` parameter. Activating this doesn't REQUIRE you to set `force` for every surface: If you don't set, it will default to 0x0000 rather than crashing. Increases RAM usage of collision. *
- The clown font includes the entire English alphabet.
- Colored ia4 text support. Format: `"@XXXXXXXX[YOUR TEXT]@--------"` (By ArcticJaguar725)
- Example Text: `"@FF0000FFRED @00FF00FFGREEN @0000FFFFBLUE @FFFFFF00INVISIBLE @--------NORMAL"`
- NOTE: It is not mandatory to reset the text color with `"@--------"`, but text will need to be recolored each time it scrolls in a dialog box, or the custom color will reset.
- Toggle visiblity of collision surfaces and object hitboxes with Visual Surface Debug. `config.h` has VISUAL_DEBUG which can be turned on to enable this feature.
- Toggle visiblity of collision surfaces and object hitboxes with Visual Surface Debug. `config/config_debug.h` has VISUAL_DEBUG which can be turned on to enable this feature.
- Workaround for infinite death loops caused by using the wrong warp type for death warps. Mario's HP will be restored when being warped to any warp if (and only if) he was warped while dead. *
**Other Bugfixes:**
- Castle music fix (Fixes the castle music sometimes triggering after getting a dialog) *
- bparam4 fix (the game no longer uses bparam4 to check if an object is mario and therefore you can safely use it)
- Castle music fix (fixes the castle music sometimes triggering after getting a dialog) *
- bparam4 fix (the game no longer uses bparam4 to check if an object is Mario and therefore you can safely use it)
- Instant warp offset fix (makes the instant warp offset work even when warping to a different area) *
- haveyourcake, also known as cake screen fix. Made by Wiseguy and ported/PR'd by Cheezepin
- Tree particle fix (Whether a tree uses snow particles or not is decided via the model IDs instead of the course number) *
- Coordinate overflow fix by falcobuster. Your levels will render correctly on console and LLE emulators even when using 2x or 4x bounds, while not hurting anything on HLE plugins. *This is automatic now, you don't have to set WORLD_SCALE manually.*
- Adjustable world scale. You can change the geometry scaling of your level, which allow large levels to render correctly on console and LLE emulators while not hurting anything on HLE plugins.
- A couple vanilla texture fixes
- Smoke fix (the smoke texture uses the correct texture format)
@@ -108,14 +109,14 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
- This means that you'll have to do your framebuffer effects on buffer 0 for emulator, but NOT for console. You can use the `gIsConsole` variable to check for console when doing your framebuffer effects.
- Widescreen (16:9) support toggleable by pressing `L` in the pause menu. *
- S2DEX engine by someone2639! To use it, compile with `make TEXT_ENGINE=s2dex_text_engine` or just set `TEXT_ENGINE` to `s2dex_text_engine` in the makefile.
- ia8 coins (64x64), the vanilla coin texture is upgraded to accomodate. *
- ia8 30 FPS (64x64) coins (Textures by InTheBeef, cleaned up by Arceveti). *
- Floombas! Simply just retextured goombas with custom behaviors (does not overwrite standard goombas). *
- ia8 (64x64) coins, the vanilla coin texture is upgraded to accomodate. *
- ia8 (64x64) 30 FPS coins (Textures by InTheBeef, cleaned up by Arceveti). *
- Floombas! Simply just retextured goombas with customizable behaviors (does not overwrite standard goombas). *
- HD texture support for intro splash screen (with floombas if enabled). *
- Mario's silhouette is shown when behind most surfaces (By Frame#5375, Axollyon, AloXado320, Wiseguy, Arceveti) *
- Skybox size modifier. You can have 2x, 3x and 4x size skyboxes (you can select the skybox size in `config.h`.) Please note that this might affect console performance, especially 4x mode. 2x or 3x mode is recommended if aiming for console. By CowQuack *
- Skybox size modifier. You can have 2x, 3x and 4x size skyboxes (you can select the skybox size in `config/config_graphics.h`.) Please note that this might affect console performance, especially 4x mode. 2x or 3x mode is recommended if aiming for console. By CowQuack *
- You can set the black border size to different values for console and emulator. It's set to 0 by default for both. *
- This repo supports much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general. See `audio/synthesis.c` for more configuration info. (By ArcticJaguar725) *
- This repo supports a much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general. See `audio/synthesis.c` for more details and configuration info. (By ArcticJaguar725) *
- Fazana's "puppyprint" text engine. *
- Use `print_small_text` to print normal text. The two last params are aligment and how many characters to print (-1 means PRINT_ALL).
- Use `render_multi_image` to draw large texture rectangles consisting of multiple images on the screen.

1
VERSION.txt Normal file
View File

@@ -0,0 +1 @@
v2.0.3

View File

Before

Width:  |  Height:  |  Size: 995 B

After

Width:  |  Height:  |  Size: 995 B

View File

@@ -10,7 +10,7 @@ ALIGNED8 static const Texture flyguy_seg8_texture_0800E088[] = {
// 0x0800F088
ALIGNED8 static const Texture flyguy_seg8_texture_0800F088[] = {
#include "actors/flyguy/flyguy_face.rgba16.inc.c"
#include "actors/flyguy/flyguy_face.custom.rgba16.inc.c"
};
// 0x0800F888

View File

@@ -96,7 +96,7 @@ static const Vtx warp_pipe_seg3_vertex_03007DC0[] = {
// 0x03007E40
ALIGNED8 static const Texture warp_pipe_seg3_texture_03007E40[] = {
#include "actors/warp_pipe/warp_pipe_side.rgba16.inc.c"
#include "actors/warp_pipe/warp_pipe_side.custom.rgba16.inc.c"
};
// 0x03008E40 - 0x03008F98

View File

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1012 B

View File

@@ -1,48 +0,0 @@
# assembler directives
.set gp=64
.include "macros.inc"
.section .text, "ax"
.balign 32
glabel mtxf_to_mtx_asm
li $v0, 1
li.s $f4, 65536.0
1:
lwc1 $f0, ($a1)
lwc1 $f2, 0x04($a1)
andi $t0, $v0, (1 << 1)
mul.s $f0, $f4
trunc.w.s $f0, $f0
mfc1 $t3, $f0
addiu $a1, 8
sra $t4, $t3, 16
sh $t4, 0x00($a0)
sh $t3, 0x20($a0)
addiu $v0, 2
bnez $t0, storezero
mul.s $f2, $f4
trunc.w.s $f2, $f2
mfc1 $t3, $f2
sra $t4, $t3, 16
sh $t4, 0x02($a0)
sh $t3, 0x22($a0)
loopend:
.set noreorder
bnel $v0, 0x11, 1b
addiu $a0, 4
.set reorder
li $t1, 1
sh $t1, 0x02($a0)
jr $ra
storezero:
sh $zero, 0x02($a0)
sh $zero, 0x22($a0)
j loopend

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +0,0 @@
# Super Mario 64 Enhancements
This directory contains unofficial patches to the source code that provide various features
and enhancements.
To apply a patch, run `tools/apply_patch.sh [patch]` where `[patch]` is the name of the
.patch file you wish to apply. This will perform all of the patch's changes
to the source code.
Likewise, to undo the changes from a patch you applied, run
`tools/revert_patch.sh` with the name of the .patch file you wish to undo.
To create your own enhancement patch, switch to the `master` Git
branch, make your changes to the code (but do not commit), then run `tools/create_patch.sh`. Your changes will be stored in the .patch file you specify.
The following enhancements are included in this directory:
## Crash Screen - `crash.patch`
This enhancement provides a crash screen that is displayed when the code throws a hardware exception. This may be useful for diagnosing crashes in game code.
## Debug Box - `debug_box.patch`
This allows you to draw 3D boxes for debugging purposes.
Call the `debug_box` function whenever you want to draw one. `debug_box` by default takes two arguments: a center and bounds vec3f. This will draw a box starting from the point (center - bounds) to (center + bounds).
Use `debug_box_rot` to draw a box rotated in the xz-plane. If you want to draw a box by specifying min and max points, use `debug_box_pos` instead.
## FPS Counter - `fps.patch`
This patch provides an in-game FPS counter to measure the frame rate.
## iQue Player Support - `ique_support.patch`
This enhancement allows the same ROM to work on both the Nintendo 64 and the iQue Player.
## Memory Expansion Pak Error Screen - `mem_error_screen.patch`
Use this patch if your game requires over 4 MB of memory and requires the
Expansion Pak. If the Expansion Pak is not present, an error message will be
shown on startup.
## Demo Input Recorder - `record_demo.patch`
This patch allows you to record gameplay demos for the attract screen. It requires the latest nightly versions of Project64, and uses the Project64 JavaScript API to dump the demo input data from RAM and write it to a file.
Place the `enhancements/RecordDemo.js` file in the `/Scripts/` folder in the Project64 directory.
In the Scripts window, double click on "RecordDemo" on the list on the left side.
When this is done, it should turn green which lets you know that it has started.
When your demo has been recorded, it will be dumped to the newly created `/SM64_DEMOS/` folder within the Project64 directory.

View File

@@ -1,184 +0,0 @@
/*
* This is a companion file for the record_demo.inc.c enhancement.
*
* You will need the PJ64 javascript API to get this to work, so
* you should download a nightly build from here (Windows only atm):
* https://www.pj64-emu.com/nightly-builds
*
* Place this .js file into the /Scripts/ folder in the PJ64 directory.
*
* In the Scripts window, double click on "RecordDemo" on the list on the left side.
* When this is done, it should turn green which lets you know that it has started.
*
* When your demo has been recorded, it will be dumped to the newly created
* /SM64_DEMOS/ folder within the PJ64 directory.
*/
var RAM_SIZE = 4 * 1048576 // 4 MB
// Get a copy of the first 4MB of memory.
var RAM = mem.getblock(0x80000000, RAM_SIZE)
// Create SM64_DEMOS Directory if it already doesn't exist.
fs.mkdir("SM64_DEMOS/");
// string "DEMORECVARS"
var pattern = [0x44, 0x45, 0x4D, 0x4F, 0x52, 0x45, 0x43, 0x56, 0x41, 0x52, 0x53, 0x00]
var matches = find_matches_fast(pattern)
if(matches.length > 1) {
console.log('Error: More than 1 instance of "DEMORECVARS" was found. Abort!')
} else if(matches.length < 1) {
console.log('Error: No instance of "DEMORECVARS" was found. Abort!')
} else {
console.clear()
var demoRecVarsLocation = 0x80000000 + matches[0] + 12
// Control variables addresses
var gRecordingStatus_vaddr = demoRecVarsLocation + 0
var gDoneDelay_vaddr = demoRecVarsLocation + 4
var gNumOfRecordedInputs_vaddr = demoRecVarsLocation + 8
var gRecordedInputsPtr_vaddr = demoRecVarsLocation + 12
console.log('Recording variables were found at address 0x' + demoRecVarsLocation.toString(16))
console.log('Initialization successful! Press L in-game to ready the demo recording before entering in a level.')
// This runs every frame that is drawn.
events.ondraw(function() {
var gRecordingStatus = mem.u32[gRecordingStatus_vaddr]
if(gRecordingStatus == 3) { // gRecordingStatus == DEMOREC_STATUS_STOPPING
var gNumOfRecordedInputs = mem.u32[gNumOfRecordedInputs_vaddr]
if(gNumOfRecordedInputs < 1) {
console.log('Error: No inputs could be recorded!')
} else {
var gRecordedInputsPtr = mem.u32[gRecordedInputsPtr_vaddr]
console.log('Recorded ' + gNumOfRecordedInputs + ' demo inputs.')
// Grab demo data from RAM.
var demo_data = mem.getblock(gRecordedInputsPtr, (gNumOfRecordedInputs + 1) * 4)
// Create filename with random id added onto it.
var filename = 'SM64_DEMOS/demo_' + get_random_int(0, 0xFFFFFFFF).toString(16) + '.bin'
// Dump demo data to file.
var file = fs.open(filename, 'wb');
fs.write(file, demo_data);
fs.close(file);
console.log('Dumped data to file ' + filename)
}
// Set status to DEMOREC_STATUS_DONE
mem.u32[gRecordingStatus_vaddr] = 4;
// Decomp memes
console.log('OK');
}
})
}
function get_random_int(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/*
* Finds a byte pattern that is 4-byte aligned.
*
* The javascript api is pretty slow when reading memory directly,
* so I made this to search a copy of RAM to make things a little faster.
*/
function find_matches_fast(pattern) {
var targetLength = pattern.length
var targetLengthMinusOne = targetLength - 1
var matches = []
var matching = 0
// Increments by 8 to speed things up.
for(var i = 0; i < RAM_SIZE; i += 8) {
if(RAM[i] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i - targetLengthMinusOne)
matching = 0
}
if(matching > 0) {
if(RAM[i + 1] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 1 - targetLengthMinusOne)
matching = 0
}
if(matching > 1) {
if(RAM[i + 2] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 2 - targetLengthMinusOne)
matching = 0
}
if(matching > 2) {
if(RAM[i + 3] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 3 - targetLengthMinusOne)
matching = 0
}
}
}
}
if(RAM[i + 4] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 4 - targetLengthMinusOne)
matching = 0
}
if(matching > 0) {
if(RAM[i + 5] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 5 - targetLengthMinusOne)
matching = 0
}
if(matching > 1) {
if(RAM[i + 6] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 6 - targetLengthMinusOne)
matching = 0
}
if(matching > 2) {
if(RAM[i + 7] == pattern[matching])
matching++
else
matching = 0
if(matching == targetLength) {
matches.push(i + 7 - targetLengthMinusOne)
matching = 0
}
}
}
}
}
return matches
}

View File

@@ -1,485 +0,0 @@
diff --git a/asm/crash.s b/asm/crash.s
new file mode 100644
index 00000000..033bf952
--- /dev/null
+++ b/asm/crash.s
@@ -0,0 +1,153 @@
+// SM64 Crash Handler
+// See Readme below.
+
+#include "macros.inc"
+
+/* ---------------------------------------------------------------
+ * IMPORTANT README:
+ * ---------------------------------------------------------------
+ * Frame buffer emulation is required. To enable it in GlideN64,
+ * check "Emulate frame buffer" and "Render frame buffer to output"
+ * in the "Frame buffer" tab.
+ *
+ * Your emulator's CPU core style should be set to interpreter for best results.
+ *
+ * See the DEBUG_ASSERT macro on how to call the crash screen for
+ * detected exceptions.
+ *
+ */
+
+.set noat
+.set noreorder
+.set gp=64
+
+.set COP0_CAUSE, $13
+.set COP0_EPC, $14
+.set COP0_BADVADDR, $8
+
+glabel crashFont
+ .incbin "enhancements/crash_font.bin"
+ .align 4
+
+glabel exceptionRegContext
+ .fill 0x108
+
+glabel pAssertFile
+ .dword 0
+glabel nAssertLine
+ .dword 0
+glabel pAssertExpression
+ .dword 0
+glabel nAssertStopProgram
+ .dword 0
+
+glabel _n64_assert
+ lui $at, %hi(pAssertFile)
+ sw $a0, %lo(pAssertFile)($at)
+ lui $at, %hi(nAssertLine)
+ sw $a1, %lo(nAssertLine)($at)
+ lui $at, %hi(pAssertExpression)
+ sw $a2, %lo(pAssertExpression)($at)
+ lui $at, %hi(nAssertStopProgram)
+ sw $a3, %lo(nAssertStopProgram)($at)
+ beqz $a3, .end_2
+ nop
+ syscall // trigger crash screen
+.end_2:
+ jr $ra
+ nop
+
+glabel cop0_get_cause
+ jr $ra
+ mfc0 $v0, COP0_CAUSE
+
+glabel cop0_get_epc
+ jr $ra
+ mfc0 $v0, COP0_EPC
+
+glabel cop0_get_badvaddr
+ jr $ra
+ mfc0 $v0, COP0_BADVADDR
+
+// If the error code field of cop0's cause register is non-zero,
+// draw crash details to the screen and hang
+
+// If there wasn't an error, continue to the original handler
+
+glabel __crash_handler_entry
+ mfc0 $k1, COP0_CAUSE
+ andi $k1, $k1, (0x1F << 2)
+ beqzl $k1, .end2 // exit if ExCode is 0
+ lui $k0, %hi(__osException)
+ la $k0, exceptionRegContext
+ sd $zero, 0x018 ($k0)
+ sd $at, 0x020 ($k0)
+ sd $v0, 0x028 ($k0)
+ sd $v1, 0x030 ($k0)
+ sd $a0, 0x038 ($k0)
+ sd $a1, 0x040 ($k0)
+ sd $a2, 0x048 ($k0)
+ sd $a3, 0x050 ($k0)
+ sd $t0, 0x058 ($k0)
+ sd $t1, 0x060 ($k0)
+ sd $t2, 0x068 ($k0)
+ sd $t3, 0x070 ($k0)
+ sd $t4, 0x078 ($k0)
+ sd $t5, 0x080 ($k0)
+ sd $t6, 0x088 ($k0)
+ sd $t7, 0x090 ($k0)
+ sd $s0, 0x098 ($k0)
+ sd $s1, 0x0A0 ($k0)
+ sd $s2, 0x0A8 ($k0)
+ sd $s3, 0x0B0 ($k0)
+ sd $s4, 0x0B8 ($k0)
+ sd $s5, 0x0C0 ($k0)
+ sd $s6, 0x0C8 ($k0)
+ sd $s7, 0x0D0 ($k0)
+ sd $t8, 0x0D8 ($k0)
+ sd $t9, 0x0E0 ($k0)
+ sd $gp, 0x0E8 ($k0)
+ sd $sp, 0x0F0 ($k0)
+ sd $fp, 0x0F8 ($k0)
+ sd $ra, 0x100 ($k0)
+ // cop unusable exception fired twice on startup so we'll ignore it for now
+ li $t0, (0x0B << 2)
+ beq $k1, $t0, .end
+ nop
+ jal show_crash_screen_and_hang
+ nop
+ .end:
+ ld $at, 0x020 ($k0)
+ ld $v0, 0x028 ($k0)
+ ld $v1, 0x030 ($k0)
+ ld $a0, 0x038 ($k0)
+ ld $a1, 0x040 ($k0)
+ ld $a2, 0x048 ($k0)
+ ld $a3, 0x050 ($k0)
+ ld $t0, 0x058 ($k0)
+ ld $t1, 0x060 ($k0)
+ ld $t2, 0x068 ($k0)
+ ld $t3, 0x070 ($k0)
+ ld $t4, 0x078 ($k0)
+ ld $t5, 0x080 ($k0)
+ ld $t6, 0x088 ($k0)
+ ld $t7, 0x090 ($k0)
+ ld $s0, 0x098 ($k0)
+ ld $s1, 0x0A0 ($k0)
+ ld $s2, 0x0A8 ($k0)
+ ld $s3, 0x0B0 ($k0)
+ ld $s4, 0x0B8 ($k0)
+ ld $s5, 0x0C0 ($k0)
+ ld $s6, 0x0C8 ($k0)
+ ld $s7, 0x0D0 ($k0)
+ ld $t8, 0x0D8 ($k0)
+ ld $t9, 0x0E0 ($k0)
+ ld $gp, 0x0E8 ($k0)
+ ld $sp, 0x0F0 ($k0)
+ ld $fp, 0x0F8 ($k0)
+ ld $ra, 0x100 ($k0)
+ lui $k0, %hi(__osException)
+ .end2:
+ addiu $k0, $k0, %lo(__osException)
+ jr $k0 // run the original handler
+ nop
diff --git a/lib/asm/__osExceptionPreamble.s b/lib/asm/__osExceptionPreamble.s
index c3b97993..c552a485 100644
--- a/lib/asm/__osExceptionPreamble.s
+++ b/lib/asm/__osExceptionPreamble.s
@@ -11,8 +11,8 @@
#endif
glabel __osExceptionPreamble
- lui $k0, %hi(__osException)
- addiu $k0, %lo(__osException)
+ lui $k0, %hi(__crash_handler_entry)
+ addiu $k0, %lo(__crash_handler_entry)
jr $k0
nop
diff --git a/sm64.ld b/sm64.ld
index 7d9b5b4a..c7bb81b9 100755
--- a/sm64.ld
+++ b/sm64.ld
@@ -117,6 +117,7 @@ SECTIONS
BUILD_DIR/src/game/rendering_graph_node.o(.text);
BUILD_DIR/src/game/profiler.o(.text);
BUILD_DIR/asm/decompress.o(.text);
+ BUILD_DIR/asm/crash.o(.text);
BUILD_DIR/src/game/camera.o(.text);
BUILD_DIR/src/game/object_list_processor.o(.text);
diff --git a/src/game/crash.c b/src/game/crash.c
new file mode 100644
index 00000000..716adfbd
--- /dev/null
+++ b/src/game/crash.c
@@ -0,0 +1,260 @@
+/* SM64 Crash Handler */
+
+#include <sm64.h>
+
+#include "crash.h"
+
+extern u32 exceptionRegContext[];
+
+extern char *pAssertFile;
+extern int nAssertLine;
+extern char *pAssertExpression;
+extern int nAssertStopProgram;
+
+u16 fbFillColor = 0xFFFF;
+u16 fbShadeColor = 0x0000;
+u16 *fbAddress = NULL;
+
+extern u8 crashFont[];
+
+const char *szErrCodes[] = {
+ "INTERRUPT",
+ "TLB MOD",
+ "UNMAPPED LOAD ADDR",
+ "UNMAPPED STORE ADDR",
+ "BAD LOAD ADDR",
+ "BAD STORE ADDR",
+ "BUS ERR ON INSTR FETCH",
+ "BUS ERR ON LOADSTORE",
+ "SYSCALL",
+ "BREAKPOINT",
+ "UNKNOWN INSTR",
+ "COP UNUSABLE",
+ "ARITHMETIC OVERFLOW",
+ "TRAP EXC",
+ "VIRTUAL COHERENCY INSTR",
+ "FLOAT EXC",
+};
+
+const char *szGPRegisters1[] = { "R0", "AT", "V0", "V1", "A0", "A1", "A2", "A3",
+ "T0", "T1", "T2", "T3", "T4", "T5", "T6", NULL };
+
+const char *szGPRegisters2[] = { "T7", "S0", "S1", "S2", "S3", "S4",
+ "S5", "S6", "S7", "T8", "T9", /*"K0", "K1",*/
+ "GP", "SP", "FP", "RA", NULL };
+
+int crash_strlen(char *str) {
+ int len = 0;
+ while (*str++) {
+ len++;
+ }
+ return len;
+}
+
+void show_crash_screen_and_hang(void) {
+ u32 cause;
+ u32 epc;
+ u8 errno;
+
+ fb_set_address((void *) (*(u32 *) 0xA4400004 | 0x80000000)); // replace me
+
+ cause = cop0_get_cause();
+ epc = cop0_get_epc();
+
+ errno = (cause >> 2) & 0x1F;
+
+ if (nAssertStopProgram == 0) {
+ fbFillColor = 0x6253;
+ fb_fill(10, 10, 300, 220);
+
+ fb_print_str(80, 20, "AN ERROR HAS OCCURRED!");
+ fb_print_int_hex(80, 30, errno, 8);
+ fb_print_str(95, 30, szErrCodes[errno]);
+
+ if (errno >= 2 && errno <= 5) {
+ /*
+ 2 UNMAPPED LOAD ADDR
+ 3 UNMAPPED STORE ADDR
+ 4 BAD LOAD ADDR
+ 5 BAD STORE ADDR
+ */
+ u32 badvaddr = cop0_get_badvaddr();
+
+ fb_print_str(145, 50, "VA");
+ fb_print_int_hex(160, 50, badvaddr, 32);
+ }
+ } else {
+ int afterFileX;
+ int exprBoxWidth;
+ fbFillColor = 0x5263;
+ fb_fill(10, 10, 300, 220);
+
+ fb_print_str(80, 20, "ASSERTION FAILED!");
+
+ afterFileX = fb_print_str(80, 30, pAssertFile);
+ fb_print_str(afterFileX, 30, ":");
+ fb_print_uint(afterFileX + 5, 30, nAssertLine);
+
+ exprBoxWidth = (crash_strlen(pAssertExpression) * 5) + 2;
+ fbFillColor = 0x0001;
+ fb_fill(80 - 1, 40 - 1, exprBoxWidth, 10);
+ fb_print_str(80, 40, pAssertExpression);
+ }
+
+ fb_print_str(80, 50, "PC");
+ fb_print_int_hex(95, 50, epc, 32);
+
+ fb_print_gpr_states(80, 70, szGPRegisters1, &exceptionRegContext[6 + 0]);
+ fb_print_gpr_states(145, 70, szGPRegisters2, &exceptionRegContext[6 + 15 * 2]);
+
+ fb_swap();
+ osWritebackDCacheAll();
+
+ while (1) // hang forever
+ {
+ UNUSED volatile int t = 0; // keep pj64 happy
+ }
+}
+
+u8 ascii_to_idx(char c) {
+ return c - 0x20;
+}
+
+void fb_set_address(void *address) {
+ fbAddress = (u16 *) address;
+}
+
+void fb_swap() {
+ // update VI frame buffer register
+ // todo other registers
+ *(u32 *) (0xA4400004) = (u32) fbAddress & 0x00FFFFFF;
+}
+
+void fb_fill(int baseX, int baseY, int width, int height) {
+ int y, x;
+
+ for (y = baseY; y < baseY + height; y++) {
+ for (x = baseX; x < baseX + width; x++) {
+ fbAddress[y * 320 + x] = fbFillColor;
+ }
+ }
+}
+
+void fb_draw_char(int x, int y, u8 idx) {
+ u16 *out = &fbAddress[y * 320 + x];
+ const u8 *in = &crashFont[idx * 3];
+ int nbyte;
+ int nrow;
+ int ncol;
+
+ for (nbyte = 0; nbyte < 3; nbyte++) {
+ u8 curbyte = in[nbyte];
+ for (nrow = 0; nrow < 2; nrow++) {
+ for (ncol = 0; ncol < 4; ncol++) {
+ u8 px = curbyte & (1 << (7 - (nrow * 4 + ncol)));
+ if (px != 0) {
+ out[ncol] = fbFillColor;
+ }
+ }
+ out += 320;
+ }
+ }
+}
+
+void fb_draw_char_shaded(int x, int y, u8 idx) {
+ fbFillColor = 0x0001;
+ fb_draw_char(x - 1, y + 1, idx);
+
+ fbFillColor = 0xFFFF;
+ fb_draw_char(x, y, idx);
+}
+
+int fb_print_str(int x, int y, const char *str) {
+ while (1) {
+ int yoffs = 0;
+ u8 idx;
+ char c = *str++;
+
+ if (c == '\0') {
+ break;
+ }
+
+ if (c == ' ') {
+ x += 5;
+ continue;
+ }
+
+ switch (c) {
+ case 'j':
+ case 'g':
+ case 'p':
+ case 'q':
+ case 'y':
+ case 'Q':
+ yoffs = 1;
+ break;
+ case ',':
+ yoffs = 2;
+ break;
+ }
+
+ idx = ascii_to_idx(c);
+ fb_draw_char_shaded(x, y + yoffs, idx);
+ x += 5;
+ }
+
+ return x;
+}
+
+void fb_print_int_hex(int x, int y, u32 value, int nbits) {
+ nbits -= 4;
+
+ while (nbits >= 0) {
+ int nib = ((value >> nbits) & 0xF);
+ u8 idx;
+
+ if (nib > 9) {
+ idx = ('A' - 0x20) + (nib - 0xa);
+ } else {
+ idx = ('0' - 0x20) + nib;
+ }
+
+ fb_draw_char_shaded(x, y, idx);
+ x += 5;
+
+ nbits -= 4;
+ }
+}
+
+int fb_print_uint(int x, int y, u32 value) {
+ int nchars = 0;
+
+ int v = value;
+ int i;
+ while (v /= 10) {
+ nchars++;
+ }
+
+ x += nchars * 5;
+
+ for (i = nchars; i >= 0; i--) {
+ fb_draw_char_shaded(x, y, ('0' - 0x20) + (value % 10));
+ value /= 10;
+ x -= 5;
+ }
+
+ return (x + nchars * 5);
+}
+
+void fb_print_gpr_states(int x, int y, const char *regNames[], u32 *regContext) {
+ int i;
+ for (i = 0;; i++) {
+ if (regNames[i] == NULL) {
+ break;
+ }
+
+ fb_print_str(x, y, regNames[i]);
+ fb_print_int_hex(x + 15, y, regContext[i * 2 + 1], 32);
+ y += 10;
+ }
+}
diff --git a/src/game/crash.h b/src/game/crash.h
new file mode 100644
index 00000000..1386930d
--- /dev/null
+++ b/src/game/crash.h
@@ -0,0 +1,28 @@
+#ifndef _CRASH_H_
+#define _CRASH_H_
+
+#include <types.h>
+
+#define CRASH_SCREEN_INCLUDED 1
+
+extern u32 cop0_get_cause(void);
+extern u32 cop0_get_epc(void);
+extern u32 cop0_get_badvaddr(void);
+
+extern void _n64_assert(const char* pFile, int nLine, const char *pExpression, int nStopProgram);
+
+extern u8 __crash_handler_entry[];
+
+void show_crash_screen_and_hang(void);
+u8 ascii_to_idx(char c);
+void fb_set_address(void *address);
+void fb_swap(void);
+void fb_fill(int baseX, int baseY, int width, int height);
+void fb_draw_char(int x, int y, u8 idx);
+void fb_draw_char_shaded(int x, int y, u8 idx);
+int fb_print_str(int x, int y, const char *str);
+int fb_print_uint(int x, int y, u32 value);
+void fb_print_int_hex(int x, int y, u32 value, int nbits);
+void fb_print_gpr_states(int x, int y, const char* regStrs[], u32 *regContext);
+
+#endif /* _CRASH_H_ */

Binary file not shown.

View File

@@ -1,340 +0,0 @@
diff --git a/src/game/area.c b/src/game/area.c
index af9d0156..c68a7f6e 100644
--- a/src/game/area.c
+++ b/src/game/area.c
@@ -22,6 +22,7 @@
#include "save_file.h"
#include "level_table.h"
#include "dialog_ids.h"
+#include "debug_box.h"
struct SpawnInfo gPlayerSpawnInfos[1];
struct GraphNode *gGraphNodePointers[0x100];
@@ -363,6 +364,8 @@ void render_game(void) {
if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) {
geo_process_root(gCurrentArea->unk04, D_8032CE74, D_8032CE78, gFBSetColor);
+ render_debug_boxes();
+
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00));
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH,
diff --git a/src/game/debug_box.c b/src/game/debug_box.c
new file mode 100644
index 00000000..1ffe0288
--- /dev/null
+++ b/src/game/debug_box.c
@@ -0,0 +1,281 @@
+#include <ultra64.h>
+
+#include "sm64.h"
+#include "game/game_init.h"
+#include "game/geo_misc.h"
+#include "engine/math_util.h"
+
+#include "debug_box.h"
+
+/**
+ * @file debug_box.c
+ * Draws 3D boxes for debugging purposes.
+ *
+ * How to use:
+ *
+ * In render_game() in area.c, add a call to render_debug_boxes():
+ *
+ * void render_game(void) {
+ * if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) {
+ * geo_process_root(...);
+ *
+ * render_debug_boxes(); // add here
+ *
+ * gSPViewport(...);
+ * gDPSetScissor(...);
+ * //...
+ *
+ * Now just call debug_box() whenever you want to draw one!
+ *
+ * debug_box by default takes two arguments: a center and bounds vec3f.
+ * This will draw a box starting from the point (center - bounds) to (center + bounds).
+ *
+ * Use debug_box_rot to draw a box rotated in the xz-plane.
+ *
+ * If you want to draw a box by specifying min and max points, use debug_box_pos() instead.
+ */
+
+/**
+ * Internal struct containing box info
+ */
+struct DebugBox {
+ u32 color;
+ Vec3s center;
+ Vec3s bounds;
+ s16 yaw;
+};
+
+struct DebugBox sBoxes[MAX_DEBUG_BOXES];
+s16 sNumBoxes = 0;
+
+extern Mat4 gMatStack[32]; //XXX: Hack
+
+/**
+ * The debug boxes' default transparency
+ */
+#define DBG_BOX_ALPHA 0x7F
+/**
+ * The debug boxes' default color. sCurBoxColor is reset to this every frame.
+ */
+#define DBG_BOX_DEF_COLOR 0xFF0000
+
+/**
+ * The color that new boxes will be drawn with.
+ */
+u32 sCurBoxColor = DBG_BOX_ALPHA << 24 | DBG_BOX_DEF_COLOR;
+
+/**
+ * The allocated size of a rotated box's dl
+ */
+#define DBG_BOX_ROT_DLSIZE ((s32)(6 * sizeof(Gfx) + 8 * sizeof(Vtx)))
+/**
+ * The allocated size of a normal box's dl
+ */
+#define DBG_BOX_DLSIZE ((s32)(2 * sizeof(Gfx) + 8 * sizeof(Vtx)))
+
+/**
+ * Sets up the RCP for drawing the boxes
+ */
+static const Gfx dl_debug_box_begin[] = {
+ gsDPPipeSync(),
+#if DBG_BOX_ALPHA < 0xFF
+ gsDPSetRenderMode(G_RM_ZB_XLU_SURF, G_RM_NOOP2),
+#else
+ gsDPSetRenderMode(G_RM_ZB_OPA_SURF, G_RM_NOOP2),
+#endif
+ gsSPClearGeometryMode(G_LIGHTING | G_CULL_BACK),
+ gsSPSetGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH),
+ gsSPTexture(0, 0, 0, 0, G_OFF),
+ gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
+ gsSPEndDisplayList(),
+};
+
+/**
+ * Actually draws the box
+ */
+static const Gfx dl_debug_draw_box[] = {
+ gsSP2Triangles(5, 4, 6, 0x0, 5, 6, 7, 0x0), // front
+ gsSP2Triangles(0, 1, 2, 0x0, 2, 1, 3, 0x0), // back
+
+ gsSP2Triangles(4, 0, 2, 0x0, 2, 6, 4, 0x0), // left
+ gsSP2Triangles(1, 5, 3, 0x0, 3, 5, 7, 0x0), // right
+
+ gsSP2Triangles(1, 0, 4, 0x0, 1, 4, 5, 0x0), // top
+ gsSP2Triangles(2, 3, 6, 0x0, 6, 3, 7, 0x0), // bottom
+
+ gsSPEndDisplayList(),
+};
+
+/**
+ * Adds a box to the list to be rendered this frame.
+ *
+ * If there are already MAX_DEBUG_BOXES boxes, does nothing.
+ */
+static void append_debug_box(Vec3f center, Vec3f bounds, s16 yaw)
+{
+ if (sNumBoxes >= MAX_DEBUG_BOXES) {
+ return;
+ }
+
+ vec3f_to_vec3s(sBoxes[sNumBoxes].center, center);
+ vec3f_to_vec3s(sBoxes[sNumBoxes].bounds, bounds);
+
+ sBoxes[sNumBoxes].yaw = yaw;
+ sBoxes[sNumBoxes].color = sCurBoxColor;
+
+ ++sNumBoxes;
+}
+
+/**
+ * Draw new boxes with the given color.
+ * Color format is 32-bit ARGB.
+ * If the alpha component is zero, DBG_BOX_ALPHA (0x7f) will be used instead.
+ * Ex: 0xFF0000 becomes 0x7FFF0000
+ */
+void debug_box_color(u32 color)
+{
+ if ((color >> 24) == 0) color |= (DBG_BOX_ALPHA << 24);
+ sCurBoxColor = color;
+}
+
+/**
+ * Draws a debug box from (center - bounds) to (center + bounds)
+ * To draw a rotated box, use debug_box_rot()
+ *
+ * @see debug_box_rot()
+ */
+void debug_box(Vec3f center, Vec3f bounds)
+{
+ append_debug_box(center, bounds, 0);
+}
+
+/**
+ * Draws a debug box from (center - bounds) to (center + bounds), rotating it by `yaw`
+ */
+void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw)
+{
+ append_debug_box(center, bounds, yaw);
+}
+
+/**
+ * Draws a debug box from pMin to pMax
+ * To draw a rotated box this way, use debug_box_pos_rot()
+ *
+ * @see debug_box_pos_rot()
+ */
+void debug_box_pos(Vec3f pMin, Vec3f pMax)
+{
+ debug_box_pos_rot(pMin, pMax, 0);
+}
+
+/**
+ * Draws a debug box from pMin to pMax, rotating it in the xz-plane by `yaw`
+ */
+void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw)
+{
+ Vec3f center, bounds;
+
+ bounds[0] = (pMax[0] - pMin[0]) / 2.0f;
+ bounds[1] = (pMax[1] - pMin[1]) / 2.0f;
+ bounds[2] = (pMax[2] - pMin[2]) / 2.0f;
+
+ center[0] = pMin[0] + bounds[0];
+ center[1] = pMin[1] + bounds[1];
+ center[2] = pMin[2] + bounds[2];
+
+ append_debug_box(center, bounds, yaw);
+}
+
+static void render_box(int index)
+{
+ Vtx *verts;
+ Mtx *translate;
+ Mtx *rotate;
+ Mtx *translateback;
+ struct DebugBox *box = &sBoxes[index];
+ u32 color = box->color;
+
+ s32 x0 = box->center[0],
+ y0 = box->center[1],
+ z0 = box->center[2];
+
+ s32 xb = box->bounds[0],
+ yb = box->bounds[1],
+ zb = box->bounds[2];
+
+ if (box->yaw != 0 && (Gfx*)gGfxPoolEnd - gDisplayListHead < DBG_BOX_ROT_DLSIZE)
+ return;
+ else if ((Gfx*)gGfxPoolEnd - gDisplayListHead < DBG_BOX_DLSIZE)
+ return;
+
+ verts = alloc_display_list(8 * sizeof(Vtx));
+
+ if (verts != NULL) {
+ if (box->yaw != 0) {
+ // Translate to the origin, rotate, then translate back, effectively rotating the box about
+ // its center
+ translate = alloc_display_list(sizeof(Mtx));
+ rotate = alloc_display_list(sizeof(Mtx));
+ translateback = alloc_display_list(sizeof(Mtx));
+
+ guTranslate(translate, box->center[0], box->center[1], box->center[2]);
+ guRotate(rotate, box->yaw / (float)0x10000 * 360.0f, 0, 1.0f, 0);
+ guTranslate(translateback, -box->center[0], -box->center[1], -box->center[2]);
+
+ gSPMatrix(gDisplayListHead++, translate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
+ gSPMatrix(gDisplayListHead++, rotate, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
+ gSPMatrix(gDisplayListHead++, translateback, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
+ }
+
+#define DBG_BOX_COL /**/ (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, (color >> 24) & 0xff
+#define DBG_BOX_VTX(i, x, y, z) make_vertex(verts, i, x, y, z, 0, 0, DBG_BOX_COL)
+ DBG_BOX_VTX(0, x0 - xb, y0 + yb, z0 - zb);
+ DBG_BOX_VTX(1, x0 + xb, y0 + yb, z0 - zb);
+ DBG_BOX_VTX(2, x0 - xb, y0 - yb, z0 - zb);
+ DBG_BOX_VTX(3, x0 + xb, y0 - yb, z0 - zb);
+ DBG_BOX_VTX(4, x0 - xb, y0 + yb, z0 + zb);
+ DBG_BOX_VTX(5, x0 + xb, y0 + yb, z0 + zb);
+ DBG_BOX_VTX(6, x0 - xb, y0 - yb, z0 + zb);
+ DBG_BOX_VTX(7, x0 + xb, y0 - yb, z0 + zb);
+#undef DBG_BOX_VTX
+
+ gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(verts), 8, 0);
+
+ gSPDisplayList(gDisplayListHead++, dl_debug_draw_box);
+
+ if (box->yaw != 0) {
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
+ }
+ }
+}
+
+void render_debug_boxes(void)
+{
+ s32 i;
+ Mtx *mtx;
+
+ debug_box_color(DBG_BOX_DEF_COLOR);
+
+ if (sNumBoxes == 0) {
+ return;
+ }
+
+ mtx = alloc_display_list(sizeof(Mtx));
+ // Don't draw if there isn't space for the configuration + at least one box
+ if (mtx == NULL || ((Gfx*)gGfxPoolEnd - gDisplayListHead) <= (s32)(2 * sizeof(Gfx)) + DBG_BOX_DLSIZE) {
+ sNumBoxes = 0;
+ return;
+ }
+
+ //XXX: This is hacky. Ths camera's look-at matrix is stored in gMatStack[1], so this is a simple way
+ // of using it without reconstructing the matrix.
+ mtxf_to_mtx(mtx, gMatStack[1]);
+ gSPMatrix(gDisplayListHead++, mtx, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
+ gSPDisplayList(gDisplayListHead++, dl_debug_box_begin);
+
+ for (i = 0; i < sNumBoxes; ++i) {
+ render_box(i);
+ }
+
+ sNumBoxes = 0;
+}
diff --git a/src/game/debug_box.h b/src/game/debug_box.h
new file mode 100644
index 00000000..540c85e4
--- /dev/null
+++ b/src/game/debug_box.h
@@ -0,0 +1,26 @@
+#ifndef DEBUG_BOX_H
+#define DEBUG_BOX_H
+
+/**
+ * @file debug_box.h
+ * Draws debug boxes, see debug_box.c for details
+ */
+
+#include "types.h"
+
+/**
+ * The max amount of debug boxes before debug_box() just returns.
+ * You can set this to something higher, but you might run out of space in the gfx pool.
+ */
+#define MAX_DEBUG_BOXES 512
+
+void debug_box_color(u32 color);
+void debug_box(Vec3f center, Vec3f bounds);
+void debug_box_rot(Vec3f center, Vec3f bounds, s16 yaw);
+
+void debug_box_pos(Vec3f pMin, Vec3f pMax);
+void debug_box_pos_rot(Vec3f pMin, Vec3f pMax, s16 yaw);
+
+void render_debug_boxes(void);
+
+#endif /* DEBUG_BOX_H */

View File

@@ -1,60 +0,0 @@
diff --git a/src/game/game_init.c b/src/game/game_init.c
index b961ca52..531231cf 100644
--- a/src/game/game_init.c
+++ b/src/game/game_init.c
@@ -82,6 +82,47 @@ struct DemoInput gRecordedDemoInput = { 0 };
// Display
// ----------------------------------------------------------------------------------------------------
+// SDK states that 1 cycle takes about 21.33 nanoseconds
+#define SECONDS_PER_CYCLE 0.00000002133f
+
+#define FPS_COUNTER_X_POS 24
+#define FPS_COUNTER_Y_POS 190
+
+static OSTime gLastOSTime = 0;
+static float gFrameTime = 0.0f;
+static u16 gFrames = 0;
+static u16 gFPS = 0;
+static u8 gRenderFPS = FALSE;
+
+static void calculate_frameTime_from_OSTime(OSTime diff) {
+ gFrameTime += diff * SECONDS_PER_CYCLE;
+ gFrames++;
+}
+
+static void render_fps(void) {
+ // Toggle rendering framerate with the L button.
+ if (gPlayer1Controller->buttonPressed & L_TRIG) {
+ gRenderFPS ^= 1;
+ }
+
+ if (gRenderFPS) {
+ OSTime newTime = osGetTime();
+
+ calculate_frameTime_from_OSTime(newTime - gLastOSTime);
+
+ // If frame time is longer or equal to a second, update FPS counter.
+ if (gFrameTime >= 1.0f) {
+ gFPS = gFrames;
+ gFrames = 0;
+ gFrameTime -= 1.0f;
+ }
+
+ print_text_fmt_int(FPS_COUNTER_X_POS, FPS_COUNTER_Y_POS, "FPS %d", gFPS);
+
+ gLastOSTime = newTime;
+ }
+}
+
/**
* Sets the initial RDP (Reality Display Processor) rendering settings.
*/
@@ -694,5 +735,7 @@ void thread5_game_loop(UNUSED void *arg) {
// amount of free space remaining.
print_text_fmt_int(180, 20, "BUF %d", gGfxPoolEnd - (u8 *) gDisplayListHead);
}
+
+ render_fps();
}
}

View File

@@ -1,312 +0,0 @@
diff --git a/include/PR/console_type.h b/include/PR/console_type.h
new file mode 100644
index 00000000..e60550ab
--- /dev/null
+++ b/include/PR/console_type.h
@@ -0,0 +1,7 @@
+enum ConsoleType {
+ CONSOLE_N64,
+ CONSOLE_IQUE
+};
+
+extern enum ConsoleType gConsoleType;
+extern enum ConsoleType get_console_type(void);
diff --git a/lib/asm/skGetId.s b/lib/asm/skGetId.s
new file mode 100644
index 00000000..58e7d4f9
--- /dev/null
+++ b/lib/asm/skGetId.s
@@ -0,0 +1,18 @@
+// Code by stuckpixel
+
+.set noreorder
+.set gp=64
+
+#include "macros.inc"
+
+glabel skGetId
+ li $v0, 0
+ li $t0, 0xA4300014
+ lw $t1, 0x00($t0)
+ nop
+ jr $ra
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/lib/src/__osViSwapContext.c b/lib/src/__osViSwapContext.c
index 990cb11f..22756e91 100644
--- a/lib/src/__osViSwapContext.c
+++ b/lib/src/__osViSwapContext.c
@@ -54,7 +54,9 @@ void __osViSwapContext() {
HW_REG(VI_INTR_REG, u32) = s0->fldRegs[field].vIntr;
HW_REG(VI_X_SCALE_REG, u32) = s1->unk20;
HW_REG(VI_Y_SCALE_REG, u32) = s1->unk2c;
- HW_REG(VI_CONTROL_REG, u32) = s1->features;
+ /* Make sure bit 13 is cleared. Otherwise, graphics will be corrupted on
+ * iQue Player. This has no effect on N64. */
+ HW_REG(VI_CONTROL_REG, u32) = s1->features & ~(1 << 13);
__osViNext = __osViCurr;
__osViCurr = s1;
*__osViNext = *__osViCurr;
diff --git a/lib/src/consoleType.c b/lib/src/consoleType.c
new file mode 100644
index 00000000..ef08d1ef
--- /dev/null
+++ b/lib/src/consoleType.c
@@ -0,0 +1,12 @@
+#include "libultra_internal.h"
+#include <PR/console_type.h>
+
+enum ConsoleType gConsoleType;
+
+void skGetId(u32 *out);
+
+enum ConsoleType get_console_type(void) {
+ u32 id = 0;
+ skGetId(&id);
+ return (id == 0) ? CONSOLE_N64 : CONSOLE_IQUE;
+}
diff --git a/lib/src/osEepromProbe.c b/lib/src/osEepromProbe.c
index d550b846..bbaf2bcc 100644
--- a/lib/src/osEepromProbe.c
+++ b/lib/src/osEepromProbe.c
@@ -1,4 +1,5 @@
#include "libultra_internal.h"
+#include <PR/console_type.h>
// TODO: merge with osEepromWrite
typedef struct {
@@ -13,11 +14,23 @@ s32 osEepromProbe(OSMesgQueue *mq) {
unkStruct sp18;
__osSiGetAccess();
- status = __osEepStatus(mq, &sp18);
- if (status == 0 && (sp18.unk00 & 0x8000) != 0) {
- status = 1;
- } else {
- status = 0;
+ if (gConsoleType == CONSOLE_N64) {
+ status = __osEepStatus(mq, &sp18);
+ if (status == 0 && (sp18.unk00 & 0x8000) != 0) {
+ status = 1;
+ } else {
+ status = 0;
+ }
+ } else if (gConsoleType == CONSOLE_IQUE) {
+ s32 __osBbEepromSize = * (s32*) 0x80000360;
+
+ if (__osBbEepromSize == 0x200) {
+ status = 1;
+ }
+
+ if (__osBbEepromSize == 0x800) {
+ status = 2;
+ }
}
__osSiRelAccess();
return status;
diff --git a/lib/src/osEepromRead.c b/lib/src/osEepromRead.c
index ea784b2c..116dae2d 100644
--- a/lib/src/osEepromRead.c
+++ b/lib/src/osEepromRead.c
@@ -1,4 +1,5 @@
#include "libultra_internal.h"
+#include <PR/console_type.h>
extern u8 _osLastSentSiCmd;
@@ -42,33 +43,44 @@ s32 osEepromRead(OSMesgQueue *mq, u8 address, u8 *buffer) {
return -1;
}
__osSiGetAccess();
- sp34 = __osEepStatus(mq, &sp28);
- if (sp34 != 0 || sp28.unk00 != 0x8000) {
+ if (gConsoleType == CONSOLE_N64) {
+ sp34 = __osEepStatus(mq, &sp28);
+ if (sp34 != 0 || sp28.unk00 != 0x8000) {
- return 8;
- }
- while (sp28.unk02 & 0x80) {
- __osEepStatus(mq, &sp28);
- }
- __osPackEepReadData(address);
- sp34 = __osSiRawStartDma(OS_WRITE, &D_80365E00);
- osRecvMesg(mq, NULL, OS_MESG_BLOCK);
- for (sp30 = 0; sp30 < 0x10; sp30++) {
- (D_80365E00)[sp30] = 255;
- }
- D_80365E3C = 0;
- sp34 = __osSiRawStartDma(OS_READ, D_80365E00);
- _osLastSentSiCmd = 4;
- osRecvMesg(mq, NULL, OS_MESG_BLOCK);
- for (sp30 = 0; sp30 < 4; sp30++) {
- sp2c++;
- }
- sp20 = *(unkStruct2 *) sp2c;
- sp34 = (sp20.unk01 & 0xc0) >> 4;
- if (sp34 == 0) {
- for (sp30 = 0; sp30 < 8; sp30++) {
- *buffer++ = ((u8 *) &sp20.unk04)[sp30];
+ return 8;
+ }
+ while (sp28.unk02 & 0x80) {
+ __osEepStatus(mq, &sp28);
+ }
+ __osPackEepReadData(address);
+ sp34 = __osSiRawStartDma(OS_WRITE, &D_80365E00);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ for (sp30 = 0; sp30 < 0x10; sp30++) {
+ (D_80365E00)[sp30] = 255;
}
+ D_80365E3C = 0;
+ sp34 = __osSiRawStartDma(OS_READ, D_80365E00);
+ _osLastSentSiCmd = 4;
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ for (sp30 = 0; sp30 < 4; sp30++) {
+ sp2c++;
+ }
+ sp20 = *(unkStruct2 *) sp2c;
+ sp34 = (sp20.unk01 & 0xc0) >> 4;
+ if (sp34 == 0) {
+ for (sp30 = 0; sp30 < 8; sp30++) {
+ *buffer++ = ((u8 *) &sp20.unk04)[sp30];
+ }
+ }
+ } else if (gConsoleType == CONSOLE_IQUE) {
+ u8 *__osBbEepromAddress = * (u8**) 0x8000035C;
+ s32 i;
+
+ for (i = 0; i < 8; i++) {
+ buffer[i] = __osBbEepromAddress[(address << 3) + i];
+ }
+
+ sp34 = 0;
}
__osSiRelAccess();
return sp34;
diff --git a/lib/src/osEepromWrite.c b/lib/src/osEepromWrite.c
index 1a86477b..a94f8721 100644
--- a/lib/src/osEepromWrite.c
+++ b/lib/src/osEepromWrite.c
@@ -1,5 +1,6 @@
#include "libultra_internal.h"
#include "osContInternal.h"
+#include <PR/console_type.h>
#ifndef AVOID_UB
ALIGNED8 u32 D_80365E00[15];
@@ -52,36 +53,47 @@ s32 osEepromWrite(OSMesgQueue *mq, u8 address, u8 *buffer) {
}
__osSiGetAccess();
- sp34 = __osEepStatus(mq, &sp1c);
+ if (gConsoleType == CONSOLE_N64) {
+ sp34 = __osEepStatus(mq, &sp1c);
- if (sp34 != 0 || sp1c.unk00 != 0x8000) {
- return 8;
- }
+ if (sp34 != 0 || sp1c.unk00 != 0x8000) {
+ return 8;
+ }
- while (sp1c.unk02 & 0x80) {
- __osEepStatus(mq, &sp1c);
- }
+ while (sp1c.unk02 & 0x80) {
+ __osEepStatus(mq, &sp1c);
+ }
- __osPackEepWriteData(address, buffer);
+ __osPackEepWriteData(address, buffer);
- sp34 = __osSiRawStartDma(OS_WRITE, &D_80365E00);
- osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ sp34 = __osSiRawStartDma(OS_WRITE, &D_80365E00);
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
- for (sp30 = 0; sp30 < 0x10; sp30++) {
- (D_80365E00)[sp30] = 255;
- }
+ for (sp30 = 0; sp30 < 0x10; sp30++) {
+ (D_80365E00)[sp30] = 255;
+ }
- D_80365E3C = 0;
- sp34 = __osSiRawStartDma(OS_READ, D_80365E00);
- _osLastSentSiCmd = 5;
- osRecvMesg(mq, NULL, OS_MESG_BLOCK);
+ D_80365E3C = 0;
+ sp34 = __osSiRawStartDma(OS_READ, D_80365E00);
+ _osLastSentSiCmd = 5;
+ osRecvMesg(mq, NULL, OS_MESG_BLOCK);
- for (sp30 = 0; sp30 < 4; sp30++) {
- sp2c++;
- }
+ for (sp30 = 0; sp30 < 4; sp30++) {
+ sp2c++;
+ }
+
+ sp20 = *(unkStruct2 *) sp2c;
+ sp34 = (sp20.unk01 & 0xc0) >> 4;
+ } else if (gConsoleType == CONSOLE_IQUE) {
+ u8 *__osBbEepromAddress = * (u8**) 0x8000035C;
+ s32 i;
- sp20 = *(unkStruct2 *) sp2c;
- sp34 = (sp20.unk01 & 0xc0) >> 4;
+ for (i = 0; i < 8; i++) {
+ __osBbEepromAddress[(address << 3) + i] = buffer[i];
+ }
+
+ sp34 = 0;
+ }
__osSiRelAccess();
return sp34;
}
diff --git a/lib/src/osInitialize.c b/lib/src/osInitialize.c
index ba73024b..6deaf407 100644
--- a/lib/src/osInitialize.c
+++ b/lib/src/osInitialize.c
@@ -1,6 +1,7 @@
#include "libultra_internal.h"
#include "hardware.h"
#include <macros.h>
+#include <PR/console_type.h>
#define PIF_ADDR_START (void *) 0x1FC007FC
@@ -51,6 +52,7 @@ void osInitialize(void) {
UNUSED u32 eu_sp30;
#endif
UNUSED u32 sp2c;
+ gConsoleType = get_console_type();
D_80365CD0 = TRUE;
__osSetSR(__osGetSR() | 0x20000000);
__osSetFpcCsr(0x01000800);
diff --git a/sm64.ld b/sm64.ld
index 7d9b5b4a..be853a3b 100755
--- a/sm64.ld
+++ b/sm64.ld
@@ -306,6 +306,8 @@ SECTIONS
#if ENABLE_RUMBLE
BUILD_DIR/libultra.a:unk_shindou_file_3.o(.text);
#endif
+ BUILD_DIR/libultra.a:consoleType.o(.text)
+ BUILD_DIR/libultra.a:skGetId.o(.text)
BUILD_DIR/lib/rsp.o(.text);
#else
BUILD_DIR/src/game*.o(.text);
@@ -428,6 +430,8 @@ SECTIONS
#if ENABLE_RUMBLE
BUILD_DIR/libultra.a:unk_shindou_file_3.o(.text);
#endif
+ BUILD_DIR/libultra.a:consoleType.o(.text)
+ BUILD_DIR/libultra.a:skGetId.o(.text)
BUILD_DIR/lib/rsp.o(.text);
#endif

View File

@@ -1,298 +0,0 @@
diff --git a/Makefile b/Makefile
index f50b7622..124c7ec6 100644
--- a/Makefile
+++ b/Makefile
@@ -478,6 +478,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
$(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
$(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
+$(BUILD_DIR)/src/boot/mem_error_screen.o: $(BUILD_DIR)/include/text_strings.h
#==============================================================================#
diff --git a/include/segments.h b/include/segments.h
index a97d6ee8..186c968e 100644
--- a/include/segments.h
+++ b/include/segments.h
@@ -3,6 +3,9 @@
#include "config.h"
+/* Use expansion pack RAM */
+#define USE_EXT_RAM 1
+
/*
* Memory addresses for segments. Ideally, this header file would not be
* needed, and the addresses would be defined in sm64.ld and linker-inserted
diff --git a/include/text_strings.h.in b/include/text_strings.h.in
index 749179b1..2f6f7a3c 100644
--- a/include/text_strings.h.in
+++ b/include/text_strings.h.in
@@ -25,6 +25,11 @@
#define TEXT_PAUSE _("PAUSE") // Pause text, Castle Courses
#define TEXT_HUD_CONGRATULATIONS _("CONGRATULATIONS") // Course Complete Text, Bowser Courses
+// Memory Expansion Error Screen
+#define TEXT_CONSOLE_8MB _("If you're using an N64 console, then you will need to buy an\nExpansion Pak to play this ROM hack.")
+#define TEXT_PJ64 _("If you are using PJ64 1.6, go to:\nOptions > Settings > Rom Settings Tab > Memory Size\nthen select 8 MB from the drop-down box.")
+#define TEXT_PJ64_2 _("If you are using PJ64 2.X, go to:\nOptions > Settings > Config: > Memory Size, select 8 MB")
+
#if defined(VERSION_JP) || defined(VERSION_SH)
/**
diff --git a/levels/entry.c b/levels/entry.c
index 17c773ed..677a5ae9 100644
--- a/levels/entry.c
+++ b/levels/entry.c
@@ -15,3 +15,12 @@ const LevelScript level_script_entry[] = {
EXECUTE(/*seg*/ SEGMENT_MENU_INTRO, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_splash_screen),
JUMP(/*target*/ level_script_entry),
};
+
+const LevelScript level_script_entry_error_screen[] = {
+ INIT_LEVEL(),
+ SLEEP(/*frames*/ 2),
+ BLACKOUT(/*active*/ FALSE),
+ SET_REG(/*value*/ 0),
+ EXECUTE(/*seg*/ SEGMENT_MENU_INTRO, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_entry_error_screen),
+ JUMP(/*target*/ level_script_entry_error_screen),
+};
diff --git a/levels/intro/geo.c b/levels/intro/geo.c
index 30a87806..6bf7b79a 100644
--- a/levels/intro/geo.c
+++ b/levels/intro/geo.c
@@ -15,6 +15,24 @@
#include "levels/intro/header.h"
+const GeoLayout intro_geo_error_screen[] = {
+ GEO_NODE_SCREEN_AREA(0, SCREEN_CENTER_X, SCREEN_CENTER_Y, SCREEN_CENTER_X, SCREEN_CENTER_Y),
+ GEO_OPEN_NODE(),
+ GEO_ZBUFFER(0),
+ GEO_OPEN_NODE(),
+ GEO_NODE_ORTHO(100),
+ GEO_OPEN_NODE(),
+ GEO_BACKGROUND_COLOR(0x0001),
+ GEO_CLOSE_NODE(),
+ GEO_CLOSE_NODE(),
+ GEO_ZBUFFER(0),
+ GEO_OPEN_NODE(),
+ GEO_ASM(0, geo18_display_error_message),
+ GEO_CLOSE_NODE(),
+ GEO_CLOSE_NODE(),
+ GEO_END(),
+};
+
// 0x0E0002D0
const GeoLayout intro_geo_splash_screen[] = {
GEO_NODE_SCREEN_AREA(0, SCREEN_CENTER_X, SCREEN_CENTER_Y, SCREEN_CENTER_X, SCREEN_CENTER_Y),
diff --git a/levels/intro/header.h b/levels/intro/header.h
index 99277e86..04797cd7 100644
--- a/levels/intro/header.h
+++ b/levels/intro/header.h
@@ -26,4 +26,8 @@ extern const LevelScript script_intro_main_level_entry_stop_music[];
extern const LevelScript script_intro_main_level_entry[];
extern const LevelScript script_intro_splash_screen[];
+extern const GeoLayout intro_geo_error_screen[];
+extern const LevelScript level_intro_entry_error_screen[];
+extern Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48);
+
#endif
diff --git a/levels/intro/script.c b/levels/intro/script.c
index 04b8fc4c..ca9058c4 100644
--- a/levels/intro/script.c
+++ b/levels/intro/script.c
@@ -18,6 +18,21 @@
#include "make_const_nonconst.h"
#include "levels/intro/header.h"
+const LevelScript level_intro_entry_error_screen[] = {
+ INIT_LEVEL(),
+ FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
+ LOAD_YAY0(/*seg*/ SEGMENT_LEVEL_DATA, _intro_segment_7SegmentRomStart, _intro_segment_7SegmentRomEnd),
+ ALLOC_LEVEL_POOL(),
+
+ AREA(/*index*/ 1, intro_geo_error_screen),
+ END_AREA(),
+
+ FREE_LEVEL_POOL(),
+ LOAD_AREA(/*area*/ 1),
+ SLEEP(/*frames*/ 32767),
+ EXIT_AND_EXECUTE(/*seg*/ SEGMENT_MENU_INTRO, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_error_screen),
+};
+
const LevelScript level_intro_splash_screen[] = {
INIT_LEVEL(),
FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
diff --git a/src/engine/level_script.h b/src/engine/level_script.h
index d41a91c8..7d047236 100644
--- a/src/engine/level_script.h
+++ b/src/engine/level_script.h
@@ -6,6 +6,7 @@
struct LevelCommand;
extern u8 level_script_entry[];
+extern u8 level_script_entry_error_screen[];
struct LevelCommand *level_script_execute(struct LevelCommand *cmd);
diff --git a/src/boot/main.c b/src/boot/main.c
index 1a9d9e7e..f4f7a9e5 100644
--- a/src/boot/main.c
+++ b/src/boot/main.c
@@ -11,6 +11,7 @@
#include "segments.h"
#include "game/main.h"
#include "game/rumble_init.h"
+#include "mem_error_screen.h"
// Message IDs
#define MESG_SP_COMPLETE 100
@@ -131,6 +132,10 @@ void alloc_pool(void) {
void *start = (void *) SEG_POOL_START;
void *end = (void *) SEG_POOL_END;
+ // Detect memory size
+ if (does_pool_end_lie_out_of_bounds(end))
+ end = (void *)SEG_POOL_END_4MB;
+
main_pool_init(start, end);
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
}
@@ -336,7 +341,10 @@ void thread3_main(UNUSED void *arg) {
create_thread(&gSoundThread, 4, thread4_sound, NULL, gThread4Stack + 0x2000, 20);
osStartThread(&gSoundThread);
- create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
+ if (!gNotEnoughMemory)
+ create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
+ else
+ create_thread(&gGameLoopThread, 5, thread5_mem_error_message_loop, NULL, gThread5Stack + 0x2000, 10);
osStartThread(&gGameLoopThread);
while (TRUE) {
diff --git a/src/boot/mem_error_screen.c b/src/boot/mem_error_screen.c
new file mode 100644
index 00000000..f432927c
--- /dev/null
+++ b/src/boot/mem_error_screen.c
@@ -0,0 +1,104 @@
+/* clang-format off */
+/*
+ * mem_error_screen.inc.c
+ *
+ * This enhancement should be used for ROM hacks that require the expansion pak.
+ *
+ */
+/* clang-format on */
+
+#include <types.h>
+#include "segments.h"
+#include "text_strings.h"
+#include "game_init.h"
+#include "main.h"
+#include "print.h"
+#include "ingame_menu.h"
+#include "segment2.h"
+#include "../engine/level_script.h"
+
+// Ensure that USE_EXT_RAM is defined.
+#ifndef USE_EXT_RAM
+#error You have to define USE_EXT_RAM in 'include/segments.h'
+#endif
+
+// Require 8 MB of RAM, even if the pool doesn't go into extended memory.
+// Change the '8' to whatever MB limit you want.
+// Note: only special emulators allow for RAM sizes above 8 MB.
+#define REQUIRED_MIN_MEM_SIZE 1048576 * 8
+
+u8 gNotEnoughMemory = FALSE;
+u8 gDelayForErrorMessage = 0;
+
+u8 does_pool_end_lie_out_of_bounds(void *end) {
+ u32 endPhy = ((u32) end) & 0x1FFFFFFF;
+ u32 memSize = *((u32 *) 0x80000318);
+
+ if (endPhy > memSize) {
+ gNotEnoughMemory = TRUE;
+ return TRUE;
+ } else {
+ if (memSize < REQUIRED_MIN_MEM_SIZE) {
+ gNotEnoughMemory = TRUE;
+ }
+ return FALSE;
+ }
+}
+
+// If you're using an N64 console, then you will need to buy an\nexpansion pak to play this ROM hack.
+u8 text_console_8mb[] = { TEXT_CONSOLE_8MB };
+
+// If you are using PJ64 1.6, go to: Options ► Settings ► Rom Settings Tab ► Memory Size then select 8
+// MB from the drop-down box.
+u8 text_pj64[] = { TEXT_PJ64 };
+
+// If you are using PJ64 2.X, go to: Options ► Settings ► Config: ► Memory Size, select 8 MB
+u8 text_pj64_2[] = { TEXT_PJ64_2 };
+
+Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48) {
+ if (run) {
+ if (gDelayForErrorMessage > 0) {
+ // Draw color text title.
+ print_text(10, 210, "ERROR Need more memory");
+
+ // Init generic text rendering
+ create_dl_ortho_matrix();
+ gSPDisplayList(gDisplayListHead++,
+ dl_ia_text_begin); // Init rendering stuff for generic text
+
+ // Set text color to white
+ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
+
+ print_generic_string(8, 170, text_console_8mb);
+ print_generic_string(8, 120, text_pj64);
+ print_generic_string(8, 54, text_pj64_2);
+
+ // Cleanup
+ gSPDisplayList(gDisplayListHead++,
+ dl_ia_text_end); // Reset back to default render settings.
+ gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
+ } else {
+ gDelayForErrorMessage += 1;
+ }
+ }
+
+ return 0;
+}
+
+// Basic main loop for the error screen. Note that controllers are not enabled here.
+void thread5_mem_error_message_loop(UNUSED void *arg) {
+ struct LevelCommand *addr;
+
+ setup_game_memory();
+ set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1);
+
+ addr = segmented_to_virtual(level_script_entry_error_screen);
+
+ render_init();
+
+ while (1) {
+ select_gfx_pool();
+ addr = level_script_execute(addr);
+ display_and_vsync();
+ }
+}
diff --git a/src/game/mem_error_screen.h b/src/game/mem_error_screen.h
new file mode 100644
index 00000000..9fbff34c
--- /dev/null
+++ b/src/game/mem_error_screen.h
@@ -0,0 +1,8 @@
+#ifndef MEM_ERROR_SCREEN_H
+#define MEM_ERROR_SCREEN_H
+
+extern u8 gNotEnoughMemory;
+void thread5_mem_error_message_loop(UNUSED void *arg);
+u8 does_pool_end_lie_out_of_bounds(void *end);
+
+#endif

Some files were not shown because too many files have changed in this diff Show More