├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
├── TODO
├── blast.c
├── config.h
├── configs
├── blast_corps.e.code.yaml
├── blast_corps.e.yaml
├── blast_corps.u.1.0.code.yaml
├── blast_corps.u.1.0.yaml
├── blast_corps.u.1.1.code.yaml
├── blast_corps.u.1.1.yaml
├── blast_dozer.code.yaml
├── blast_dozer.yaml
├── doraemon.yaml
├── mk64.u.yaml
├── pifboot.yaml
├── sm64.e.yaml
├── sm64.j.yaml
├── sm64.shindou.yaml
└── sm64.u.yaml
├── examples
├── README.md
├── behavior
│ └── sm64.rotating_sign.patch
├── coin_colors
│ ├── coin_colors.ips
│ ├── doors_trees_coins.0x05780.ia16.png
│ ├── doors_trees_coins.0x05F80.ia16.png
│ ├── doors_trees_coins.0x06780.ia16.png
│ └── doors_trees_coins.0x06F80.ia16.png
├── hello_c
│ ├── gen
│ │ ├── extended.c
│ │ └── sm64.h
│ └── hello_c.patch
├── hello_world
│ └── sm64.hello_world.patch
├── hud_toggle
│ └── sm64.hudtoggle.patch
├── skip_screens
│ ├── skip_lakitu.patch
│ ├── skip_mario.patch
│ ├── skip_menu.patch
│ ├── skip_peach.patch
│ └── skip_title.patch
└── texture_swap
│ ├── castle_grounds_segment7.0x0EAE8.ia8.png
│ ├── castle_grounds_textures.0x01000.png
│ ├── font_graphics.0x122B8.ia8.png
│ └── water_skybox.0x00000.skybox.png
├── f3d.c
├── f3d2obj.c
├── libblast.h
├── libmio0.c
├── libmio0.h
├── libsfx.c
├── libsfx.h
├── libsm64.c
├── libsm64.h
├── mipsdisasm.c
├── mipsdisasm.h
├── n64cksum.c
├── n64graphics.c
├── n64graphics.h
├── n64split.c
├── n64split.collision.mtl.h
├── n64split.makefile.h
├── release
├── licenses
│ ├── capstone.LICENSE
│ ├── gnu_make.LICENSE
│ ├── libyaml.LICENSE
│ └── n64split.LICENSE
├── n64split.README.txt
├── sm64extend.README.txt
└── split.bat
├── sm64compress.c
├── sm64extend.c
├── sm64geo.c
├── sm64walk.c
├── strutils.c
├── strutils.h
├── tests
└── example1
│ ├── Makefile
│ ├── example1.asm
│ └── textures
│ ├── heart.0.ia16.png
│ └── heart.0.rgba16.png
├── tools
├── Makefile
├── dma2config.py
├── hudtable.c
├── jalfind.c
├── match_signatures.c
├── mk64karts.c
├── montage.c
├── n64ci.c
├── sm64collision.c
└── sm64text.c
├── utils.c
├── utils.h
└── yamlconfig.c
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.obj
4 |
5 | # Precompiled Headers
6 | *.gch
7 | *.pch
8 |
9 | # Libraries
10 | *.lib
11 | *.a
12 |
13 | # Shared objects (inc. Windows DLLs)
14 | *.dll
15 | *.so
16 | *.so.*
17 | *.dylib
18 |
19 | # Executables
20 | *.exe
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ext/stb"]
2 | path = ext/stb
3 | url = https://github.com/nothings/stb.git
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1)
2 |
3 | project(sm64tools C)
4 |
5 | if (MSVC)
6 | # Always static linking on windows
7 | add_definitions(/MT)
8 | else ()
9 | add_definitions(-Wextra)
10 | endif ()
11 |
12 | set(CMAKE_C_FLAGS "${GCC_EXTRA_CFLAGS}")
13 | set(CMAKE_EXE_LINKER_FLAGS "${GCC_EXTRA_LDFLAGS}")
14 |
15 | include_directories(${CMAKE_SOURCE_DIR}/ext)
16 | include_directories("${PROJECT_SOURCE_DIR}/external/include")
17 | link_directories("${PROJECT_SOURCE_DIR}/external/lib")
18 |
19 | add_library(sm64 STATIC libmio0.c libsm64.c utils.c)
20 |
21 | add_executable(sm64extend sm64extend.c)
22 | target_link_libraries(sm64extend sm64)
23 |
24 | add_executable(sm64compress sm64compress.c)
25 | target_link_libraries(sm64compress sm64)
26 |
27 | add_executable(sm64walk sm64walk.c)
28 | target_link_libraries(sm64walk sm64)
29 |
30 | add_executable(f3d f3d.c utils.c)
31 |
32 | add_executable(f3d2obj blast.c f3d2obj.c n64graphics.c utils.c)
33 | target_link_libraries(f3d2obj png z)
34 |
35 | add_executable(sm64geo sm64geo.c utils.c)
36 |
37 | add_executable(mio0 libmio0.c)
38 | set_target_properties(mio0 PROPERTIES COMPILE_DEFINITIONS "MIO0_STANDALONE")
39 |
40 | add_executable(mipsdisasm mipsdisasm.c utils.c yamlconfig.c)
41 | set_target_properties(mipsdisasm PROPERTIES COMPILE_DEFINITIONS "MIPSDISASM_STANDALONE")
42 | target_link_libraries(mipsdisasm capstone yaml)
43 |
44 | add_executable(n64cksum n64cksum.c)
45 | target_link_libraries(n64cksum sm64)
46 |
47 | add_executable(n64graphics n64graphics.c utils.c)
48 | set_target_properties(n64graphics PROPERTIES COMPILE_DEFINITIONS "N64GRAPHICS_STANDALONE")
49 | target_link_libraries(n64graphics png z)
50 |
51 | add_executable(n64split blast.c libsfx.c mipsdisasm.c n64split.c n64graphics.c strutils.c yamlconfig.c)
52 | target_link_libraries(n64split sm64 capstone yaml z)
53 |
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Q
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ################ Target Executable and Sources ###############
2 |
3 | SM64_LIB := libsm64.a
4 | COMPRESS_TARGET := sm64compress
5 | CKSUM_TARGET := n64cksum
6 | DISASM_TARGET := mipsdisasm
7 | EXTEND_TARGET := sm64extend
8 | F3D_TARGET := f3d
9 | F3D2OBJ_TARGET := f3d2obj
10 | GEO_TARGET := sm64geo
11 | GRAPHICS_TARGET := n64graphics
12 | MIO0_TARGET := mio0
13 | SPLIT_TARGET := n64split
14 | WALK_TARGET := sm64walk
15 |
16 | LIB_SRC_FILES := libmio0.c \
17 | libsm64.c \
18 | libsfx.c \
19 | utils.c
20 |
21 | CKSUM_SRC_FILES := n64cksum.c
22 |
23 | COMPRESS_SRC_FILES := sm64compress.c
24 |
25 | DISASM_SRC_FILES := mipsdisasm.c \
26 | utils.c
27 |
28 | EXTEND_SRC_FILES := sm64extend.c
29 |
30 | F3D_SRC_FILES := f3d.c \
31 | utils.c
32 |
33 | F3D2OBJ_SRC_FILES := blast.c \
34 | f3d2obj.c \
35 | n64graphics.c \
36 | utils.c
37 |
38 | GEO_SRC_FILES := sm64geo.c \
39 | utils.c
40 |
41 | GRAPHICS_SRC_FILES := n64graphics.c \
42 | utils.c
43 |
44 | SPLIT_SRC_FILES := blast.c \
45 | libmio0.c \
46 | libsfx.c \
47 | mipsdisasm.c \
48 | n64graphics.c \
49 | n64split.c \
50 | strutils.c \
51 | utils.c \
52 | yamlconfig.c
53 |
54 | OBJ_DIR = ./obj
55 |
56 | ##################### Compiler Options #######################
57 |
58 | WIN64_CROSS = x86_64-w64-mingw32-
59 | WIN32_CROSS = i686-w64-mingw32-
60 | #CROSS = $(WIN32_CROSS)
61 | CC = $(CROSS)gcc
62 | LD = $(CC)
63 | AR = $(CROSS)ar
64 |
65 | INCLUDES = -I./ext
66 | DEFS =
67 | # Release flags
68 | CFLAGS = -Wall -Wextra -Wno-format-overflow -O2 -ffunction-sections -fdata-sections $(INCLUDES) $(DEFS) -MMD
69 | LDFLAGS = -s -Wl,--gc-sections
70 | # Debug flags
71 | #CFLAGS = -Wall -Wextra -O0 -g $(INCLUDES) $(DEFS) -MMD
72 | #LDFLAGS =
73 | LIBS =
74 | SPLIT_LIBS = -lcapstone -lyaml -lz
75 |
76 | LIB_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(LIB_SRC_FILES:.c=.o))
77 | CKSUM_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(CKSUM_SRC_FILES:.c=.o))
78 | COMPRESS_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(COMPRESS_SRC_FILES:.c=.o))
79 | EXTEND_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(EXTEND_SRC_FILES:.c=.o))
80 | F3D_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(F3D_SRC_FILES:.c=.o))
81 | F3D2OBJ_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(F3D2OBJ_SRC_FILES:.c=.o))
82 | GEO_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(GEO_SRC_FILES:.c=.o))
83 | SPLIT_OBJ_FILES = $(addprefix $(OBJ_DIR)/,$(SPLIT_SRC_FILES:.c=.o))
84 | OBJ_FILES = $(LIB_OBJ_FILES) $(EXTEND_OBJ_FILES) $(COMPRESS_OBJ_FILES) \
85 | $(SPLIT_OBJ_FILES) $(CKSUM_OBJ_FILES) $(F3D_OBJ_FILES) \
86 | $(F3D2OBJ_OBJ_FILES) $(GEO_OBJ_FILES)
87 | DEP_FILES = $(OBJ_FILES:.o=.d)
88 |
89 | ######################## Targets #############################
90 |
91 | default: all
92 |
93 | all: $(EXTEND_TARGET) $(COMPRESS_TARGET) $(MIO0_TARGET) $(CKSUM_TARGET) \
94 | $(SPLIT_TARGET) $(F3D_TARGET) $(F3D2OBJ_TARGET) $(GRAPHICS_TARGET) \
95 | $(DISASM_TARGET) $(GEO_TARGET) $(WALK_TARGET)
96 |
97 | $(OBJ_DIR)/%.o: %.c
98 | @[ -d $(OBJ_DIR) ] || mkdir -p $(OBJ_DIR)
99 | $(CC) $(CFLAGS) -o $@ -c $<
100 |
101 | $(SM64_LIB): $(LIB_OBJ_FILES)
102 | rm -f $@
103 | $(AR) rcs $@ $^
104 |
105 | $(CKSUM_TARGET): $(CKSUM_OBJ_FILES) $(SM64_LIB)
106 | $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
107 |
108 | $(COMPRESS_TARGET): $(COMPRESS_OBJ_FILES) $(SM64_LIB)
109 | $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
110 |
111 | $(EXTEND_TARGET): $(EXTEND_OBJ_FILES) $(SM64_LIB)
112 | $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
113 |
114 | $(F3D_TARGET): $(F3D_OBJ_FILES)
115 | $(LD) $(LDFLAGS) -o $@ $^
116 |
117 | $(F3D2OBJ_TARGET): $(F3D2OBJ_OBJ_FILES)
118 | $(LD) $(LDFLAGS) -o $@ $^
119 |
120 | $(GEO_TARGET): $(GEO_OBJ_FILES)
121 | $(LD) $(LDFLAGS) -o $@ $^
122 |
123 | $(GRAPHICS_TARGET): $(GRAPHICS_SRC_FILES)
124 | $(CC) $(CFLAGS) -DN64GRAPHICS_STANDALONE $^ $(LDFLAGS) -o $@
125 |
126 | $(MIO0_TARGET): libmio0.c libmio0.h
127 | $(CC) $(CFLAGS) -DMIO0_STANDALONE $(LDFLAGS) -o $@ $<
128 |
129 | $(DISASM_TARGET): $(DISASM_SRC_FILES)
130 | $(CC) $(CFLAGS) -DMIPSDISASM_STANDALONE $^ $(LDFLAGS) -o $@ -lcapstone
131 |
132 | $(SPLIT_TARGET): $(SPLIT_OBJ_FILES)
133 | $(LD) $(LDFLAGS) -o $@ $^ $(SPLIT_LIBS)
134 |
135 | $(WALK_TARGET): sm64walk.c $(SM64_LIB)
136 | $(CC) $(CFLAGS) -o $@ $^
137 |
138 | rawmips: rawmips.c utils.c
139 | $(CC) $(CFLAGS) -o $@ $^ -lcapstone
140 |
141 | clean:
142 | rm -f $(OBJ_FILES) $(DEP_FILES) $(SM64_LIB) $(MIO0_TARGET)
143 | rm -f $(CKSUM_TARGET) $(CKSUM_TARGET).exe
144 | rm -f $(COMPRESS_TARGET) $(COMPRESS_TARGET).exe
145 | rm -f $(DISASM_TARGET) $(DISASM_TARGET).exe
146 | rm -f $(EXTEND_TARGET) $(EXTEND_TARGET).exe
147 | rm -f $(F3D_TARGET) $(F3D_TARGET).exe
148 | rm -f $(F3D2OBJ_TARGET) $(F3D2OBJ_TARGET).exe
149 | rm -f $(GEO_TARGET) $(GEO_TARGET).exe
150 | rm -f $(MIO0_TARGET) $(MIO0_TARGET).exe
151 | rm -f $(GRAPHICS_TARGET) $(GRAPHICS_TARGET).exe
152 | rm -f $(SPLIT_TARGET) $(SPLIT_TARGET).exe
153 | rm -f $(WALK_TARGET) $(WALK_TARGET).exe
154 | -@[ -d $(OBJ_DIR) ] && rmdir --ignore-fail-on-non-empty $(OBJ_DIR)
155 |
156 | .PHONY: all clean default
157 |
158 | #################### Dependency Files ########################
159 |
160 | -include $(DEP_FILES)
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sm64tools
2 | Collection of tools for manipulating the Super Mario 64 ROM
3 |
4 | ## n64split
5 | N64 ROM Splitter and Build System
6 | - splits ROM into assets: asm, textures, models, levels, behavior data
7 | - generates build files to rebuild the ROM
8 | - intelligent recursive disassembler
9 | - generic config file system to support multiple games
10 |
11 | ### Usage
12 | ```console
13 | n64split [-c CONFIG] [-k] [-m] [-o OUTPUT_DIR] [-s SCALE] [-t] [-v] [-V] ROM
14 | ```
15 | Options:
16 | - -c CONFIG
ROM configuration file (default: auto-detect)
17 | - -k
keep going as much as possible after error
18 | - -m
merge related instructions in to pseudoinstructions
19 | - -o OUTPUT_DIR
output directory (default: {CONFIG.basename}.split)
20 | - -s SCALE
amount to scale models by (default: 1024.0)
21 | - -t
generate large texture for MIO0 blocks
22 | - -v
verbose output
23 | - -V
print version information
24 |
25 | ## sm64extend
26 | Super Mario 64 ROM Extender
27 | - accepts Z64 (BE), V64 (byte-swapped), or N64 (little-endian) ROMs as input
28 | - works with US, European, Japanese, and Shindou ROMs
29 | - decompresses all MIO0 blocks from ROM to extended area
30 | - configurable extended ROM size (default 64 MB)
31 | - configurable padding between MIO0 blocks (default 32 KB)
32 | - configurable MIO0 block alignment (default 1 byte)
33 | - changes all 0x18 level commands to 0x17
34 | - creates MIO0 headers for all 0x1A level commands
35 | - optionally fills old MIO0 blocks with 0x01
36 | - optionally dump compressed and uncompressed MIO0 data to files
37 | - updates assembly reference to MIO0 blocks
38 | - recalculates ROM header checksums
39 |
40 | ### Usage
41 | ```console
42 | sm64extend [-a ALIGNMENT] [-p PADDING] [-s SIZE] [-d] [-f] [-v] FILE [OUT_FILE]
43 | ```
44 | Options:
45 | - -a ALIGNMENT
Byte boundary to align MIO0 blocks (default = 1).
46 | - -p PADDING
Padding to insert between MIO0 blocks in KB (default = 32).
47 | - -s SIZE
Size of the extended ROM in MB (default: 64).
48 | - -d
Dump MIO0 blocks to files in mio0 directory.
49 | - -f
Fill old MIO0 blocks with 0x01.
50 | - -v
verbose output.
51 |
52 | Output file: If unspecified, it is constructed by replacing input file extension with .ext.z64
53 |
54 | ### Examples
55 | 64 MB extended ROM that is bit compatible with with generated from the M64ROMExtender1.3b, after extending to 64 MB
56 | ```console
57 | sm64extend sm64.z64
58 | ```
59 |
60 | 24 MB extended ROM that is bit compatible with the ROM generated from the M64ROMExtender1.3b
61 | ```console
62 | sm64extend -s 24 sm64.z64
63 | ```
64 |
65 | Enable verbose messages and specify output filename:
66 | ```console
67 | sm64extend -v sm64.z64 sm64_output.ext.z64
68 | ```
69 |
70 | Pad 64 KB between blocks, align blocks to 16-byte boundaries, fill old MIO0 blocks with 0x01:
71 | ```console
72 | sm64extend -p 64 -a 16 -f sm64.z64
73 | ```
74 |
75 | ## sm64compress
76 | Experimental Super Mario 64 ROM alignment and compression tool
77 | - packs all MIO0 blocks together, reducing unused space
78 | - optionally compresses MIO0 blocks (and converts 0x17 commands to 0x18)
79 | - configurable MIO0 block alignment (default 16 byte)
80 | - reduces output ROM size to 4 MB boundary
81 | - updates assembly reference to MIO0 blocks
82 | - recalculates ROM header checksums
83 |
84 | ### Usage
85 | ```console
86 | sm64compress [-a ALIGNMENT] [-c] [-d] [-v] FILE [OUT_FILE]
87 | ```
88 | Options:
89 | - -a alignment
Byte boundary to align MIO0 blocks (default = 16).
90 | - -c
compress all blocks using MIO0.
91 | - -d
dump MIO0 blocks to files in mio0 directory.
92 | - -v
verbose output.
93 |
94 | Output file: If unspecified, it is constructed by replacing input file extension with .out.z64
95 |
96 | ## Other Tools
97 | There are many other smaller tools included to help with SM64 hacking. They are:
98 | - f3d: tool to decode Fast3D display lists
99 | - mio0: standalone MIO0 compressor/decompressor
100 | - n64cksum: standalone N64 checksum generator. can either do in place or output to a new file
101 | - n64graphics: converts graphics data from PNG files into RGBA or IA N64 graphics data
102 | - mipsdisasm: standalone recursive MIPS disassembler
103 | - sm64geo: standalone SM64 geometry layout decoder
104 |
105 | ## License
106 |
107 | MIT License. Copyright 2015 queueRAM.
108 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | 0.4:
2 | *add batch files to patch examples
3 | *fix 'make clean' not deleting sm64.map
4 | *fill in sm64.j asm and RAM/ROM mappings
5 | *add option to specify output dir
6 | *name 'gen' dir based on config name
7 | *add TYPE_M64 to support M64 music data and find references
8 | *add GNU patch for windows
9 | *update libcapstone
10 | *add some mk64 asm
11 |
12 | 0.5:
13 | rip models and collision?
14 | improve sw %lo() detection
15 | scan procedure at a time to find instruction pairs to collapse
16 | - lui/addiu, lui/ori, lui/sw (possibly .set at or at least %hi/%lo), slt/bne
17 | add TYPE_TEXTURE and support arbitrary types within MIO0 (and other compressed?) blocks
18 | add standalone sm64level, sm64behavior tools?
19 | add 0x39 level references to table at EC7E0
20 | add way to include jump tables or define data types of tables
21 | - autodetect through JR?
22 | add RAM labels for tables
23 | add VS compiler flags to reduce build size
24 | add document or script release
25 | - bump version in changed tools
26 | - update release/n64split.README
27 | - update README with any changes to usage
28 | - create new build-vM.m.b
29 | - cd build-vM.m.b
30 | - cmake -DCMAKE_BUILD_TYPE=Release ..
31 | - call command line tool to build all projects?
32 | - create new n64split-vM.m.b-win32
33 | - copy licenses/
34 | - copy configs/
35 | - copy release/split.bat
36 | - copy release/n64split.README.txt README.txt
37 | - copy build-vM.m.b/Release/ tools/
38 | - delete libsm64.lib
39 | add version, help, flags to n64graphics
40 | add ./test/
41 | remove hacks for overlapping asm procedures
42 | create directories for mipsdisasm, libmio0
43 | merge rawmips into mipsdisasm
44 | rename mipsdisasm to mipsrdisasm - MIPS recursive disasm
45 | add parens and arguments in function name
46 | use segmented addresses for more level script callouts
47 | - move data to segmented address (possibly overlay)
48 | - add symbols for LOAD addresses
49 | add asm macros for level scripts
50 | add asm macros for geo layout
51 | - add labels for asm and other references
52 | add asm macros for behavior scripts
53 | create common label database (config lables, ROM labels, behavior labels, HW register labels, jump tables)
54 | update linker script for RAM/ROM AT addressing
55 | find way to have data labels
56 | - in config file
57 | - linker script
58 | figure out remaining cut scenes
59 | maybe:
60 | use shygoo's 0x1A level command with uncompressed data
61 | convert texture encoding to:
62 | split --> textures/A.0x0.png, A.s
63 | textures/A.0x0.png --n64graphics--> bin/textures/A.0x0.bin
64 | .include "A.s" .incbin "bin/textures/A.0x0.bin"
65 | A.bin -> A.mio0: remove this step
66 |
67 | Examples:
68 | hello world example
69 | - hook into mario function instead of butterfly behavior
70 | hello world 2 example
71 | http://www.hastebin.com/unuqiwetov <-- use this one
72 | http://www.hastebin.com/ayoqopoyeq
73 | switch to Green Stars method of HUD toggle
74 | - still need show star status
75 | look into what importer does for bounds extending
76 | import custom levels
77 | look into m64 music importing
78 | add new .text section at 0x80400000 and setup DMAs for it
79 |
80 | Other:
81 | add f3d parsing?
82 | see what else the level importer changed
83 | figure out where music and samples are located and split out
84 | switch emulator to cen64
85 | see what data is after geo layout after main_level_scripts
86 | improve mio0 compressor
87 | check capstone disassembly of COP instructions
88 | -> appears to do some COP2, need to validate assembly again
89 | -> does not do RSP, need to implement in custom callback for data
90 | - probably also requires switching to callback for each instruction
91 | http://sprunge.us/VYYI?gas
92 |
93 | figure out what these functions are for:
94 | JALs:
95 | // recursive, only called by self 802C9AD8
96 | Looking for 802C9AD8 0C0B26B6
97 | 084AFC: 0C0B26B6
98 | 084B28: 0C0B26B6
99 |
100 | // recursive, only called by self 8017E430
101 | Looking for 8017E430 0C05F90C
102 | 22E96C: 0C05F90C
103 |
104 | // recursive, only called by self 8017F350
105 | Looking for 8017F350 0C05FCD4
106 | 22F96C: 0C05FCD4
107 |
108 | // recursive, only called by self 8018837C
109 | Looking for 8018837C 0C0620DF
110 | 238968: 0C0620DF
111 |
112 | Looking for 8017C810 0C05F204
113 | 257A28: 0C05F204
114 |
115 | Looking for 8017EF9C 0C05FBE7
116 | 257B88: 0C05FBE7
117 |
118 |
--------------------------------------------------------------------------------
/config.h:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_H_
2 | #define CONFIG_H_
3 |
4 | typedef enum
5 | {
6 | TYPE_INVALID,
7 | TYPE_ASM,
8 | TYPE_BIN,
9 | TYPE_BLAST,
10 | TYPE_GZIP,
11 | TYPE_HEADER,
12 | TYPE_INSTRUMENT_SET,
13 | TYPE_M64,
14 | TYPE_SFX_CTL,
15 | TYPE_SFX_TBL,
16 | TYPE_MIO0,
17 | TYPE_PTR,
18 | // F3D display lists and related
19 | TYPE_F3D_DL,
20 | TYPE_F3D_LIGHT,
21 | TYPE_F3D_VERTEX,
22 | // Textures
23 | TYPE_TEX_CI,
24 | TYPE_TEX_I,
25 | TYPE_TEX_IA,
26 | TYPE_TEX_RGBA,
27 | TYPE_TEX_SKYBOX,
28 | // SM64 specific types
29 | TYPE_SM64_GEO,
30 | TYPE_SM64_BEHAVIOR,
31 | TYPE_SM64_COLLISION,
32 | TYPE_SM64_LEVEL,
33 | } section_type;
34 |
35 | typedef struct _label
36 | {
37 | unsigned int ram_addr;
38 | char name[128];
39 | } label;
40 |
41 | typedef struct _texture
42 | {
43 | unsigned int offset;
44 | unsigned int palette; // only for CI textures
45 | unsigned short width;
46 | unsigned short height;
47 | unsigned short depth;
48 | section_type format;
49 | } texture;
50 |
51 | typedef struct _split_section
52 | {
53 | char label[128];
54 | unsigned int start;
55 | unsigned int end;
56 | unsigned int vaddr;
57 | section_type type;
58 |
59 | int subtype;
60 |
61 | // texture specific data
62 | texture tex;
63 |
64 | struct _split_section *children;
65 | int child_count;
66 | } split_section;
67 |
68 | typedef struct _rom_config
69 | {
70 | char name[128];
71 | char basename[128];
72 |
73 | unsigned int checksum1;
74 | unsigned int checksum2;
75 |
76 | split_section *sections;
77 | int section_count;
78 |
79 | label *labels;
80 | int label_count;
81 | } rom_config;
82 |
83 | int config_parse_file(const char *filename, rom_config *config);
84 | void config_print(const rom_config *config);
85 | int config_validate(const rom_config *config, unsigned int max_len);
86 | void config_free(rom_config *config);
87 |
88 | section_type config_str2section(const char *type_name);
89 | const char *config_section2str(section_type section);
90 |
91 | // get version of underlying config library
92 | const char *config_get_version(void);
93 |
94 | #endif // CONFIG_H_
95 |
--------------------------------------------------------------------------------
/configs/blast_corps.e.code.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file
2 | name: "Blast Corps (E) hd_code_text.raw"
3 |
4 | # checksums from ROM header offsets 0x10 and 0x14
5 | # used for auto configuration detection
6 | checksum1: 0x3C0E00FF
7 | checksum2: 0x35CEB000
8 |
9 | # base filename used for outputs (please, no spaces)
10 | basename: "blast_corps.e.code"
11 |
12 | # ranges to split the ROM into
13 | # types:
14 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
15 | ranges:
16 | # start, end, type, label
17 | - [0x000000, 0x0A4410, "asm", "main", 0x802447C0]
18 |
19 | # Labels for functions or data memory addresses
20 | # All label addresses are RAM addresses
21 | # Order does not matter
22 | labels:
23 | - [0x802447C0, "MainJump"]
24 | - [0x80244870, "Thread1"]
25 | - [0x80244930, "Thread3"]
26 | - [0x80257594, "LoadLevel"]
27 | - [0x80269258, "Thread4"]
28 | - [0x80271640, "LoadLevelRdus"]
29 | - [0x802729F8, "Thread5"]
30 | - [0x8028D1E4, "InitiateDma"]
31 | - [0x8028DEB0, "LoadLevelAmmo"]
32 | - [0x8028F1E0, "LoadLevelTnt"]
33 | - [0x80291AD0, "LoadLevelSquareBlocks"]
34 | - [0x802A440C, "LoadLevelTodo74"]
35 | - [0x802A4590, "LoadLevelTodo2C"]
36 | - [0x802A46C4, "LoadLevelBuildings"]
37 | - [0x802A5520, "CopyBuildingTableToRam"]
38 | - [0x802A5408, "InflateBuildingData"]
39 | - [0x802A55C4, "LoadLevelTodo60"]
40 | - [0x802A56D8, "LoadLevelTodo4C"]
41 | - [0x802A5978, "LoadLevelTodo78"]
42 | - [0x802A5E7C, "LoadLevelVehicles"]
43 | - [0x802A59AC, "LoadLevelMissileCarrier"]
44 | - [0x802A66C4, "LoadLevelCollisionXZ"]
45 | - [0x802A6768, "LoadLevelTodo70"]
46 | - [0x802A680C, "LoadLevelTodo64"]
47 | - [0x802A68F0, "LoadLevelTrainPlatform"]
48 | - [0x802A6DD4, "LoadLevelTerrain"]
49 | - [0x802A6E54, "AlignTo8Bytes"]
50 | - [0x802A7E80, "LoadLevelTodo40"]
51 | - [0x802A7F74, "LoadLevelTodo44"]
52 | - [0x802A814C, "DecodeTexture"]
53 | - [0x802A82C8, "DecodeTexture6"]
54 | - [0x802A839C, "DecodeTexture3"]
55 | - [0x802A8450, "DecodeTexture1"]
56 | - [0x802A8500, "DecodeTexture2"]
57 | - [0x802A85CC, "DecodeTexture4"]
58 | - [0x802A86A4, "DecodeTexture5"]
59 | - [0x802A8780, "DecodeTexture0"]
60 | - [0x802C6A78, "GzipInflate"]
61 | - [0x802D1410, "LoadLevelCommPoint"]
62 | - [0x802D6990, "osInitialize"]
63 | - [0x802D6BC0, "osEPiRawReadIo"]
64 | - [0x802D6C20, "osCreateThread"]
65 | - [0x802D6D70, "osStartThread"]
66 | - [0x802D6ED0, "osCreatePiManager"]
67 | - [0x802D7050, "osSetThreadPri"]
68 | - [0x802D7130, "osSendMesg"]
69 | - [0x802D7280, "osRecvMesg"]
70 | - [0x802D73C0, "osViBlack"]
71 | - [0x802D7430, "osGetTime"]
72 | - [0x802D74C0, "__ull_rshift"]
73 | - [0x802D74EC, "__ull_rem"]
74 | - [0x802D7528, "__ull_div"]
75 | - [0x802D7564, "__ll_lshift"]
76 | - [0x802D7590, "__ll_rem"]
77 | - [0x802D75CC, "__ll_div"]
78 | - [0x802D7628, "__ll_mul"]
79 | - [0x802D7658, "__ull_divremi"]
80 | - [0x802D76B8, "__ll_mod"]
81 | - [0x802D7754, "__ll_rshift"]
82 | - [0x802D7790, "osVirtualToPhysical"]
83 | - [0x802D7810, "osWriteBackDCache"]
84 | - [0x802D7A40, "guOrthoF"]
85 | - [0x802D7B94, "guFrustum"]
86 | - [0x802D7C00, "guPerspectiveF"]
87 | - [0x802D7E30, "guPerspective"]
88 | - [0x802D8290, "guMtxF2L"]
89 | - [0x802D8390, "guMtxIdentF"]
90 | - [0x802D8500, "guRotateRPYF"]
91 | - [0x802D8554, "guRotateRPY"]
92 | - [0x802D8A60, "sqrtf"]
93 | - [0x802D8DA0, "sinf"]
94 | - [0x802D8F60, "osCreateMesgQueue"]
95 | - [0x802D8FD0, "osViSetSpecialFeatures"]
96 | - [0x802D9190, "osWriteBackDCacheAll"]
97 | - [0x802D91C0, "osInvalDCache"]
98 | - [0x802D9270, "osDestroyThread"]
99 | - [0x802D9370, "cosf"]
100 | - [0x802D78F0, "proutSprintf"]
101 | - [0x802D795C, "sprintf"]
102 | - [0x802D7890, "osSetIntMask"]
103 | - [0x802DADD4, "alBnkfNew"]
104 | - [0x802DAED8, "alSetFileNew"]
105 | - [0x802DC190, "osGetCount"]
106 | - [0x802DC240, "__osViInit"]
107 | - [0x802DC380, "osAiSetFrequency"]
108 | - [0x802DC4E0, "osAiSetNextBuffer"]
109 | - [0x802DC590, "osAiGetLength"]
110 | - [0x802DCC70, "osPiStartDma"]
111 | - [0x802DCF90, "osCreateViManager"]
112 | - [0x802DD114, "__osViDevMgrMain"]
113 | - [0x802DD2F0, "osViSetMode"]
114 | - [0x802DD360, "osSetEventMsg"]
115 | - [0x802DD3D0, "osViSetEventMsg"]
116 | - [0x802DD840, "osViSwapBuffer"]
117 | - [0x802DD890, "osSetTimer"]
118 | - [0x802DD9F0, "osSpTaskDunno"]
119 | - [0x802DDB0C, "osSpTaskLoad"]
120 | - [0x802DDC6C, "osSpTaskStartGo"]
121 | - [0x802DDCAC, "osSpTaskYield"]
122 | - [0x802DDD90, "osContInit"]
123 | - [0x802DDF8C, "__osContGetInitData"]
124 | - [0x802DE05C, "__osPackRequestData"]
125 | - [0x802DE1C0, "osContStartReadData"]
126 | - [0x802DE284, "osContGetReadData"]
127 | - [0x802DE420, "osInvalCache"]
128 | - [0x802DE4A0, "bzero"]
129 | - [0x802DE690, "__osGetSR"]
130 | - [0x802DE6A0, "__osSetFpcCsr"]
131 | - [0x802DE6B0, "__osSiRawReadIo"]
132 | - [0x802DE700, "__osSiRawWriteIo"]
133 | - [0x802DE750, "__osExceptionPreamble"]
134 | - [0x802DE760, "__osExceptionHandler"]
135 | - [0x802DED90, "__osEnqueueAndYield"]
136 | - [0x802DEE20, "__osEnqueueThread"]
137 | - [0x802DEE68, "__osPopThread"]
138 | - [0x802DEE78, "__osDispatchThread"]
139 | - [0x802DEFB8, "__osCleanupThread"]
140 | - [0x802DF020, "__osDisableInt"]
141 | - [0x802DF040, "__osRestoreInt"]
142 | - [0x802DF0A0, "__osPiCreateAccessQueue"]
143 | - [0x802DF0F0, "__osPiGetAccess"]
144 | - [0x802DF134, "__osPiRelAccess"]
145 | - [0x802DF160, "osGetThreadPri"]
146 | - [0x802DF180, "osPiRawStartDma"]
147 | - [0x802DF260, "__osDevMgrMain"]
148 | - [0x802DF3E0, "__osTimerServicesInit"]
149 | - [0x802DF46C, "__osTimerInterrupt"]
150 | - [0x802DF5E4, "__osSetTimerIntr"]
151 | - [0x802DF658, "__osInsertTimer"]
152 | - [0x802DF7E0, "__osProbeTLB"]
153 | - [0x802DF8A0, "_Printf"]
154 | - [0x802E0A30, "memcpy"]
155 | - [0x802E28F0, "__osAiDeviceBusy"]
156 | - [0x802E42B0, "osJamMesg"]
157 | - [0x802E4440, "__osSpGetStatus"]
158 | - [0x802DD440, "bcopy"]
159 | - [0x802E4450, "__osSpSetStatus"]
160 | - [0x802E4460, "__osSpSetPc"]
161 | - [0x802E44A0, "__osSpRawStartDma"]
162 | - [0x802E4530, "__osSpDeviceBusy"]
163 | - [0x802E4560, "__osSiRawStartDma"]
164 | - [0x802E4610, "__osSiCreateAccessQueue"]
165 | - [0x802E4660, "__osSiGetAccess"]
166 | - [0x802E46A4, "__osSiRelAccess"]
167 | - [0x802E46D0, "__osSiDeviceBusy"]
168 | - [0x802E4B80, "__osSyncPutChars"]
169 | - [0x802E4CB0, "__osSetCompare"]
170 | - [0x802E7000, "__osAtomicDec"]
171 |
172 |
--------------------------------------------------------------------------------
/configs/blast_corps.e.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file
2 | name: "Blast Corps (E)"
3 |
4 | # checksums from ROM header offsets 0x10 and 0x14
5 | # used for auto configuration detection
6 | checksum1: 0x7C64E6DB
7 | checksum2: 0x55B924DB
8 |
9 | # base filename used for outputs (please, no spaces)
10 | basename: "blast_corps.e"
11 |
12 | # ranges to split the ROM into
13 | # types:
14 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
15 | # behavior - behavior script
16 | # bin - raw binary, usually data
17 | # blast - Blast Corps compressed blocks
18 | # gzip - gzip compressed blocks
19 | # header - ROM header block
20 | # instrset - instrument set
21 | # level - level commands
22 | # m64 - M64 music sequence bank
23 | # mio0 - MIO0 compressed data block. may have texture breakdown
24 | # ptr - RAM address or ROM offset pointer
25 | #
26 | # textures types:
27 | # rgba - 32/16 bit RGBA (5-5-5-1/8-8-8-8)
28 | # ia - 16/8/4/1-bit greyscale
29 | # skybox - grid of 32x32 16-bit RGBA
30 | ranges:
31 | # start, end, type, label
32 | - [0x000000, 0x000040, "header", "header"]
33 | - [0x000040, 0x001000, "bin", "boot"]
34 | - [0x001000, 0x004A3C, "asm", "main", 0x8021ED00]
35 | # hd_code_text is copied to 0x80000400 and then inflated to 0x802447C0 by proc_80220998
36 | - [0x788120, 0x7D845C, "gzip", "hd_code_text.raw"]
37 | - [0x7D845C, 0x7E4940, "gzip", "hd_code_data.raw"]:
38 | # TODO: many of these are just guesses
39 | - [0x10E30, "tex.rgba", 32, 16, 16]
40 | - [0x11230, "tex.rgba", 32, 16, 16]
41 | - [0x12180, "tex.rgba", 32, 32, 30]
42 | - [0x142E0, "tex.rgba", 16, 32, 32]
43 | - [0x16B68, "tex.ia", 16, 32, 32]
44 | - [0x7E4940, 0x7F75A4, "gzip", "hd_front_end_text.raw"]
45 | - [0x7F75A4, 0x7FB7C0, "gzip", "hd_front_end_data.raw"]
46 |
47 | # Labels for functions or data memory addresses
48 | # All label addresses are RAM addresses
49 | # Order does not matter
50 | labels:
51 | - [0x8021ED00, "EntryPoint"]
52 | - [0x80220730, "Main"]
53 | - [0x80220BA0, "bzero"]
54 | - [0x80220C40, "osInitialize"]
55 | - [0x80220E70, "DmaCopy"]
56 | - [0x80220F50, "GetDmaStatus"]
57 | - [0x80220F70, "__osGetSR"]
58 | - [0x80220F80, "__osSetFpcCsr"]
59 | - [0x80220F90, "__osSiRawReadIo"]
60 | - [0x80220FE0, "__osSiRawWriteIo"]
61 | - [0x802218A0, "osWriteBackDCache"]
62 | - [0x80221920, "osInvalCache"]
63 | - [0x80221A00, "osEPiRawReadIo"]
64 | - [0x80221AC8, "__ull_div"]
65 | - [0x80221BC8, "__ll_mul"]
66 | - [0x80221DE0, "__osSiDeviceBusy"]
67 | - [0x802447C0, "MainJump"]
68 |
69 |
--------------------------------------------------------------------------------
/configs/blast_corps.u.1.0.code.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file
2 | name: "Blast Corps (U) (V1.0) hd_code_text.raw"
3 |
4 | # checksums from ROM header offsets 0x10 and 0x14
5 | # used for auto configuration detection
6 | checksum1: 0x3C0E00FF
7 | checksum2: 0x35CEB000
8 |
9 | # base filename used for outputs (please, no spaces)
10 | basename: "blast_corps.u.1.0.hd_code_text"
11 |
12 | # ranges to split the ROM into
13 | # types:
14 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
15 | ranges:
16 | # start, end, type, label
17 | - [0x000000, 0x0A4360, "asm", 0x802447C0]
18 |
19 | # Labels for functions or data memory addresses
20 | # All label addresses are RAM addresses
21 | # Order does not matter
22 | labels:
23 | - [0x802447C0, "MainJump"]
24 | - [0x80244870, "Thread1"]
25 | - [0x80244930, "Thread3"]
26 | - [0x8025615C, "LoadLevel"]
27 | - [0x80267A9C, "Thread4"]
28 | - [0x8026FBB0, "LoadLevelRdus"]
29 | - [0x80270F7C, "Thread5"]
30 | - [0x8028B4C4, "InitiateDma"]
31 | - [0x8028C190, "LoadLevelAmmo"]
32 | - [0x8028D4C0, "LoadLevelTnt"]
33 | - [0x8028FDA0, "LoadLevelSquareBlocks"]
34 | - [0x802A1A9C, "LoadLevelTodo74"]
35 | - [0x802A1C20, "LoadLevelTodo2C"]
36 | - [0x802A1D54, "LoadLevelBuildings"]
37 | - [0x802A2BB0, "CopyBuildingTableToRam"]
38 | - [0x802A2A98, "InflateBuildingData"]
39 | - [0x802A2C54, "LoadLevelTodo60"]
40 | - [0x802A2D68, "LoadLevelTodo4C"]
41 | - [0x802A3000, "LoadLevelTodo78"]
42 | - [0x802A3504, "LoadLevelVehicles"]
43 | - [0x802A3034, "LoadLevelMissileCarrier"]
44 | - [0x802A3D4C, "LoadLevelCollisionXZ"]
45 | - [0x802A3DF0, "LoadLevelTodo70"]
46 | - [0x802A3E94, "LoadLevelTodo64"]
47 | - [0x802A3F78, "LoadLevelTrainPlatform"]
48 | - [0x802A445C, "LoadLevelTerrain"]
49 | - [0x802A44DC, "AlignTo8Bytes"]
50 | - [0x802A5500, "LoadLevelTodo40"]
51 | - [0x802A55F4, "LoadLevelTodo44"]
52 | - [0x802A57CC, "DecodeTexture"]
53 | - [0x802A5948, "DecodeTexture6"]
54 | - [0x802A5A1C, "DecodeTexture3"]
55 | - [0x802A5AD0, "DecodeTexture1"]
56 | - [0x802A5B80, "DecodeTexture2"]
57 | - [0x802A5C4C, "DecodeTexture4"]
58 | - [0x802A5D24, "DecodeTexture5"]
59 | - [0x802A5E00, "DecodeTexture0"]
60 | - [0x802C4058, "GzipInflate"]
61 | - [0x802CE9F0, "LoadLevelCommPoint"]
62 | - [0x802D3F70, "osInitialize"]
63 | - [0x802D41A0, "osEPiRawReadIo"]
64 | - [0x802D4200, "osCreateThread"]
65 | - [0x802D4350, "osStartThread"]
66 | - [0x802D44B0, "osCreatePiManager"]
67 | - [0x802D4630, "osSetThreadPri"]
68 | - [0x802D4710, "osSendMesg"]
69 | - [0x802D4860, "osRecvMesg"]
70 | - [0x802D49A0, "osViBlack"]
71 | - [0x802D4A10, "osGetTime"]
72 | - [0x802D4AA0, "__ull_rshift"]
73 | - [0x802D4ACC, "__ull_rem"]
74 | - [0x802D4B08, "__ull_div"]
75 | - [0x802D4B44, "__ll_lshift"]
76 | - [0x802D4B70, "__ll_rem"]
77 | - [0x802D4BAC, "__ll_div"]
78 | - [0x802D4C08, "__ll_mul"]
79 | - [0x802D4C38, "__ull_divremi"]
80 | - [0x802D4C98, "__ll_mod"]
81 | - [0x802D4D34, "__ll_rshift"]
82 | - [0x802D4D70, "osVirtualToPhysical"]
83 | - [0x802D4DF0, "osWriteBackDCache"]
84 | - [0x802D4F10, "guOrthoF"]
85 | - [0x802D5064, "guFrustum"]
86 | - [0x802D50D0, "guPerspectiveF"]
87 | - [0x802D5300, "guPerspective"]
88 | - [0x802D5760, "guMtxF2L"]
89 | - [0x802D5860, "guMtxIdentF"]
90 | - [0x802D59D0, "guRotateRPYF"]
91 | - [0x802D5A24, "guRotateRPY"]
92 | - [0x802D5F30, "sqrtf"]
93 | - [0x802D6270, "sinf"]
94 | - [0x802D6430, "osCreateMesgQueue"]
95 | - [0x802D64A0, "osViSetSpecialFeatures"]
96 | - [0x802D6660, "osWriteBackDCacheAll"]
97 | - [0x802D6690, "osInvalDCache"]
98 | - [0x802D6740, "osDestroyThread"]
99 | - [0x802D6840, "cosf"]
100 | - [0x802D69B0, "proutSprintf"]
101 | - [0x802D6A1C, "sprintf"]
102 | - [0x802D75B0, "osSetIntMask"]
103 | - [0x802D83B4, "alBnkfNew"]
104 | - [0x802D84B8, "alSetFileNew"]
105 | - [0x802D9770, "osGetCount"]
106 | - [0x802D9820, "__osViInit"]
107 | - [0x802D9950, "osAiSetFrequency"]
108 | - [0x802D9AB0, "osAiSetNextBuffer"]
109 | - [0x802D9B60, "osAiGetLength"]
110 | - [0x802DA240, "osPiStartDma"]
111 | - [0x802DA560, "osCreateViManager"]
112 | - [0x802DA6E4, "__osViDevMgrMain"]
113 | - [0x802DA8C0, "osViSetMode"]
114 | - [0x802DA930, "osSetEventMsg"]
115 | - [0x802DA9A0, "osViSetEventMsg"]
116 | - [0x802DAAA0, "osViSwapBuffer"]
117 | - [0x802DAAF0, "osSetTimer"]
118 | - [0x802DAC50, "osSpTaskDunno"]
119 | - [0x802DAD6C, "osSpTaskLoad"]
120 | - [0x802DAECC, "osSpTaskStartGo"]
121 | - [0x802DAF10, "osSpTaskYield"]
122 | - [0x802DAFF0, "osContInit"]
123 | - [0x802DB1EC, "__osContGetInitData"]
124 | - [0x802DB2BC, "__osPackRequestData"]
125 | - [0x802DB420, "osContStartReadData"]
126 | - [0x802DB4E4, "osContGetReadData"]
127 | - [0x802DB680, "osInvalCache"]
128 | - [0x802DB700, "bzero"]
129 | - [0x802DB8F0, "__osGetSR"]
130 | - [0x802DB900, "__osSetFpcCsr"]
131 | - [0x802DB910, "__osSiRawReadIo"]
132 | - [0x802DB960, "__osSiRawWriteIo"]
133 | - [0x802DB9B0, "__osExceptionPreamble"]
134 | - [0x802DB9C0, "__osExceptionHandler"]
135 | - [0x802DBFF0, "__osEnqueueAndYield"]
136 | - [0x802DC080, "__osEnqueueThread"]
137 | - [0x802DC0C8, "__osPopThread"]
138 | - [0x802DC0D8, "__osDispatchThread"]
139 | - [0x802DC218, "__osCleanupThread"]
140 | - [0x802DC280, "__osDisableInt"]
141 | - [0x802DC2A0, "__osRestoreInt"]
142 | - [0x802DC300, "__osPiCreateAccessQueue"]
143 | - [0x802DC350, "__osPiGetAccess"]
144 | - [0x802DC394, "__osPiRelAccess"]
145 | - [0x802DC3C0, "osGetThreadPri"]
146 | - [0x802DC3E0, "osPiRawStartDma"]
147 | - [0x802DC4C0, "__osDevMgrMain"]
148 | - [0x802DC640, "__osTimerServicesInit"]
149 | - [0x802DC6CC, "__osTimerInterrupt"]
150 | - [0x802DC844, "__osSetTimerIntr"]
151 | - [0x802DC8B8, "__osInsertTimer"]
152 | - [0x802DCA40, "__osProbeTLB"]
153 | - [0x802DCB00, "_Printf"]
154 | - [0x802DDC90, "memcpy"]
155 | - [0x802DFB50, "__osAiDeviceBusy"]
156 | - [0x802E20F0, "osJamMesg"]
157 | - [0x802E2280, "__osSpGetStatus"]
158 | - [0x802E2290, "bcopy"]
159 | - [0x802E25A0, "__osSpSetStatus"]
160 | - [0x802E25B0, "__osSpSetPc"]
161 | - [0x802E25F0, "__osSpRawStartDma"]
162 | - [0x802E2680, "__osSpDeviceBusy"]
163 | - [0x802E26B0, "__osSiRawStartDma"]
164 | - [0x802E2760, "__osSiCreateAccessQueue"]
165 | - [0x802E27B0, "__osSiGetAccess"]
166 | - [0x802E27F4, "__osSiRelAccess"]
167 | - [0x802E2820, "__osSiDeviceBusy"]
168 | - [0x802E2CD0, "__osSyncPutChars"]
169 | - [0x802E2E00, "__osSetCompare"]
170 | - [0x802E5150, "__osAtomicDec"]
171 |
--------------------------------------------------------------------------------
/configs/blast_corps.u.1.1.code.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file
2 | name: "Blast Corps (U) (V1.1) hd_code_text.raw"
3 |
4 | # checksums from ROM header offsets 0x10 and 0x14
5 | # used for auto configuration detection
6 | checksum1: 0x3C0E00FF
7 | checksum2: 0x35CEB000
8 |
9 | # base filename used for outputs (please, no spaces)
10 | basename: "blast_corps.u.1.1.hd_code_text"
11 |
12 | # ranges to split the ROM into
13 | # types:
14 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
15 | ranges:
16 | # start, end, type, label
17 | - [0x000000, 0x0A4410, "asm", "main", 0x802447C0]
18 |
19 | # Labels for functions or data memory addresses
20 | # All label addresses are RAM addresses
21 | # Order does not matter
22 | labels:
23 | - [0x802447C0, "MainJump"]
24 | - [0x80244870, "Thread1"]
25 | - [0x80244930, "Thread3"]
26 | - [0x8025615C, "LoadLevel"]
27 | - [0x80267A9C, "Thread4"]
28 | - [0x8026FBB0, "LoadLevelRdus"]
29 | - [0x80270F7C, "Thread5"]
30 | - [0x8028B4C4, "InitiateDma"]
31 | - [0x8028C190, "LoadLevelAmmo"]
32 | - [0x8028D4C0, "LoadLevelTnt"]
33 | - [0x8028FDA0, "LoadLevelSquareBlocks"]
34 | - [0x802A1A9C, "LoadLevelTodo74"]
35 | - [0x802A1C20, "LoadLevelTodo2C"]
36 | - [0x802A1D54, "LoadLevelBuildings"]
37 | - [0x802A2BB0, "CopyBuildingTableToRam"]
38 | - [0x802A2A98, "InflateBuildingData"]
39 | - [0x802A2C54, "LoadLevelTodo60"]
40 | - [0x802A2D68, "LoadLevelTodo4C"]
41 | - [0x802A3008, "LoadLevelTodo78"]
42 | - [0x802A350C, "LoadLevelVehicles"]
43 | - [0x802A303C, "LoadLevelMissileCarrier"]
44 | - [0x802A3D54, "LoadLevelCollisionXZ"]
45 | - [0x802A3DF8, "LoadLevelTodo70"]
46 | - [0x802A3E9C, "LoadLevelTodo64"]
47 | - [0x802A3F80, "LoadLevelTrainPlatform"]
48 | - [0x802A4464, "LoadLevelTerrain"]
49 | - [0x802A44E4, "AlignTo8Bytes"]
50 | - [0x802A5510, "LoadLevelTodo40"]
51 | - [0x802A5604, "LoadLevelTodo44"]
52 | - [0x802A57DC, "DecodeTexture"]
53 | - [0x802A5958, "DecodeTexture6"]
54 | - [0x802A5A2C, "DecodeTexture3"]
55 | - [0x802A5AE0, "DecodeTexture1"]
56 | - [0x802A5B90, "DecodeTexture2"]
57 | - [0x802A5C5C, "DecodeTexture4"]
58 | - [0x802A5D34, "DecodeTexture5"]
59 | - [0x802A5E10, "DecodeTexture0"]
60 | - [0x802C4108, "GzipInflate"]
61 | - [0x802CEAA0, "LoadLevelCommPoint"]
62 | - [0x802D4020, "osInitialize"]
63 | - [0x802D4250, "osEPiRawReadIo"]
64 | - [0x802D42B0, "osCreateThread"]
65 | - [0x802D4400, "osStartThread"]
66 | - [0x802D4560, "osCreatePiManager"]
67 | - [0x802D46E0, "osSetThreadPri"]
68 | - [0x802D47C0, "osSendMesg"]
69 | - [0x802D4910, "osRecvMesg"]
70 | - [0x802D4A50, "osViBlack"]
71 | - [0x802D4AC0, "osGetTime"]
72 | - [0x802D4B50, "__ull_rshift"]
73 | - [0x802D4B7C, "__ull_rem"]
74 | - [0x802D4BB8, "__ull_div"]
75 | - [0x802D4BF4, "__ll_lshift"]
76 | - [0x802D4C20, "__ll_rem"]
77 | - [0x802D4C5C, "__ll_div"]
78 | - [0x802D4CB8, "__ll_mul"]
79 | - [0x802D4CE8, "__ull_divremi"]
80 | - [0x802D4D48, "__ll_mod"]
81 | - [0x802D4DE4, "__ll_rshift"]
82 | - [0x802D4E20, "osVirtualToPhysical"]
83 | - [0x802D4EA0, "osWriteBackDCache"]
84 | - [0x802D4FC0, "guOrthoF"]
85 | - [0x802D5114, "guFrustum"]
86 | - [0x802D5180, "guPerspectiveF"]
87 | - [0x802D53B0, "guPerspective"]
88 | - [0x802D5810, "guMtxF2L"]
89 | - [0x802D5910, "guMtxIdentF"]
90 | - [0x802D5A80, "guRotateRPYF"]
91 | - [0x802D5AD4, "guRotateRPY"]
92 | - [0x802D5FE0, "sqrtf"]
93 | - [0x802D6320, "sinf"]
94 | - [0x802D64E0, "osCreateMesgQueue"]
95 | - [0x802D6550, "osViSetSpecialFeatures"]
96 | - [0x802D6710, "osWriteBackDCacheAll"]
97 | - [0x802D6740, "osInvalDCache"]
98 | - [0x802D67F0, "osDestroyThread"]
99 | - [0x802D68F0, "cosf"]
100 | - [0x802D6A60, "proutSprintf"]
101 | - [0x802D6ACC, "sprintf"]
102 | - [0x802D7660, "osSetIntMask"]
103 | - [0x802D8464, "alBnkfNew"]
104 | - [0x802D8568, "alSetFileNew"]
105 | - [0x802D9820, "osGetCount"]
106 | - [0x802D98D0, "__osViInit"]
107 | - [0x802D9A00, "osAiSetFrequency"]
108 | - [0x802D9B60, "osAiSetNextBuffer"]
109 | - [0x802D9C10, "osAiGetLength"]
110 | - [0x802DA2F0, "osPiStartDma"]
111 | - [0x802DA610, "osCreateViManager"]
112 | - [0x802DA794, "__osViDevMgrMain"]
113 | - [0x802DA970, "osViSetMode"]
114 | - [0x802DA9E0, "osSetEventMsg"]
115 | - [0x802DAA50, "osViSetEventMsg"]
116 | - [0x802DAB50, "osViSwapBuffer"]
117 | - [0x802DABA0, "osSetTimer"]
118 | - [0x802DAD00, "osSpTaskDunno"]
119 | - [0x802DAE1C, "osSpTaskLoad"]
120 | - [0x802DAF7C, "osSpTaskStartGo"]
121 | - [0x802DAFC0, "osSpTaskYield"]
122 | - [0x802DB0A0, "osContInit"]
123 | - [0x802DB29C, "__osContGetInitData"]
124 | - [0x802DB36C, "__osPackRequestData"]
125 | - [0x802DB4D0, "osContStartReadData"]
126 | - [0x802DB594, "osContGetReadData"]
127 | - [0x802DB730, "osInvalCache"]
128 | - [0x802DB7B0, "bzero"]
129 | - [0x802DB9A0, "__osGetSR"]
130 | - [0x802DB9B0, "__osSetFpcCsr"]
131 | - [0x802DB9C0, "__osSiRawReadIo"]
132 | - [0x802DBA10, "__osSiRawWriteIo"]
133 | - [0x802DBA60, "__osExceptionPreamble"]
134 | - [0x802DBA70, "__osExceptionHandler"]
135 | - [0x802DC0A0, "__osEnqueueAndYield"]
136 | - [0x802DC130, "__osEnqueueThread"]
137 | - [0x802DC178, "__osPopThread"]
138 | - [0x802DC188, "__osDispatchThread"]
139 | - [0x802DC2C8, "__osCleanupThread"]
140 | - [0x802DC330, "__osDisableInt"]
141 | - [0x802DC350, "__osRestoreInt"]
142 | - [0x802DC3B0, "__osPiCreateAccessQueue"]
143 | - [0x802DC400, "__osPiGetAccess"]
144 | - [0x802DC444, "__osPiRelAccess"]
145 | - [0x802DC470, "osGetThreadPri"]
146 | - [0x802DC490, "osPiRawStartDma"]
147 | - [0x802DC570, "__osDevMgrMain"]
148 | - [0x802DC6F0, "__osTimerServicesInit"]
149 | - [0x802DC77C, "__osTimerInterrupt"]
150 | - [0x802DC8F4, "__osSetTimerIntr"]
151 | - [0x802DC968, "__osInsertTimer"]
152 | - [0x802DCAF0, "__osProbeTLB"]
153 | - [0x802DCBB0, "_Printf"]
154 | - [0x802DDD40, "memcpy"]
155 | - [0x802DFC00, "__osAiDeviceBusy"]
156 | - [0x802E21A0, "osJamMesg"]
157 | - [0x802E2330, "__osSpGetStatus"]
158 | - [0x802E2340, "bcopy"]
159 | - [0x802E2650, "__osSpSetStatus"]
160 | - [0x802E2660, "__osSpSetPc"]
161 | - [0x802E26A0, "__osSpRawStartDma"]
162 | - [0x802E2730, "__osSpDeviceBusy"]
163 | - [0x802E2760, "__osSiRawStartDma"]
164 | - [0x802E2810, "__osSiCreateAccessQueue"]
165 | - [0x802E2860, "__osSiGetAccess"]
166 | - [0x802E28A4, "__osSiRelAccess"]
167 | - [0x802E28D0, "__osSiDeviceBusy"]
168 | - [0x802E2D80, "__osSyncPutChars"]
169 | - [0x802E2EB0, "__osSetCompare"]
170 | - [0x802E5200, "__osAtomicDec"]
171 |
--------------------------------------------------------------------------------
/configs/blast_dozer.code.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file
2 | name: "Blast Dozer (J) hd_code_text.raw"
3 |
4 | # checksums from ROM header offsets 0x10 and 0x14
5 | # used for auto configuration detection
6 | checksum1: 0x3C0E00FF
7 | checksum2: 0x35CEB000
8 |
9 | # base filename used for outputs (please, no spaces)
10 | basename: "blast_dozer.hd_code_text"
11 |
12 | # ranges to split the ROM into
13 | # types:
14 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
15 | ranges:
16 | # start, end, type, label
17 | - [0x000000, 0x0A4360, "asm", "main", 0x802447C0]
18 |
19 | # Labels for functions or data memory addresses
20 | # All label addresses are RAM addresses
21 | # Order does not matter
22 | labels:
23 | - [0x802447C0, "MainJump"]
24 | - [0x80244870, "Thread1"]
25 | - [0x80244930, "Thread3"]
26 | - [0x8025615C, "LoadLevel"]
27 | - [0x80267C5C, "Thread4"]
28 | - [0x8026FEB0, "LoadLevelRdus"]
29 | - [0x8027127C, "Thread5"]
30 | - [0x8028B824, "InitiateDma"]
31 | - [0x8028C4F0, "LoadLevelAmmo"]
32 | - [0x8028D820, "LoadLevelTnt"]
33 | - [0x80290100, "LoadLevelSquareBlocks"]
34 | - [0x802A1E0C, "LoadLevelTodo74"]
35 | - [0x802A1F90, "LoadLevelTodo2C"]
36 | - [0x802A20C4, "LoadLevelBuildings"]
37 | - [0x802A2F20, "CopyBuildingTableToRam"]
38 | - [0x802A2E08, "InflateBuildingData"]
39 | - [0x802A2FC4, "LoadLevelTodo60"]
40 | - [0x802A30D8, "LoadLevelTodo4C"]
41 | - [0x802A3378, "LoadLevelTodo78"]
42 | - [0x802A387C, "LoadLevelVehicles"]
43 | - [0x802A33AC, "LoadLevelMissileCarrier"]
44 | - [0x802A40C4, "LoadLevelCollisionXZ"]
45 | - [0x802A4168, "LoadLevelTodo70"]
46 | - [0x802A420C, "LoadLevelTodo64"]
47 | - [0x802A42F0, "LoadLevelTrainPlatform"]
48 | - [0x802A47D4, "LoadLevelTerrain"]
49 | - [0x802A4854, "AlignTo8Bytes"]
50 | - [0x802A5880, "LoadLevelTodo40"]
51 | - [0x802A5974, "LoadLevelTodo44"]
52 | - [0x802A5B4C, "DecodeTexture"]
53 | - [0x802A5CC8, "DecodeTexture6"]
54 | - [0x802A5D9C, "DecodeTexture3"]
55 | - [0x802A5E50, "DecodeTexture1"]
56 | - [0x802A5F00, "DecodeTexture2"]
57 | - [0x802A5FCC, "DecodeTexture4"]
58 | - [0x802A60A4, "DecodeTexture5"]
59 | - [0x802A6180, "DecodeTexture0"]
60 | - [0x802C44D8, "GzipInflate"]
61 | - [0x802CEE70, "LoadLevelCommPoint"]
62 | - [0x802D43F0, "osInitialize"]
63 | - [0x802D4620, "osEPiRawReadIo"]
64 | - [0x802D4680, "osCreateThread"]
65 | - [0x802D47D0, "osStartThread"]
66 | - [0x802D4930, "osCreatePiManager"]
67 | - [0x802D4AB0, "osSetThreadPri"]
68 | - [0x802D4B90, "osSendMesg"]
69 | - [0x802D4CE0, "osRecvMesg"]
70 | - [0x802D4E20, "osViBlack"]
71 | - [0x802D4E90, "osGetTime"]
72 | - [0x802D4F20, "__ull_rshift"]
73 | - [0x802D4F4C, "__ull_rem"]
74 | - [0x802D4F88, "__ull_div"]
75 | - [0x802D4FC4, "__ll_lshift"]
76 | - [0x802D4FF0, "__ll_rem"]
77 | - [0x802D502C, "__ll_div"]
78 | - [0x802D5088, "__ll_mul"]
79 | - [0x802D50B8, "__ull_divremi"]
80 | - [0x802D5118, "__ll_mod"]
81 | - [0x802D51B4, "__ll_rshift"]
82 | - [0x802D51F0, "osVirtualToPhysical"]
83 | - [0x802D5270, "osWriteBackDCache"]
84 | - [0x802D5390, "guOrthoF"]
85 | - [0x802D54E4, "guFrustum"]
86 | - [0x802D5550, "guPerspectiveF"]
87 | - [0x802D5780, "guPerspective"]
88 | - [0x802D5BE0, "guMtxF2L"]
89 | - [0x802D5CE0, "guMtxIdentF"]
90 | - [0x802D5E50, "guRotateRPYF"]
91 | - [0x802D5EA4, "guRotateRPY"]
92 | - [0x802D63B0, "sqrtf"]
93 | - [0x802D66F0, "sinf"]
94 | - [0x802D68B0, "osCreateMesgQueue"]
95 | - [0x802D6920, "osViSetSpecialFeatures"]
96 | - [0x802D6AE0, "osWriteBackDCacheAll"]
97 | - [0x802D6B10, "osInvalDCache"]
98 | - [0x802D6BC0, "osDestroyThread"]
99 | - [0x802D6CC0, "cosf"]
100 | - [0x802D6E30, "proutSprintf"]
101 | - [0x802D6E9C, "sprintf"]
102 | - [0x802D7A30, "osSetIntMask"]
103 | - [0x802D8834, "alBnkfNew"]
104 | - [0x802D8938, "alSetFileNew"]
105 | - [0x802D9BF0, "osGetCount"]
106 | - [0x802D9CA0, "__osViInit"]
107 | - [0x802D9DD0, "osAiSetFrequency"]
108 | - [0x802D9F30, "osAiSetNextBuffer"]
109 | - [0x802D9FE0, "osAiGetLength"]
110 | - [0x802DA6C0, "osPiStartDma"]
111 | - [0x802DA9E0, "osCreateViManager"]
112 | - [0x802DAB64, "__osViDevMgrMain"]
113 | - [0x802DAD40, "osViSetMode"]
114 | - [0x802DADB0, "osSetEventMsg"]
115 | - [0x802DAE20, "osViSetEventMsg"]
116 | - [0x802DAF20, "osViSwapBuffer"]
117 | - [0x802DAF70, "osSetTimer"]
118 | - [0x802DB0D0, "osSpTaskDunno"]
119 | - [0x802DB1EC, "osSpTaskLoad"]
120 | - [0x802DB34C, "osSpTaskStartGo"]
121 | - [0x802DB390, "osSpTaskYield"]
122 | - [0x802DB470, "osContInit"]
123 | - [0x802DB66C, "__osContGetInitData"]
124 | - [0x802DB73C, "__osPackRequestData"]
125 | - [0x802DB8A0, "osContStartReadData"]
126 | - [0x802DB964, "osContGetReadData"]
127 | - [0x802DBB00, "osInvalCache"]
128 | - [0x802DBB80, "bzero"]
129 | # [0x802DBD60, "__osSetSR"]
130 | - [0x802DBD70, "__osGetSR"]
131 | - [0x802DBD80, "__osSetFpcCsr"]
132 | - [0x802DBD90, "__osSiRawReadIo"]
133 | - [0x802DBDE0, "__osSiRawWriteIo"]
134 | - [0x802DBE30, "__osExceptionPreamble"]
135 | - [0x802DBE40, "__osExceptionHandler"]
136 | - [0x802DC470, "__osEnqueueAndYield"]
137 | - [0x802DC500, "__osEnqueueThread"]
138 | - [0x802DC548, "__osPopThread"]
139 | - [0x802DC558, "__osDispatchThread"]
140 | - [0x802DC698, "__osCleanupThread", 0x802DC6A0]
141 | - [0x802DC700, "__osDisableInt"]
142 | - [0x802DC720, "__osRestoreInt"]
143 | - [0x802DC780, "__osPiCreateAccessQueue"]
144 | - [0x802DC7D0, "__osPiGetAccess"]
145 | - [0x802DC814, "__osPiRelAccess"]
146 | - [0x802DC840, "osGetThreadPri"]
147 | - [0x802DC860, "osPiRawStartDma"]
148 | - [0x802DC940, "__osDevMgrMain"]
149 | - [0x802DCAC0, "__osTimerServicesInit"]
150 | - [0x802DCB4C, "__osTimerInterrupt"]
151 | - [0x802DCCC4, "__osSetTimerIntr"]
152 | - [0x802DCD38, "__osInsertTimer"]
153 | - [0x802DCEC0, "__osProbeTLB"]
154 | - [0x802DCF80, "_Printf"]
155 | - [0x802DE110, "memcpy"]
156 | - [0x802DFFD0, "__osAiDeviceBusy"]
157 | - [0x802E2570, "osJamMesg"]
158 | - [0x802E2700, "__osSpGetStatus"]
159 | - [0x802E2710, "bcopy"]
160 | - [0x802E2A20, "__osSpSetStatus"]
161 | - [0x802E2A30, "__osSpSetPc"]
162 | - [0x802E2A70, "__osSpRawStartDma"]
163 | - [0x802E2B00, "__osSpDeviceBusy"]
164 | - [0x802E2B30, "__osSiRawStartDma"]
165 | - [0x802E2BE0, "__osSiCreateAccessQueue"]
166 | - [0x802E2C30, "__osSiGetAccess"]
167 | - [0x802E2C74, "__osSiRelAccess"]
168 | - [0x802E2CA0, "__osSiDeviceBusy"]
169 | - [0x802E3150, "__osSyncPutChars"]
170 | - [0x802E3280, "__osSetCompare"]
171 | - [0x802E55D0, "__osAtomicDec"]
172 |
--------------------------------------------------------------------------------
/configs/doraemon.yaml:
--------------------------------------------------------------------------------
1 | name: "Doraemon - Mittsu no Seireiseki (J)"
2 |
3 | checksum1: 0xbff7b1c2
4 | checksum2: 0xaebf148e
5 |
6 | basename: "doraemon"
7 |
8 | ranges:
9 | - [0x000000, 0x000040, "header", "header"]
10 | - [0x000040, 0x001000, "bin", "boot"]
11 | - [0x001000, 0x0A0754, "asm", "main", 0x80000400]
12 | # TODO: RSP ucode
13 | # - [0x0A0830, 0x0A1030, "bin", "rsp.audio"] # 0x8009FC30 [0x0800]
14 | # - [0x0A3040, 0x0A4040, "bin", "rsp.graphics"] # 0x800A2440 [0x1000]
15 |
16 | labels:
17 | - [0x80000400, "EntryPoint"]
18 | - [0x80000450, "Main"]
19 | - [0x80001BF8, "ReadControllerData"]
20 | - [0x80001C38, "InitControllers"]
21 | - [0x800004C0, "Thread1_Idle"]
22 | - [0x80006D94, "Thread3"]
23 | - [0x80000BC0, "Thread4"]
24 | - [0x80000550, "Thread10"]
25 | - [0x80001EF0, "Thread20"]
26 | - [0x800016D0, "Thread30"]
27 | - [0x80002470, "Thread44_1"]
28 | - [0x80002944, "Thread44_2"]
29 | - [0x80002AF4, "Thread44_3"]
30 | - [0x8008BAC0, "osContInit"]
31 | - [0x8008AF70, "osGetTime"]
32 | - [0x80091950, "osGetCount"]
33 | - [0x80092068, "__ull_div"]
34 | - [0x80092000, "__ull_rshift"]
35 | - [0x8009202C, "__ull_rem"]
36 | - [0x800920A4, "__ll_lshift"]
37 | - [0x800920D0, "__ll_rem"]
38 | - [0x8009210C, "__ll_div"]
39 | - [0x80092168, "__ll_mul"]
40 | - [0x80092198, "__ull_divremi"]
41 | - [0x800921F8, "__ll_mod"]
42 | - [0x80092294, "__ll_rshift"]
43 | - [0x8008A840, "osCreateMesgQueue"]
44 | - [0x80095000, "osSetTimer"]
45 | - [0x8008AE30, "osRecvMesg"]
46 | - [0x8008B040, "osSendMesg"]
47 | - [0x8008BD88, "__osPackRequestData"]
48 | - [0x80098A70, "__osSiRawStartDma"]
49 | - [0x8008BCB8, "__osContGetInitData"]
50 | - [0x800989B0, "__osSiCreateAccessQueue"]
51 | - [0x8008BE80, "osEepromProbe"]
52 | - [0x800950E0, "osEepromRead"]
53 | - [0x80089E50, "osEepromLongRead"]
54 | - [0x80094B20, "osEepromWrite"]
55 | - [0x80089D10, "osEepromLongWrite"]
56 | - [0x80094CD0, "EepromWriteSerialize"]
57 | - [0x80091B40, "guMtxIdentF"]
58 | - [0x80091CB0, "guScaleF"]
59 | - [0x80091D04, "guScale"]
60 | - [0x80091A40, "guMtxF2L"]
61 | - [0x8008C820, "guPerspectiveF"]
62 | - [0x8008CA50, "guPerspective"]
63 | - [0x80091D50, "guRotateRPYF"]
64 | - [0x80091EE4, "guRotateRPY"]
65 | - [0x8008C4E0, "sinf"]
66 | - [0x8008C6A0, "cosf"]
67 | - [0x80098A00, "__osSiGetAccess"]
68 | - [0x80094DDC, "__osEepStatus"]
69 | - [0x80098A44, "__osSiRelAccess"]
70 | - [0x80089F90, "osInitialize"]
71 | - [0x800953F0, "__osGetSR"]
72 | - [0x80095400, "__osSetFpcCsr"]
73 | - [0x80095410, "__osSiRawReadIo"]
74 | - [0x80095460, "__osSiRawWriteIo"]
75 | - [0x8009D8E0, "__osSiDeviceBusy"]
76 | - [0x800954B0, "__osExceptionPreamble"]
77 | - [0x800954C0, "__osExceptionHandler"]
78 | - [0x80091890, "osWriteBackDCache"]
79 | - [0x80095DB0, "osInvalCache"]
80 | - [0x8008DD60, "osInvalDCache"]
81 | - [0x8008B320, "osWriteBackDCacheAll"]
82 | - [0x80095E90, "osEPiRawReadIo"]
83 | - [0x8008DBB0, "osPiStartDma"]
84 | - [0x8009CF90, "osJamMesg"]
85 | - [0x800984C0, "memcpy"]
86 | - [0x800984EC, "strlen"]
87 | - [0x80098514, "strchr"]
88 | - [0x80095EF0, "bzero"]
89 | - [0x80098560, "bcopy"]
90 | - [0x8008C810, "sqrtf"]
91 | - [0x8008B250, "sprintf"]
92 | - [0x8008B274, "proutSprintf"]
93 | - [0x80097E70, "_Printf"]
94 | - [0x8008D390, "osVirtualToPhysical"]
95 | - [0x8008B6E0, "osContStartReadData"]
96 | - [0x8008B7A4, "osContGetReadData"]
97 | - [0x80095ACC, "__osEnqueueAndYield"]
98 | - [0x80095C14, "__osPopThread"]
99 | - [0x80095BCC, "__osEnqueueThread"]
100 | - [0x80095C24, "__osDispatchThread"]
101 | - [0x80096860, "__osDisableInt"]
102 | - [0x80096880, "__osRestoreInt"]
103 | - [0x8008A230, "osCreateThread"]
104 | - [0x8008A5B0, "osDestroyThread"]
105 | - [0x80095DA0, "__osCleanupThread"]
106 | - [0x8008A870, "osCreateViManager"]
107 | - [0x8008A9F8, "__osViDevMgrMain"]
108 | - [0x80096FBC, "__osTimerInterrupt"]
109 | - [0x8009DB00, "__osSetCompare"]
110 | - [0x80097134, "__osSetTimerIntr"]
111 | - [0x800971A8, "__osInsertTimer"]
112 | - [0x80096F30, "__osTimerServicesInit"]
113 | - [0x8008ABD0, "osViSetMode"]
114 | - [0x8008AC40, "osViBlack"]
115 | - [0x800916D0, "osViSetSpecialFeatures"]
116 | - [0x8008B2D0, "osViSwapBuffer"]
117 | - [0x8008ACB0, "osSetEventMsg"]
118 | - [0x8008AD20, "osViSetEventMsg"]
119 | - [0x800969A0, "osGetThreadPri"]
120 | - [0x8008A4D0, "osSetThreadPri"]
121 | - [0x80097330, "__osViInit"]
122 | - [0x8008A380, "osStartThread"]
123 | - [0x800968E0, "__osPiCreateAccessQueue"]
124 | - [0x80096930, "__osPiGetAccess"]
125 | - [0x80096974, "__osPiRelAccess"]
126 | - [0x800969C0, "osPiRawStartDma"]
127 | - [0x8008A6B0, "osCreatePiManager"]
128 | - [0x80098870, "__osSpSetStatus"]
129 | - [0x800977F0, "__osSpGetStatus"]
130 | - [0x8008B46C, "osSpTaskLoad"]
131 | - [0x8008B5CC, "osSpTaskStartGo"]
132 | - [0x80098950, "__osSpDeviceBusy"]
133 | - [0x8008B6C0, "osSpTaskYield"]
134 | - [0x8008B350, "TaskVirtualToPhysical"]
135 | - [0x80098880, "__osSpSetPc"]
136 | - [0x800988C0, "__osSpRawStartDma"]
137 | - [0x8008D170, "osAiSetFrequency"]
138 | - [0x8008D4C0, "osAiGetLength"]
139 | - [0x8008D410, "osAiSetNextBuffer"]
140 | - [0x8009A950, "__osAiDeviceBusy"]
141 | - [0x8009A890, "__osProbeTLB"]
142 |
--------------------------------------------------------------------------------
/configs/pifboot.yaml:
--------------------------------------------------------------------------------
1 | # ROM splitter configuration file name: "N64 PIF IPL NTSC" # checksums from ROM header offsets 0x10 and 0x14 # used for auto configuration detection
2 | checksum1: 0x40898000
3 | checksum2: 0x3C08A404
4 |
5 | # base filename used for outputs (please, no spaces)
6 | basename: "pif.ntsc"
7 |
8 | # ranges to split the ROM into
9 | # types:
10 | # asm - MIPS assembly block. Symbol names are in 'labels' list below
11 | ranges:
12 | # start, end, type, label
13 | - [0x000000, 0x0000D4, "asm", "rom", 0x1FC00000]
14 | - [0x0000D4, 0x000800, "asm", "ram", 0xA4000000]
15 |
16 | # Labels for functions or data memory addresses
17 | # All label addresses are RAM addresses
18 | # Order does not matter
19 | labels:
20 | - [0x1FC00000, "Reset"]
21 | - [0xA4000000, "Main"]
22 | - [0xA4000550, "Multiply"]
23 | - [0xA4000184, "proc_A4000184"]
24 |
25 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Example modifications
2 |
3 | This directory contains examples for replacing textures, patching assembly
4 | source, and updating binaries. The steps for applying the examples to a split
5 | ROM are given below. Most examples include a batch file to automate the process.
6 |
7 | ## Hello World
8 | Print Hello World to the screen by hooking into a behavior and overriding an
9 | unused function. Kills a butterfly.
10 |
11 | 1. patch -p0 < sm64.hello\_world.patch
12 |
13 | Thanks to Jedi for implementing this example and Kaze for his ASM Tutorial:
14 | http://www.smwcentral.net/?p=viewthread&t=68900
15 |
16 | ## Texture swap
17 |
18 | ### Castle grounds
19 | Adds a little color to the castle exterior texture in castle grounds (RGBA).
20 |
21 | 1. copy texture\_swap/castle\_grounds\_textures.0x01000.png to sm64.split/textures/
22 |
23 | ### Peach's signature
24 | Replace Peach's signature (IA8) with someone else's.
25 |
26 | 1. copy texture\_swap/castle\_grounds\_segment7.0x0EAE8.ia8.png to sm64.split/textures/
27 |
28 | ### Transition
29 | Swap star transition with mushroom.
30 |
31 | 1. copy texture\_swap/font\_graphics.0x122B8.ia8.png to sm64.split/textures/
32 |
33 | ### Skybox
34 | Replace water skybox with night sky from Lylat System.
35 |
36 | 1. copy texture\_swap/water\_skybox.0x00000.skybox.png to sm64.split/textures/
37 |
38 | ## HUD toggle
39 | Source patch for R-button toggle show HUD ASM
40 |
41 | 1. patch -p0 < sm64.hudtoggle.patch
42 |
43 | Thanks to Skelux and Kaze for each of their HUD toggling implementations:
44 | https://sites.google.com/site/supermario64starroad/home/sm64-documents/skelux
45 | http://smwc.me/1208284
46 |
47 | ## Coin colors
48 | Coin vertex colors and texture replacement.
49 |
50 | 1. copy the png files from coin\_colors/ to sm64.split/textures/
51 | 2. Apply coin\_colors.ips IPS patch to sm64.split/bin/doors\_trees\_coins.bin
52 |
53 | Thanks to cpuHacka101 for details on this
54 | http://www.smwcentral.net/?p=viewthread&t=58544
55 |
56 | ## Behavior
57 | Source patch for modifying the sign posts behavior to rotate about the Y-axis
58 |
59 | 1. patch -p0 < sm64.rotating\_sign.patch
60 |
61 | ## Skip Screens
62 | Skip title, Mario, menu screens at startup or Peach and Lakitu intros.
63 |
64 | 1. patch -p0 < skip\_mario.patch
65 | 2. patch -p0 < skip\_title.patch
66 | 3. patch -p0 < skip\_menu.patch
67 | 4. patch -p0 < skip\_peach.patch
68 | 5. patch -p0 < skip\_lakitu.patch
69 |
--------------------------------------------------------------------------------
/examples/behavior/sm64.rotating_sign.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/behavior_data.s
2 | +++ sm64.split/behavior_data.s
3 | @@ -2799,7 +2799,7 @@
4 | .word 0x08000000
5 | .word 0x10050000
6 | .word 0x0C000000, ProcessCollision
7 | -.word 0x102B0000
8 | +.word 0x0F130100
9 | .word 0x09000000
10 | beh_sign_on_wall: # 3324
11 | .word 0x00090000
12 |
--------------------------------------------------------------------------------
/examples/coin_colors/coin_colors.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/coin_colors/coin_colors.ips
--------------------------------------------------------------------------------
/examples/coin_colors/doors_trees_coins.0x05780.ia16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/coin_colors/doors_trees_coins.0x05780.ia16.png
--------------------------------------------------------------------------------
/examples/coin_colors/doors_trees_coins.0x05F80.ia16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/coin_colors/doors_trees_coins.0x05F80.ia16.png
--------------------------------------------------------------------------------
/examples/coin_colors/doors_trees_coins.0x06780.ia16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/coin_colors/doors_trees_coins.0x06780.ia16.png
--------------------------------------------------------------------------------
/examples/coin_colors/doors_trees_coins.0x06F80.ia16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/coin_colors/doors_trees_coins.0x06F80.ia16.png
--------------------------------------------------------------------------------
/examples/hello_c/gen/extended.c:
--------------------------------------------------------------------------------
1 | extern void PrintXY(unsigned int x, unsigned int y, const char *str);
2 |
3 | const char HelloString[] = "- Hello World -";
4 | unsigned int x = 1;
5 | unsigned int y = 1;
6 | char xdir = 0, ydir = 0;
7 |
8 | #define MAX_X 0x100
9 | #define MAX_Y 0xB0
10 |
11 | void BehHelloWorld(void)
12 | {
13 | PrintXY(x, y, HelloString);
14 | x += xdir ? -1 : 1;
15 | y += ydir ? -1 : 1;
16 | if (x == 0 || x == MAX_X) xdir = !xdir;
17 | if (y == 0 || y == MAX_Y) ydir = !ydir;
18 | }
19 |
--------------------------------------------------------------------------------
/examples/hello_c/gen/sm64.h:
--------------------------------------------------------------------------------
1 | #ifndef SM64_H
2 | #define SM64_H
3 |
4 | #include
5 |
6 | // handful of useful routines to call from C
7 |
8 | // standard libary
9 | void bcopy(const void *src, void *dest, size_t n);
10 | void bzero(void *s, size_t n);
11 |
12 | // math
13 | float sinf(float);
14 | float cosf(float);
15 | float sqrtf(float);
16 |
17 | // SM64
18 | void PrintInt(unsigned int x, unsigned int y, const char *format, unsigned int value);
19 | void PrintStr(unsigned int x, unsigned int y, const char *str);
20 | void PrintXY(unsigned int x, unsigned int y, const char *str);
21 |
22 | #endif // SM64_H
23 |
--------------------------------------------------------------------------------
/examples/hello_c/hello_c.patch:
--------------------------------------------------------------------------------
1 | diff -Naur gen.orig/behavior_data.s gen/behavior_data.s
2 | --- gen.orig/behavior_data.s 2015-08-05 13:07:51.819231111 -0500
3 | +++ gen/behavior_data.s 2015-08-05 13:13:20.057826973 -0500
4 | @@ -4692,3 +4692,9 @@
5 | .word 0x0C000000, BehIntroSceneLoop
6 | .word 0x09000000
7 | .word 0x00000000
8 | +
9 | +beh_hello_world:
10 | +.word 0x08000000
11 | +.word 0x0C000000, BehHelloWorld
12 | +.word 0x09000000
13 | +.word 0x00000000
14 | diff -Naur gen.orig/extended.c gen/extended.c
15 | --- gen.orig/extended.c 1969-12-31 18:00:00.000000000 -0600
16 | +++ gen/extended.c 2015-08-06 16:31:17.162926557 -0500
17 | @@ -0,0 +1,18 @@
18 | +#include "sm64.h"
19 | +
20 | +const char HelloString[] = "- Hello World -";
21 | +unsigned int x = 1;
22 | +unsigned int y = 1;
23 | +char xdir = 0, ydir = 0;
24 | +
25 | +#define MAX_X 0x100
26 | +#define MAX_Y 0xB0
27 | +
28 | +void BehHelloWorld(void)
29 | +{
30 | + PrintXY(x, y, HelloString);
31 | + x += xdir ? -1 : 1;
32 | + y += ydir ? -1 : 1;
33 | + if (x == 0 || x == MAX_X) xdir = !xdir;
34 | + if (y == 0 || y == MAX_Y) ydir = !ydir;
35 | +}
36 | diff -Naur gen.orig/levels/castle_grounds_level.s gen/levels/castle_grounds_level.s
37 | --- gen.orig/levels/castle_grounds_level.s 2015-08-05 13:07:52.329223754 -0500
38 | +++ gen/levels/castle_grounds_level.s 2015-08-05 13:22:20.880011503 -0500
39 | @@ -67,7 +67,7 @@
40 | .word 0x24181FBB, 0x16F10307, 0xEA0A0000, 0x00000000, 0x00000000, beh_butterfly
41 | .word 0x24181FBB, 0x15610307, 0xEB360000, 0x00000000, 0x00000000, beh_butterfly
42 | .word 0x24181FBB, 0xFA200146, 0x0C7C0000, 0x00000000, 0x00000000, beh_butterfly
43 | -.word 0x24181FBB, 0xFB4C0146, 0x0CE00000, 0x00000000, 0x00000000, beh_butterfly
44 | +.word 0x24181FBB, 0xFB4C0146, 0x0CE00000, 0x00000000, 0x00000000, beh_hello_world
45 | .word 0x24181F55, 0x00000C66, 0xEA070000, 0x00000000, 0x00000000, beh_yoshi
46 | .word 0x07040000
47 | .word 0x1B040000
48 | diff -Naur gen.orig/sm64.h gen/sm64.h
49 | --- gen.orig/sm64.h 1969-12-31 18:00:00.000000000 -0600
50 | +++ gen/sm64.h 2015-08-06 16:31:11.946334171 -0500
51 | @@ -0,0 +1,22 @@
52 | +#ifndef SM64_H
53 | +#define SM64_H
54 | +
55 | +#include
56 | +
57 | +// handful of useful routines to call from C
58 | +
59 | +// standard libary
60 | +void bcopy(const void *src, void *dest, size_t n);
61 | +void bzero(void *s, size_t n);
62 | +
63 | +// math
64 | +float sinf(float);
65 | +float cosf(float);
66 | +float sqrtf(float);
67 | +
68 | +// SM64
69 | +void PrintInt(unsigned int x, unsigned int y, const char *format, unsigned int value);
70 | +void PrintStr(unsigned int x, unsigned int y, const char *str);
71 | +void PrintXY(unsigned int x, unsigned int y, const char *str);
72 | +
73 | +#endif // SM64_H
74 | diff -Naur gen.orig/sm64.ld gen/sm64.ld
75 | --- gen.orig/sm64.ld 2015-08-05 13:07:52.405889314 -0500
76 | +++ gen/sm64.ld 2015-08-05 13:25:47.643687263 -0500
77 | @@ -3,6 +3,7 @@
78 |
79 | OUTPUT_FORMAT ("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
80 | OUTPUT_ARCH (mips)
81 | +ENTRY(EntryPoint)
82 |
83 | SECTIONS
84 | {
85 | @@ -16,8 +17,8 @@
86 | .rodata 0x800000 : {
87 | FILL (0x01) /* fill unused with 0x01 */
88 | * (.mio0);
89 | - * (.rodata);
90 | - * (.data);
91 | + build/sm64.o (.rodata);
92 | + build/sm64.o (.data);
93 | * (.MIPS.abiflags);
94 | . = ALIGN(0x10);
95 | }
96 | @@ -26,13 +27,32 @@
97 | .behavior 0x13000000 : AT( LOADADDR(.rodata) + SIZEOF(.rodata) ) {
98 | FILL (0x01) /* fill unused with 0x01 */
99 | * (.behavior);
100 | + . = ALIGN(0x10);
101 | behavior_length = . - 0x13000000;
102 | - /* default 4MB data (12MB ROM) */
103 | - . = 0x400000 - SIZEOF(.rodata);
104 | }
105 | __load_behavior_data = LOADADDR(.behavior);
106 | __load_behavior_data_end = LOADADDR(.behavior) + behavior_length;
107 |
108 | + /* Create new text section at 0x80400000 loaded immediately after behaviors */
109 | + .text80400000 0x80400000 : AT(__load_behavior_data_end) {
110 | + __run_text80400000 = .;
111 | + * (.text80400000); /* use this for assembly sections */
112 | + build/extended.o (.text);
113 | + build/extended.o (.rodata);
114 | + build/extended.o (.rodata.*);
115 | + build/extended.o (.data);
116 | + build/extended.o (.sdata);
117 | + build/extended.o (.bss);
118 | + build/extended.o (.sbss);
119 | + . = ALIGN(0x10);
120 | + __load_text80400000_len = . - 0x80400000;
121 | + /* default 4MB data (12MB ROM) */
122 | + . = 0x400000 - SIZEOF(.rodata) - SIZEOF(.behavior);
123 | + }
124 | + /* Create two symbols for the start and end addresses. */
125 | + __load_text80400000 = LOADADDR(.text80400000);
126 | + __load_text80400000_end = LOADADDR(.text80400000) + __load_text80400000_len;
127 | +
128 | /* (0x8016F000, 0x801B99DF, 0x7FF4FB40), // 21F4C0-269EA0 [4A9E0] */
129 | .text8016F000 0x8016F000 : AT(0x21F4C0) {
130 | * (.text8016F000);
131 | diff -Naur gen.orig/sm64.s gen/sm64.s
132 | --- gen.orig/sm64.s 2015-08-05 13:07:52.405889314 -0500
133 | +++ gen/sm64.s 2015-08-05 13:12:31.271864732 -0500
134 | @@ -38,30 +38,39 @@
135 | .LEntryPoint_10: # 80246010
136 | addi $t1, $t1, -8
137 | sw $zero, ($t0)
138 | - sw $zero, %lo(0x80340004)($t0) # $zero, 4($t0)
139 | + sw $zero, 4($t0)
140 | bnez $t1, .LEntryPoint_10
141 | addi $t0, $t0, 8
142 | - lui $t2, 0x8024
143 | - lui $sp, 0x8020
144 | - addiu $t2, $t2, 0x6df8
145 | - jr $t2
146 | - addiu $sp, $sp, 0x600
147 | -# end EntryPoint
148 | -
149 | -# alignment
150 | -.word 0x00000000, 0x00000000, 0x00000000, 0x00000000
151 | -.word 0x00000000, 0x00000000
152 | -
153 | -Unknown80246050: # begin 80246050 (001050)
154 | - addiu $sp, $sp, -8
155 | - lw $t6, 0x8032d5ec # lui $t6, 0x8033/lw $t6, -0x2a14($t6)
156 | - lhu $t7, 0x12($t6)
157 | - beqz $t7, .LUnknown80246050_110
158 | - nop
159 | - lh $t8, 0x8032d5bc # lui $t8, 0x8033/lh $t8, -0x2a44($t8)
160 | - lw $t1, 0x8032d5ec # lui $t1, 0x8033/lw $t1, -0x2a14($t1)
161 | - lui $t0, 0x8033
162 | - sll $t9, $t8, 1
163 | +
164 | +# intialize stack so we can call some routines
165 | + la $sp, 0x80200600
166 | +
167 | + jal osWriteBackDCacheAll
168 | + nop
169 | +
170 | + li $a0, 0x0
171 | + la $a1, __load_text80400000
172 | + la $a2, __run_text80400000
173 | + li $a3, __load_text80400000_len
174 | + jal osPiRawStartDma
175 | + nop
176 | +
177 | +.LUntilDmaDone:
178 | + lw $t0, 0xA4600010
179 | + andi $t0, $t0, 0x1
180 | + bne $t0, $zero, .LUntilDmaDone
181 | + nop
182 | +
183 | +# TODO: do these need different args?
184 | + jal osInvalCache
185 | + nop
186 | + jal osInvalDCache
187 | + nop
188 | +# this replaces the lui $t2, 0x8024/addiu $t2, $t2, 0x6df8/jr $t2
189 | + j Main
190 | + nop
191 | +
192 | +# leftover from Unknown80246050:
193 | addu $t0, $t0, $t9
194 | lhu $t0, -0x2a64($t0)
195 | lhu $t2, 0x12($t1)
196 | --- Makefile.orig 2015-08-05 12:49:18.333734339 -0500
197 | +++ Makefile 2015-08-05 12:48:52.617442852 -0500
198 | @@ -44,7 +44,7 @@
199 | all: $(TARGET).gen.z64
200 |
201 | clean:
202 | - rm -f $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).o $(BUILD_DIR)/$(TARGET).bin $(TARGET).v64
203 | + rm -f $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/extended.o $(BUILD_DIR)/$(TARGET).o $(BUILD_DIR)/$(TARGET).bin $(TARGET).v64
204 |
205 | $(MIO0_DIR)/%.mio0: $(MIO0_DIR)/%.bin
206 | $(MIO0TOOL) $< $@
207 | @@ -58,8 +58,8 @@
208 | $(BUILD_DIR)/%.o: gen/%.c Makefile.as | $(BUILD_DIR)
209 | $(CC) $(CFLAGS) -o $@ $<
210 |
211 | -$(BUILD_DIR)/$(TARGET).elf: $(BUILD_DIR)/$(TARGET).o $(LD_SCRIPT)
212 | - $(LD) $(LDFLAGS) -o $@ $< $(LIBS)
213 | +$(BUILD_DIR)/$(TARGET).elf: $(BUILD_DIR)/$(TARGET).o $(BUILD_DIR)/extended.o $(LD_SCRIPT)
214 | + $(LD) $(LDFLAGS) -o $@ $< $(BUILD_DIR)/extended.o $(LIBS)
215 |
216 | $(BUILD_DIR)/$(TARGET).bin: $(BUILD_DIR)/$(TARGET).elf
217 | $(OBJCOPY) $< $@ -O binary
218 |
--------------------------------------------------------------------------------
/examples/hello_world/sm64.hello_world.patch:
--------------------------------------------------------------------------------
1 | diff -aur sm64.split.orig/behavior_data.s sm64.split/behavior_data.s
2 | --- sm64.split.orig/behavior_data.s
3 | +++ sm64.split/behavior_data.s
4 | @@ -4663,3 +4663,8 @@
5 | .word 0x0C000000, BehIntroSceneLoop
6 | .word 0x09000000
7 | .word 0x00000000
8 | +beh_hello_world:
9 | +.word 0x08000000
10 | +.word 0x0C000000, BehHelloWorld
11 | +.word 0x09000000
12 | +.word 0x00000000
13 | diff -aur sm64.split.orig/levels/castle_grounds_level.s sm64.split/levels/castle_grounds_level.s
14 | --- sm64.split.orig/levels/castle_grounds_level.s
15 | +++ sm64.split/levels/castle_grounds_level.s
16 | @@ -56,7 +56,7 @@
17 | .word 0x24181F37, 0xF1050D14, 0xE6090000, 0x00000000, 0x00000000, beh_castle_flag_waving
18 | .word 0x24181F37, 0x0EFB0D14, 0xE6090000, 0x00000000, 0x00000000, beh_castle_flag_waving
19 | .word 0x07040000
20 | -.word 0x24181FBB, 0xEE640196, 0x11300000, 0x00000000, 0x00000000, beh_butterfly
21 | +.word 0x24181FBB, 0xEE640196, 0x11300000, 0x00000000, 0x00000000, beh_hello_world
22 | .word 0x24181FBB, 0xEEC80196, 0x11940000, 0x00000000, 0x00000000, beh_butterfly
23 | .word 0x24181FBB, 0xED9C0196, 0x10040000, 0x00000000, 0x00000000, beh_butterfly
24 | .word 0x24181FBB, 0xE88D01D9, 0xF5C30000, 0x00000000, 0x00000000, beh_butterfly
25 | Only in sm64.split/levels: castle_grounds_level.s.orig
26 | diff -aur sm64.split.orig/sm64.s sm64.split/sm64.s
27 | --- sm64.split.orig/sm64.s
28 | +++ sm64.split/sm64.s
29 | @@ -141124,49 +141124,30 @@
30 | addiu $sp, $sp, 8
31 | # end proc_802C9A3C
32 |
33 | -UnknownRecursive802C9AD8: # begin 802C9AD8 (084AD8)
34 | - addiu $sp, $sp, -0x28
35 | +# hello world behavior function
36 | +BehHelloWorld: # begin 802C9AD8 (084AD8)
37 | + # increase stack and store return address
38 | + addiu $sp, $sp, -0x18
39 | sw $ra, 0x14($sp)
40 | - sw $a0, 0x28($sp)
41 | - lw $t6, 0x28($sp)
42 | - sw $t6, 0x1c($sp)
43 | - lw $t7, 0x28($sp)
44 | - lw $t8, 0x10($t7)
45 | - beqz $t8, .LUnknownRecursive802C9AD8_34
46 | - sw $t8, 0x24($sp)
47 | - jal UnknownRecursive802C9AD8
48 | - lw $a0, 0x24($sp)
49 | - b .LUnknownRecursive802C9AD8_3C
50 | - nop
51 | -.LUnknownRecursive802C9AD8_34: # 802C9B0C
52 | - jal proc_802CA028
53 | - lw $a0, 0x28($sp)
54 | -.LUnknownRecursive802C9AD8_3C: # 802C9B14
55 | - lw $t9, 0x28($sp)
56 | - lw $t1, 0x1c($sp)
57 | - lw $t0, 8($t9)
58 | - bne $t0, $t1, .LUnknownRecursive802C9AD8_78
59 | - sw $t0, 0x20($sp)
60 | -.LUnknownRecursive802C9AD8_50: # 802C9B28
61 | - jal UnknownRecursive802C9AD8
62 | - lw $a0, 0x20($sp)
63 | - lw $t2, 0x20($sp)
64 | - lw $t3, 8($t2)
65 | - sw $t3, 0x28($sp)
66 | - lw $t4, 0x28($sp)
67 | - lw $t6, 0x1c($sp)
68 | - lw $t5, 8($t4)
69 | - beq $t5, $t6, .LUnknownRecursive802C9AD8_50
70 | - sw $t5, 0x20($sp)
71 | -.LUnknownRecursive802C9AD8_78: # 802C9B50
72 | - b .LUnknownRecursive802C9AD8_80
73 | - nop
74 | -.LUnknownRecursive802C9AD8_80: # 802C9B58
75 | +
76 | + la $a2, hello_string # message location, lui/addiu
77 | + li $a0, 0xA0 # X position
78 | + li $a1, 0xA8 # Y position
79 | + jal PrintXY
80 | + nop
81 | +
82 | + # restore return address and jump back
83 | lw $ra, 0x14($sp)
84 | - addiu $sp, $sp, 0x28
85 | + addiu $sp, $sp, 0x18
86 | jr $ra
87 | nop
88 | -# end UnknownRecursive802C9AD8
89 | +# end BehHelloWorld
90 | +
91 | +# placing the string here makes sure it's copied to RAM
92 | +hello_string:
93 | +.string "- Hello World -"
94 | +
95 | +.space 0x50, 0x0 # keep alignment the same
96 |
97 | proc_802C9B68: # begin 802C9B68 (084B68)
98 | addiu $sp, $sp, -0x18
99 |
--------------------------------------------------------------------------------
/examples/hud_toggle/sm64.hudtoggle.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/sm64.s
2 | +++ sm64.split/sm64.s
3 | @@ -69951,11 +69951,11 @@
4 | lw $t6, 0x40($sp)
5 | lui $at, 0x8034
6 | sw $t6, %lo(0x8033CBD0)($at) # $t6, -0x3430($at)
7 | - jal ChangeCameraStatus
8 | + jal HandleToggleHud
9 | lw $a0, 0x40($sp)
10 | lw $t7, 0x40($sp)
11 | lbu $t8, 0x30($t7)
12 | - bnez $t8, .Lproc_802868F8_98
13 | + b .Lproc_802868F8_98 # disable lakitu camera
14 | nop
15 | jal proc_80288624
16 | move $a0, $zero
17 | @@ -72380,73 +72380,37 @@
18 | jr $ra
19 | nop
20 |
21 | -ChangeCameraStatus: # begin 80288E68 (043E68)
22 | - addiu $sp, $sp, -0x20
23 | +HandleToggleHud:
24 | + addiu $sp, $sp, -0x18
25 | sw $ra, 0x14($sp)
26 | - sw $a0, 0x20($sp)
27 | - sh $zero, 0x1e($sp)
28 | - lw $t6, 0x20($sp)
29 | - lbu $t7, 0x30($t6)
30 | - bnez $t7, .LChangeCameraStatus_4C
31 | - nop
32 | - lw $t8, 0x8032d5e4 # lui $t8, 0x8033/lw $t8, -0x2a1c($t8)
33 | - lhu $t9, 0x10($t8)
34 | - andi $t0, $t9, 0x10
35 | - beqz $t0, .LChangeCameraStatus_5C
36 | - nop
37 | - jal proc_80288624
38 | - move $a0, $zero
39 | - addiu $at, $zero, 2
40 | - bne $v0, $at, .LChangeCameraStatus_5C
41 | - nop
42 | -.LChangeCameraStatus_4C: # 80288EB4
43 | - lh $t1, 0x1e($sp)
44 | - ori $t2, $t1, 4
45 | - b .LChangeCameraStatus_8C
46 | - sh $t2, 0x1e($sp)
47 | -.LChangeCameraStatus_5C: # 80288EC4
48 | - jal proc_80288718
49 | - move $a0, $zero
50 | - addiu $at, $zero, 1
51 | - bne $v0, $at, .LChangeCameraStatus_80
52 | - nop
53 | - lh $t3, 0x1e($sp)
54 | - ori $t4, $t3, 1
55 | - b .LChangeCameraStatus_8C
56 | - sh $t4, 0x1e($sp)
57 | -.LChangeCameraStatus_80: # 80288EE8
58 | - lh $t5, 0x1e($sp)
59 | - ori $t6, $t5, 2
60 | - sh $t6, 0x1e($sp)
61 | -.LChangeCameraStatus_8C: # 80288EF4
62 | - lh $t7, 0x8033c848 # lui $t7, 0x8034/lh $t7, -0x37b8($t7)
63 | - andi $t8, $t7, 2
64 | - beqz $t8, .LChangeCameraStatus_AC
65 | - nop
66 | - lh $t9, 0x1e($sp)
67 | - ori $t0, $t9, 8
68 | - sh $t0, 0x1e($sp)
69 | -.LChangeCameraStatus_AC: # 80288F14
70 | - lh $t1, 0x8033c848 # lui $t1, 0x8034/lh $t1, -0x37b8($t1)
71 | - andi $t2, $t1, 0x2000
72 | - beqz $t2, .LChangeCameraStatus_CC
73 | - nop
74 | - lh $t3, 0x1e($sp)
75 | - ori $t4, $t3, 0x10
76 | - sh $t4, 0x1e($sp)
77 | -.LChangeCameraStatus_CC: # 80288F34
78 | - jal SetCameraStatus
79 | - lh $a0, 0x1e($sp)
80 | - b .LChangeCameraStatus_E4
81 | - lh $v0, 0x1e($sp)
82 | - b .LChangeCameraStatus_E4
83 | - nop
84 | -.LChangeCameraStatus_E4: # 80288F4C
85 | + lh $s1, 0x8033AFA0 # lui $s1, 0x8034 / lh $s1, -0x5060($s1)
86 | + lh $t0, 0x8032B1A0 # lui $t0, 0x8034 / lh $t0, -0x4E60($t0)
87 | + andi $s1, $s1, 0x10
88 | + beq $zero, $s1, .L_End # if R no being pressed, skip
89 | + nop
90 | + beq $t0, $s1, .L_PrintTimer # if being toggled on, play sound
91 | + nop
92 | + lui $a0, 0x701A
93 | + la $a1, 0x803331F0 # lui $a1, 0x8033 / addiu $a1, $a1, 0x31F0
94 | + jal SetSound # 8031EB00
95 | + ori $a0, $a0, 0x81
96 | +.L_PrintTimer:
97 | + addiu $a0, $zero, 0x102
98 | + lh $a3, 0x8033B226 # lui $a3, 0x8034 / lh $a3, -0x4DDA($a3)
99 | + beq $zero, $a3, .L_End
100 | + nop
101 | + la $a2, 0x803383A0 # lui $a2, 0x8034 / addiu $a2, $a2, 0x7C60
102 | + jal PrintInt # 802D62D8
103 | + li $a1, 0x20
104 | +.L_End:
105 | + lui $at, 0x8033
106 | + sh $s1, %lo(0x8032B1A0)($at)
107 | lw $ra, 0x14($sp)
108 | - addiu $sp, $sp, 0x20
109 | + addiu $sp, $sp, 0x18
110 | jr $ra
111 | nop
112 | -# end ChangeCameraStatus
113 | +# keep same size
114 | +.space 0x78, 0x00
115 |
116 | proc_80288F5C: # begin 80288F5C (043F5C)
117 | addiu $sp, $sp, -0x98
118 | @@ -168911,10 +168875,9 @@
119 | addiu $sp, $sp, -0x20
120 | sw $ra, 0x14($sp)
121 | lh $t6, 0x8033b26a # lui $t6, 0x8034/lh $t6, -0x4d96($t6)
122 | + bnez $t6, .LRenderHud_40
123 | sh $t6, 0x1e($sp)
124 | - lh $t7, 0x1e($sp)
125 | - bnez $t7, .LRenderHud_40
126 | - nop
127 | +
128 | lui $at, 0x8033
129 | sb $zero, %lo(0x803325F0)($at) # $zero, 0x25f0($at)
130 | addiu $t8, $zero, 8
131 | @@ -168937,6 +168900,9 @@
132 | jal RenderHudCannonReticle
133 | nop
134 | .LRenderHud_74: # 802E3DA0
135 | + lh $t1, 0x8033AFA0 # lui $t1, 0x8034 / lh $t1, -0x5060($t1)
136 | + andi $t1, $t1, 0x10
137 | + beq $t1, $zero, .LRenderHud_BC
138 | lh $t2, 0x1e($sp)
139 | andi $t3, $t2, 1
140 | beqz $t3, .LRenderHud_8C
141 | @@ -168971,7 +168937,7 @@
142 | nop
143 | jal RenderHudHp
144 | nop
145 | - jal ShowCameraStatus
146 | + nop
147 | nop
148 | .LRenderHud_F4: # 802E3E20
149 | lh $t2, 0x1e($sp)
150 | @@ -168981,9 +168947,6 @@
151 | jal RenderHudTimer
152 | nop
153 | .LRenderHud_10C: # 802E3E38
154 | - b .LRenderHud_114
155 | - nop
156 | -.LRenderHud_114: # 802E3E40
157 | lw $ra, 0x14($sp)
158 | addiu $sp, $sp, 0x20
159 | jr $ra
160 |
--------------------------------------------------------------------------------
/examples/skip_screens/skip_lakitu.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/sm64.s
2 | +++ sm64.split/sm64.s
3 | @@ -6115,7 +6115,7 @@
4 | lh $a0, 0x8032ddf4 # lui $a0, 0x8033/lh $a0, -0x220c($a0)
5 | jal proc_80279E44
6 | addiu $a0, $a0, -1
7 | - sltiu $s0, $v0, 1
8 | + li $s0, 0
9 | lui $at, 0x8034
10 | sb $s0, %lo(0x8033B26E)($at) # $s0, -0x4d92($at)
11 | lw $t6, 0x2c($sp)
12 |
--------------------------------------------------------------------------------
/examples/skip_screens/skip_mario.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/levels/game_over_level.s
2 | +++ sm64.split/levels/game_over_level.s
3 | @@ -28,9 +28,9 @@
4 | .word 0x19040002
5 | .word 0x170C0013, __load_behavior_data, __load_behavior_data_end
6 | .word 0x1A0C000A, mario_bg, mario_bg_end
7 | -.word 0x1D040000
8 | -.word 0x1F080100, 0x1400035C
9 | -.word 0x20040000
10 | +
11 | +.word 0x01100014, game_over_level, game_over_level_end, 0x1400020C
12 | +
13 | .word 0x1E040000
14 | .word 0x03040002
15 | .word 0x34040000
16 | @@ -48,9 +48,9 @@
17 | .word 0x19040003
18 | .word 0x170C0013, __load_behavior_data, __load_behavior_data_end
19 | .word 0x1A0C000A, mario_bg, mario_bg_end
20 | -.word 0x1D040000
21 | -.word 0x1F080100, 0x140003B8
22 | -.word 0x20040000
23 | +
24 | +.word 0x01100014, game_over_level, game_over_level_end, 0x1400020C
25 | +
26 | .word 0x1E040000
27 | .word 0x03040002
28 | .word 0x34040000
29 |
--------------------------------------------------------------------------------
/examples/skip_screens/skip_menu.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/levels/game_over_level.s
2 | +++ sm64.split/levels/game_over_level.s
3 | @@ -84,7 +84,7 @@
4 | .word 0x1C040000
5 | .word 0x03040002
6 | .word 0x13040010
7 | -.word 0x01100014, main_menu_level, main_menu_level_end, 0x14000000
8 | +.word 0x01100015, main_level_scripts, main_level_scripts_end, 0x15000000
9 | .word 0x33080110, 0xFFFFFF00
10 | .word 0x03040010
11 | .word 0x1C040000
12 |
--------------------------------------------------------------------------------
/examples/skip_screens/skip_peach.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/sm64.s
2 | +++ sm64.split/sm64.s
3 | @@ -5996,7 +5996,7 @@
4 | lh $a0, 0x8032ddf4 # lui $a0, 0x8033/lh $a0, -0x220c($a0)
5 | jal proc_80279E44
6 | addiu $a0, $a0, -1
7 | - beqz $v0, .Lproc_8024BA8C_170
8 | + nop
9 | nop
10 | lw $a0, 0x8032d93c # lui $a0, 0x8033/lw $a0, -0x26c4($a0)
11 | li $a1, 0x0C400201 # lui $a1, 0xc40/ori $a1, $a1, 0x201
12 |
--------------------------------------------------------------------------------
/examples/skip_screens/skip_title.patch:
--------------------------------------------------------------------------------
1 | --- sm64.split.orig/levels/game_over_level.s
2 | +++ sm64.split/levels/game_over_level.s
3 | @@ -9,9 +9,9 @@
4 | .word 0x16100000, 0x8016F000, 0x0021F4C0, 0x00269EA0
5 | .word 0x170C0013, __load_behavior_data, __load_behavior_data_end
6 | .word 0x180C0007, wood_trademark, wood_trademark_end
7 | -.word 0x1D040000
8 | -.word 0x1F080100, 0x140002D0
9 | -.word 0x20040000
10 | +
11 | +.word 0x01100014, game_over_level, game_over_level_end, 0x14000078
12 | +
13 | .word 0x1E040000
14 | .word 0x29040100
15 | .word 0x11080000, LevelProc_8016F5B0 # 8016F5B0
16 |
--------------------------------------------------------------------------------
/examples/texture_swap/castle_grounds_segment7.0x0EAE8.ia8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/texture_swap/castle_grounds_segment7.0x0EAE8.ia8.png
--------------------------------------------------------------------------------
/examples/texture_swap/castle_grounds_textures.0x01000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/texture_swap/castle_grounds_textures.0x01000.png
--------------------------------------------------------------------------------
/examples/texture_swap/font_graphics.0x122B8.ia8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/texture_swap/font_graphics.0x122B8.ia8.png
--------------------------------------------------------------------------------
/examples/texture_swap/water_skybox.0x00000.skybox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/examples/texture_swap/water_skybox.0x00000.skybox.png
--------------------------------------------------------------------------------
/f3d.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "utils.h"
6 |
7 | #define F3D_VERSION "0.2"
8 |
9 | #define F3D_MOVEMEM 0x03
10 | #define F3D_VTX 0x04
11 | #define F3D_DL 0x06
12 | #define F3D_QUAD 0xB5
13 | #define F3D_CLRGEOMODE 0xB6
14 | #define F3D_SETGEOMODE 0xB7
15 | #define F3D_ENDDL 0xB8
16 | #define F3D_TEXTURE 0xBB
17 | #define F3D_TRI1 0xBF
18 | #define G_SETTILESIZE 0xF2
19 | #define G_LOADBLOCK 0xF3
20 | #define G_SETTILE 0xF5
21 | #define G_SETFOGCOLOR 0xF8
22 | #define G_SETENVCOLOR 0xFB
23 | #define G_SETCOMBINE 0xFC
24 | #define G_SETTIMG 0xFD
25 |
26 | typedef struct
27 | {
28 | char *in_filename;
29 | char *out_filename;
30 | unsigned int offset;
31 | unsigned int length;
32 | } arg_config;
33 |
34 | static arg_config default_config =
35 | {
36 | NULL,
37 | NULL,
38 | 0,
39 | 0
40 | };
41 |
42 | static void get_mode_string(unsigned char *data, char *description)
43 | {
44 | unsigned int val = read_u32_be(&data[4]);
45 | switch (val) {
46 | case 0x00022000: sprintf(description, "vertex RGB, no culling"); break;
47 | case 0x00020000: sprintf(description, "vertex RGB, culling"); break;
48 | case 0x00000000: sprintf(description, "no vertex RGB, culling"); break;
49 | case 0x00002200: sprintf(description, "no vertex RGB, no culling"); break;
50 | default: sprintf(description, "unknown"); break;
51 | }
52 | }
53 |
54 | static void print_f3d(FILE *fout, unsigned char *data)
55 | {
56 | char description[64];
57 | unsigned char offset;
58 | unsigned int address;
59 | unsigned int val;
60 | // default description
61 | description[0] = '\0';
62 | switch (data[0]) {
63 | case F3D_MOVEMEM:
64 | switch (data[1]) {
65 | case 0x86: sprintf(description, "light"); break;
66 | case 0x88: sprintf(description, "dark "); break;
67 | }
68 | address = read_u32_be(&data[4]);
69 | fprintf(fout, "%14s %s %08X", "F3D_MOVEMEM", description, address);
70 | break;
71 | case F3D_VTX:
72 | offset = data[1];
73 | val = read_u16_be(&data[2]);
74 | address = read_u32_be(&data[4]);
75 | fprintf(fout, "%14s %02X %04X (%d) %08X", "F3D_VTX", offset, val, val/0x10, address);
76 | break;
77 | case F3D_DL:
78 | address = read_u32_be(&data[4]);
79 | fprintf(fout, "%14s %08X", "F3D_DL", address);
80 | break;
81 | case F3D_QUAD:
82 | {
83 | unsigned char vertex[6];
84 | vertex[0] = data[1] / 0x0A;
85 | vertex[1] = data[2] / 0x0A;
86 | vertex[2] = data[3] / 0x0A;
87 | // data[6] unused
88 | vertex[3] = data[5] / 0x0A;
89 | vertex[4] = data[6] / 0x0A;
90 | vertex[5] = data[7] / 0x0A;
91 | fprintf(fout, "%14s %3d %3d %3d %3d %3d %3d", "F3D_QUAD",
92 | vertex[0], vertex[1], vertex[2],
93 | vertex[3], vertex[4], vertex[5]);
94 | break;
95 | }
96 | case F3D_CLRGEOMODE:
97 | get_mode_string(data, description);
98 | fprintf(fout, "%14s %s", "F3D_CLRGEOMODE", description);
99 | break;
100 | case F3D_SETGEOMODE:
101 | get_mode_string(data, description);
102 | fprintf(fout, "%14s %s", "F3D_SETGEOMODE", description);
103 | break;
104 | case F3D_ENDDL:
105 | fprintf(fout, "%14s %s", "F3D_ENDL", description);
106 | break;
107 | case F3D_TEXTURE:
108 | switch (data[3]) {
109 | case 0x00:
110 | val = read_u32_be(&data[4]);
111 | if (val == 0xFFFFFFFF) {
112 | sprintf(description, "end, reset scale to 0");
113 | }
114 | break;
115 | case 0x01:
116 | val = read_u32_be(&data[4]);
117 | if (val == 0xFFFFFFFF) {
118 | sprintf(description, "start, set scale to 1");
119 | } else if (val == 0x0F8007C0) {
120 | sprintf(description, "start environment mapping");
121 | }
122 | break;
123 | }
124 | fprintf(fout, "%14s %s", "F3D_TEXTURE", description);
125 | break;
126 | case F3D_TRI1:
127 | {
128 | unsigned char vertex[3];
129 | vertex[0] = data[5] / 0x0A;
130 | vertex[1] = data[6] / 0x0A;
131 | vertex[2] = data[7] / 0x0A;
132 | fprintf(fout, "%14s %3d %3d %3d", "F3D_TRI1", vertex[0], vertex[1], vertex[2]);
133 | break;
134 | }
135 | case G_SETTILESIZE:
136 | {
137 | unsigned short width, height;
138 | width = (((data[5] << 8) | (data[6] & 0xF0)) >> 6) + 1;
139 | height = (((data[6] & 0x0F) << 8 | data[7]) >> 2) + 1;
140 | fprintf(fout, "%14s %2d %2d", "G_SETTILESIZE", width, height);
141 | break;
142 | }
143 | case G_LOADBLOCK:
144 | {
145 | unsigned w0 = read_u32_be(data);
146 | unsigned w1 = read_u32_be(&data[4]);
147 | unsigned uls = (w0 >> 12) & 0x3FF;
148 | unsigned ult = w0 & 0x3FF;
149 | unsigned lrs = (w1 >> 12) & 0x3FF;
150 | unsigned dxt = w1 & 0x3FF;
151 | fprintf(fout, "%14s %03X %03X %03X %u", "G_LOADBLOCK", uls, ult, lrs, dxt);
152 | break;
153 | }
154 | case G_SETTILE:
155 | {
156 | const char * fmt_table[] =
157 | {
158 | "RGBA", "YUV", "CI", "IA", "I"
159 | };
160 | unsigned format = (data[1] >> 5) & 0x7; // bits 21-23
161 | unsigned size = (data[1] >> 3) & 0x3; // bits 19-20
162 | unsigned depth = 0;
163 | switch (size) {
164 | case 0: depth = 4; break;
165 | case 1: depth = 8; break;
166 | case 2: depth = 16; break;
167 | case 3: depth = 32; break;
168 | default: ERROR("Unknown depth: %d\n", size);
169 | }
170 | if (format < DIM(fmt_table)) {
171 | sprintf(description, "%s %d", fmt_table[format], depth);
172 | }
173 | fprintf(fout, "%14s %s", "G_SETTILE", description);
174 | break;
175 | }
176 | case G_SETFOGCOLOR:
177 | fprintf(fout, "%14s %3d, %3d, %3d, %3d", "G_SETFOGCOLOR", data[4], data[5], data[6], data[7]);
178 | break;
179 | case G_SETENVCOLOR:
180 | fprintf(fout, "%14s %3d, %3d, %3d, %3d", "G_SETENVCOLOR", data[4], data[5], data[6], data[7]);
181 | break;
182 | case G_SETCOMBINE:
183 | {
184 | struct {unsigned char data[7]; char *description;} table[] =
185 | {
186 | {{0x12, 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0x38}, "solid RGBA"},
187 | {{0x12, 0x18, 0x24, 0xFF, 0x33, 0xFF, 0xFF}, "alpha RGBA"},
188 | };
189 | unsigned i;
190 | for (i = 0; i < DIM(table); i++) {
191 | if (!memcmp(table[i].data, &data[1], 7)) {
192 | strcpy(description, table[i].description);
193 | }
194 | }
195 | fprintf(fout, "%14s %s", "G_SETCOMBINE", description);
196 | break;
197 | }
198 | case G_SETTIMG:
199 | address = read_u32_be(&data[4]);
200 | fprintf(fout, "%14s %08X", "G_SETTIMG", address);
201 | break;
202 | default:
203 | fprintf(fout, "%14s %s", "Unknown", description);
204 | break;
205 | }
206 | }
207 |
208 | static void print_usage(void)
209 | {
210 | ERROR("Usage: f3d [-l LENGTH] [-o OFFSET] FILE\n"
211 | "\n"
212 | "f3d v" F3D_VERSION ": N64 Fast3D display list decoder\n"
213 | "\n"
214 | "Optional arguments:\n"
215 | " -l LENGTH length of data to decode in bytes (default: length of file)\n"
216 | " -o OFFSET starting offset in FILE (default: 0)\n"
217 | "\n"
218 | "File arguments:\n"
219 | " FILE input file\n"
220 | " [OUTPUT] output file (default: stdout)\n");
221 | exit(1);
222 | }
223 |
224 | // parse command line arguments
225 | static void parse_arguments(int argc, char *argv[], arg_config *config)
226 | {
227 | int i;
228 | int file_count = 0;
229 | if (argc < 2) {
230 | print_usage();
231 | exit(1);
232 | }
233 | for (i = 1; i < argc; i++) {
234 | if (argv[i][0] == '-') {
235 | switch (argv[i][1]) {
236 | case 'l':
237 | if (++i >= argc) {
238 | print_usage();
239 | }
240 | config->length = strtoul(argv[i], NULL, 0);
241 | break;
242 | case 'o':
243 | if (++i >= argc) {
244 | print_usage();
245 | }
246 | config->offset = strtoul(argv[i], NULL, 0);
247 | break;
248 | default:
249 | print_usage();
250 | break;
251 | }
252 | } else {
253 | switch (file_count) {
254 | case 0:
255 | config->in_filename = argv[i];
256 | break;
257 | case 1:
258 | config->out_filename = argv[i];
259 | break;
260 | default: // too many
261 | print_usage();
262 | break;
263 | }
264 | file_count++;
265 | }
266 | }
267 | if (file_count < 1) {
268 | print_usage();
269 | }
270 | }
271 |
272 | int main(int argc, char *argv[])
273 | {
274 | arg_config config;
275 | FILE *fout;
276 | unsigned char *data;
277 | long size;
278 | unsigned int i;
279 | int stop_on_enddl = 0;
280 |
281 | // get configuration from arguments
282 | config = default_config;
283 | parse_arguments(argc, argv, &config);
284 | if (config.out_filename == NULL) {
285 | fout = stdout;
286 | } else {
287 | fout = fopen(config.out_filename, "w");
288 | if (fout == NULL) {
289 | perror("Error opening output file");
290 | return EXIT_FAILURE;
291 | }
292 | }
293 |
294 | // operation
295 | size = read_file(config.in_filename, &data);
296 | if (size < 0) {
297 | perror("Error opening input file");
298 | return EXIT_FAILURE;
299 | }
300 | if (config.length == 0) {
301 | config.length = size - config.offset;
302 | stop_on_enddl = 1;
303 | }
304 | if (config.offset >= (unsigned int)size) {
305 | ERROR("Error: offset greater than file size (%X > %X)\n",
306 | config.offset, (unsigned int)size);
307 | return EXIT_FAILURE;
308 | }
309 | if (config.offset + config.length > (unsigned int)size) {
310 | ERROR("Warning: length goes beyond file size (%X > %X), truncating\n",
311 | config.offset + config.length, (unsigned int)size);
312 | config.length = size - config.offset;
313 | }
314 |
315 | for (i = config.offset; i < config.offset + config.length; i += 8) {
316 | fprintf(fout, "%05X: %08X %08X", i, read_u32_be(&data[i]), read_u32_be(&data[i+4]));
317 | print_f3d(fout, &data[i]);
318 | fprintf(fout, "\n");
319 | if (stop_on_enddl && F3D_ENDDL == data[i]) {
320 | break;
321 | }
322 | }
323 |
324 | free(data);
325 | if (fout != stdout) {
326 | fclose(fout);
327 | }
328 |
329 | return 0;
330 | }
331 |
--------------------------------------------------------------------------------
/libblast.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBBLAST_H_
2 | #define LIBBLAST_H_
3 |
4 | // 802A5E10 (061650)
5 | // just a memcpy from a0 to a3
6 | int decode_block0(unsigned char *in, int length, unsigned char *out);
7 |
8 | // 802A5AE0 (061320)
9 | int decode_block1(unsigned char *in, int length, unsigned char *out);
10 |
11 | // 802A5B90 (0613D0)
12 | int decode_block2(unsigned char *in, int length, unsigned char *out);
13 |
14 | // 802A5A2C (06126C)
15 | int decode_block3(unsigned char *in, int length, unsigned char *out);
16 |
17 | // 802A5C5C (06149C)
18 | int decode_block4(unsigned char *in, int length, unsigned char *out, unsigned char *lut);
19 |
20 | // 802A5D34 (061574)
21 | int decode_block5(unsigned char *in, int length, unsigned char *out, unsigned char *lut);
22 |
23 | // 802A5958 (061198)
24 | int decode_block6(unsigned char *in, int length, unsigned char *out);
25 |
26 | // decode Blast Corps compressed data of given type
27 | // in_filename - input file name of compressed data
28 | // type - type of compression: 0-6
29 | // out_filename - output file name of uncompressed data
30 | // lut - lookup table to use for types 4 and 5
31 | // returns 0 on success, non-0 otherwise
32 | int blast_decode_file(char *in_filename, int type, char *out_filename, unsigned char *lut);
33 |
34 | #endif // LIBBLAST_H_
35 |
--------------------------------------------------------------------------------
/libmio0.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBMIO0_H_
2 | #define LIBMIO0_H_
3 |
4 | // defines
5 |
6 | #define MIO0_HEADER_LENGTH 16
7 |
8 | // typedefs
9 |
10 | typedef struct
11 | {
12 | unsigned int dest_size;
13 | unsigned int comp_offset;
14 | unsigned int uncomp_offset;
15 | } mio0_header_t;
16 |
17 | // function prototypes
18 |
19 | // decode MIO0 header
20 | // returns 1 if valid header, 0 otherwise
21 | int mio0_decode_header(const unsigned char *buf, mio0_header_t *head);
22 |
23 | // encode MIO0 header from struct
24 | void mio0_encode_header(unsigned char *buf, const mio0_header_t *head);
25 |
26 | // decode MIO0 data in memory
27 | // in: buffer containing MIO0 data
28 | // out: buffer for output data
29 | // end: output offset of the last byte decoded from in (set to NULL if unwanted)
30 | // returns bytes extracted to 'out' or negative value on failure
31 | int mio0_decode(const unsigned char *in, unsigned char *out, unsigned int *end);
32 |
33 | // encode MIO0 data in memory
34 | // in: buffer containing raw data
35 | // out: buffer for MIO0 data
36 | // returns size of compressed data in 'out' including MIO0 header
37 | int mio0_encode(const unsigned char *in, unsigned int length, unsigned char *out);
38 |
39 | // decode an entire MIO0 block at an offset from file to output file
40 | // in_file: input filename
41 | // offset: offset to start decoding from in_file
42 | // out_file: output filename
43 | int mio0_decode_file(const char *in_file, unsigned long offset, const char *out_file);
44 |
45 | // encode an entire file
46 | // in_file: input filename containing raw data to be encoded
47 | // out_file: output filename to write MIO0 compressed data to
48 | int mio0_encode_file(const char *in_file, const char *out_file);
49 |
50 | #endif // LIBMIO0_H_
51 |
--------------------------------------------------------------------------------
/libsfx.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBSFX_H_
2 | #define LIBSFX_H_
3 |
4 | // defines
5 |
6 | // typedefs
7 |
8 | typedef struct {
9 | unsigned int order;
10 | unsigned int predictor_count;
11 | unsigned *data;
12 | } predictor_data;
13 |
14 | typedef struct {
15 | unsigned int start;
16 | unsigned int end;
17 | unsigned int count;
18 | unsigned int unknown;
19 | unsigned *state;
20 | } loop_data;
21 |
22 | typedef struct {
23 | unsigned int unknown_1;
24 | unsigned int sound_offset;
25 | loop_data *loop;
26 | predictor_data *predictor;
27 | unsigned int sound_length;
28 | unsigned int unknown_2;
29 | unsigned int unknown_3;
30 | unsigned int unknown_4;
31 | } wave_table;
32 |
33 | typedef struct {
34 | unsigned char unknown_1;
35 | unsigned char pan;
36 | unsigned unknown_2;
37 | wave_table *wav;
38 | float key_base;
39 | unsigned *adrs;
40 | } percussion;
41 |
42 | typedef struct {
43 | percussion *items;
44 | } percussion_table;
45 |
46 | typedef struct {
47 | unsigned int unknown;
48 | unsigned *adrs;
49 | wave_table *wav_prev;
50 | float key_base_prev;
51 | wave_table *wav;
52 | float key_base;
53 | wave_table *wav_sec;
54 | float key_base_sec;
55 | } sound;
56 |
57 | typedef struct {
58 | unsigned int instrument_count;
59 | unsigned int percussion_count;
60 | unsigned int unknown_1;
61 | unsigned int unknown_2;
62 | percussion_table percussions;
63 | sound *sounds;
64 | } sound_bank;
65 |
66 | typedef struct {
67 | unsigned unknown;
68 | unsigned bank_count;
69 | sound_bank *banks;
70 | } sound_bank_header;
71 |
72 | typedef struct {
73 | unsigned unknown;
74 | unsigned data_count;
75 | unsigned char **data;
76 | } sound_data_header;
77 |
78 | // function prototypes
79 |
80 | //NEEDS COMMENTS!!!
81 |
82 | // initialize the key table for vadpcm decoding
83 | void sfx_initialize_key_table();
84 |
85 | // read the sound bank table
86 | // data: buffer containing sound bank data
87 | // data_offset: offset in data where the sound bank begins
88 | // returns a sound_data_header which contains info about all the sounds stored in the rom
89 | sound_bank_header read_sound_bank(unsigned char *data, unsigned int data_offset);
90 |
91 | // read the sound data table
92 | // data: buffer containing sound data
93 | // data_offset: offset in data where the sound data begins
94 | // returns a sound_data_header which contains the raw, encoded sound data
95 | sound_data_header read_sound_data(unsigned char *data, unsigned int data_offset);
96 |
97 | // create a .wav file from provided encoded sound data
98 | // sound_dir: directory to store the .wav file in
99 | // wav_name: name for the new .wav file
100 | // wav: the sound information that's stored in the sound_bank_header
101 | // key_base: not entirely sure what this is, but it's converted & stored in the new .wav file
102 | // snd_data: buffer containing the raw, encoded sound data
103 | // sampling_rate: sample rate for the sound data (higher sampling rate = wav file speeds up)
104 | // returns 1 if the .wav file was created, 0 if not
105 | int extract_raw_sound(char *sound_dir, char *wav_name, wave_table *wav, float key_base, unsigned char *snd_data, unsigned long sampling_rate);
106 |
107 | #endif // LIBMIO0_H_
108 |
--------------------------------------------------------------------------------
/libsm64.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBSM64_H_
2 | #define LIBSM64_H_
3 |
4 | #define MIO0_DIR "mio0files"
5 |
6 | // typedefs
7 | typedef enum
8 | {
9 | ROM_INVALID, // not valid SM64 ROM
10 | ROM_SM64_BS, // SM64 byte-swapped (BADC)
11 | ROM_SM64_BE, // SM64 big-endian (ABCD)
12 | ROM_SM64_LE, // SM64 little-endian
13 | ROM_SM64_BE_EXT, // SM64 big-endian, extended
14 | } rom_type;
15 |
16 | typedef enum
17 | {
18 | VERSION_UNKNOWN,
19 | VERSION_SM64_U,
20 | VERSION_SM64_E,
21 | VERSION_SM64_J,
22 | VERSION_SM64_SHINDOU,
23 | VERSION_SM64_IQUE,
24 | } rom_version;
25 |
26 | typedef struct
27 | {
28 | char *in_filename;
29 | char *ext_filename;
30 | unsigned int ext_size;
31 | unsigned int padding;
32 | unsigned int alignment;
33 | char fill;
34 | char dump;
35 | } sm64_config;
36 |
37 | // determine ROM type based on data
38 | // buf: buffer containing raw SM64 ROM file data
39 | // length: length of 'buf'
40 | // returns SM64 ROM type or invalid
41 | rom_type sm64_rom_type(unsigned char *buf, unsigned int length);
42 |
43 | // determine SM64 ROM type based on cksum data
44 | // buf: buffer containing raw SM64 ROM file data
45 | // returns SM64 ROM version or unknown
46 | rom_version sm64_rom_version(unsigned char *buf);
47 |
48 | // find and decompress all MIO0 blocks
49 | // config: configuration to determine alignment, padding and size
50 | // in_buf: buffer containing entire contents of SM64 data in big endian
51 | // length: length of in_buf
52 | // out_buf: buffer containing extended SM64
53 | void sm64_decompress_mio0(const sm64_config *config,
54 | unsigned char *in_buf,
55 | unsigned int in_length,
56 | unsigned char *out_buf);
57 |
58 | // update N64 header checksums
59 | // buf: buffer containing ROM data
60 | // checksums are written into the buffer
61 | void sm64_update_checksums(unsigned char *buf);
62 |
63 | #endif // LIBSM64_H_
64 |
--------------------------------------------------------------------------------
/mipsdisasm.h:
--------------------------------------------------------------------------------
1 | #ifndef MIPSDISASM_H_
2 | #define MIPSDISASM_H_
3 |
4 | // typedefs
5 | typedef struct _disasm_state disasm_state;
6 |
7 | typedef enum
8 | {
9 | ASM_GAS, // GNU as
10 | ASM_ARMIPS, // armips
11 | } asm_syntax;
12 |
13 | // allocate and initialize disassembler state to be passed into disassembler routines
14 | // syntax: assembler syntax to use
15 | // merge_pseudo: if true, attempt to link pseudo instructions
16 | // returns disassembler state
17 | disasm_state *disasm_state_init(asm_syntax syntax, int merge_pseudo);
18 |
19 | // free disassembler state allocated during pass1
20 | // state: disassembler state returned from disasm_state_alloc() or mipsdisasm_pass1()
21 | void disasm_state_free(disasm_state *state);
22 |
23 | // add a label to the disassembler state
24 | // state: disassembler state returned from disasm_state_alloc() or mipsdisasm_pass1()
25 | // name: string name of label (if NULL, generated based on vaddr)
26 | // vaddr: virtual address of label
27 | void disasm_label_add(disasm_state *state, const char *name, unsigned int vaddr);
28 |
29 | // lookup a global label from the disassembler state
30 | // state: disassembler state returned from disasm_state_alloc() or mipsdisasm_pass1()
31 | // vaddr: virtual address of label
32 | // name: string to write label to
33 | // returns 1 if found, 0 otherwise
34 | int disasm_label_lookup(const disasm_state *state, unsigned int vaddr, char *name);
35 |
36 | // first pass of disassembler - collects procedures called and sorts them
37 | // data: buffer containing raw MIPS assembly
38 | // offset: buffer offset to start at
39 | // length: length to disassemble starting at 'offset'
40 | // vaddr: virtual address of first byte
41 | // syntax: assembler syntax to use
42 | // state: disassembler state. if NULL, is allocated, returned at end
43 | void mipsdisasm_pass1(unsigned char *data, unsigned int offset, unsigned int length, unsigned int vaddr, disasm_state *state);
44 |
45 | // disassemble a region of code, output to file stream
46 | // out: stream to output data to
47 | // state: disassembler state from pass1
48 | // offset: starting offset to match in disassembler state
49 | void mipsdisasm_pass2(FILE *out, disasm_state *state, unsigned int offset);
50 |
51 | // get version string of raw disassembler
52 | const char *disasm_get_version(void);
53 |
54 | #endif // MIPSDISASM_H_
55 |
--------------------------------------------------------------------------------
/n64cksum.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "libsm64.h"
5 | #include "utils.h"
6 |
7 | #define N64CKSUM_VERSION "0.1"
8 |
9 | static void print_usage(void)
10 | {
11 | ERROR("Usage: n64cksum ROM [ROM_OUT]\n"
12 | "\n"
13 | "n64cksum v" N64CKSUM_VERSION ": N64 ROM checksum calculator\n"
14 | "\n"
15 | "File arguments:\n"
16 | " ROM input ROM file\n"
17 | " ROM_OUT output ROM file (default: overwrites input ROM)\n");
18 | }
19 |
20 | int main(int argc, char *argv[])
21 | {
22 | unsigned char *rom_data;
23 | char *file_in;
24 | char *file_out;
25 | long length;
26 | long write_length;
27 | if (argc < 2) {
28 | print_usage();
29 | return EXIT_FAILURE;
30 | }
31 |
32 | file_in = argv[1];
33 | if (argc > 2) {
34 | file_out = argv[2];
35 | } else {
36 | file_out = argv[1];
37 | }
38 |
39 | length = read_file(file_in, &rom_data);
40 | if (length < 0) {
41 | ERROR("Error reading input file \"%s\"\n", file_in);
42 | return EXIT_FAILURE;
43 | }
44 |
45 | sm64_update_checksums(rom_data);
46 |
47 | write_length = write_file(file_out, rom_data, length);
48 |
49 | free(rom_data);
50 |
51 | if (write_length != length) {
52 | ERROR("Error writing to output file \"%s\"\n", file_out);
53 | return EXIT_FAILURE;
54 | }
55 |
56 | return EXIT_SUCCESS;
57 | }
58 |
--------------------------------------------------------------------------------
/n64graphics.h:
--------------------------------------------------------------------------------
1 | #ifndef N64GRAPHICS_H_
2 | #define N64GRAPHICS_H_
3 |
4 | #include
5 |
6 | // intermediate formats
7 | typedef struct _rgba
8 | {
9 | uint8_t red;
10 | uint8_t green;
11 | uint8_t blue;
12 | uint8_t alpha;
13 | } rgba;
14 |
15 | typedef struct _ia
16 | {
17 | uint8_t intensity;
18 | uint8_t alpha;
19 | } ia;
20 |
21 | // CI palette
22 | typedef struct
23 | {
24 | uint16_t data[256];
25 | int max; // max number of entries
26 | int used; // number of entries used
27 | } palette_t;
28 |
29 | //---------------------------------------------------------
30 | // N64 RGBA/IA/I/CI -> intermediate RGBA/IA
31 | //---------------------------------------------------------
32 |
33 | // N64 raw RGBA16/RGBA32 -> intermediate RGBA
34 | rgba *raw2rgba(const uint8_t *raw, int width, int height, int depth);
35 |
36 | // N64 raw IA1/IA4/IA8/IA16 -> intermediate IA
37 | ia *raw2ia(const uint8_t *raw, int width, int height, int depth);
38 |
39 | // N64 raw I4/I8 -> intermediate IA
40 | ia *raw2i(const uint8_t *raw, int width, int height, int depth);
41 |
42 | //---------------------------------------------------------
43 | // intermediate RGBA/IA -> N64 RGBA/IA/I/CI
44 | // returns length written to 'raw' used or -1 on error
45 | //---------------------------------------------------------
46 |
47 | // intermediate RGBA -> N64 raw RGBA16/RGBA32
48 | int rgba2raw(uint8_t *raw, const rgba *img, int width, int height, int depth);
49 |
50 | // intermediate IA -> N64 raw IA1/IA4/IA8/IA16
51 | int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
52 |
53 | // intermediate IA -> N64 raw I4/I8
54 | int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
55 |
56 |
57 | //---------------------------------------------------------
58 | // N64 CI <-> N64 RGBA16/IA16
59 | //---------------------------------------------------------
60 |
61 | // N64 CI raw data and palette to raw data (either RGBA16 or IA16)
62 | uint8_t *ci2raw(const uint8_t *rawci, const uint8_t *palette, int width, int height, int ci_depth);
63 |
64 | // convert from raw (RGBA16 or IA16) format to CI + palette
65 | int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int ci_depth);
66 |
67 |
68 | //---------------------------------------------------------
69 | // intermediate RGBA/IA -> PNG
70 | //---------------------------------------------------------
71 |
72 | // intermediate RGBA write to PNG file
73 | int rgba2png(const char *png_filename, const rgba *img, int width, int height);
74 |
75 | // intermediate IA write to grayscale PNG file
76 | int ia2png(const char *png_filename, const ia *img, int width, int height);
77 |
78 |
79 | //---------------------------------------------------------
80 | // PNG -> intermediate RGBA/IA
81 | //---------------------------------------------------------
82 |
83 | // PNG file -> intermediate RGBA
84 | rgba *png2rgba(const char *png_filename, int *width, int *height);
85 |
86 | // PNG file -> intermediate IA
87 | ia *png2ia(const char *png_filename, int *width, int *height);
88 |
89 |
90 | //---------------------------------------------------------
91 | // version
92 | //---------------------------------------------------------
93 |
94 | // get version of underlying graphics reading library
95 | const char *n64graphics_get_read_version(void);
96 |
97 | // get version of underlying graphics writing library
98 | const char *n64graphics_get_write_version(void);
99 |
100 | #endif // N64GRAPHICS_H_
101 |
--------------------------------------------------------------------------------
/n64split.collision.mtl.h:
--------------------------------------------------------------------------------
1 | static const char collision_mtl_data[] =
2 | "# collision model materials\n"
3 | "#\n"
4 | "# Ka: ambient reflectivity\n"
5 | "# Kd: diffuse reflectivity\n"
6 | "# illum: illuminaiton model\n"
7 | "# * 1: Color on and Ambient on\n"
8 | "# * 2: Highlight on\n"
9 | "# * 3: Reflection on and Ray trace on\n"
10 | "# * 4: Transparency: Glass on\n"
11 | "# Reflection: Ray trace on\n"
12 | "# * 5: Reflection: Fresnel on and Ray trace on\n"
13 | "# * 6: Transparency: Refraction on\n"
14 | "# Reflection: Fresnel off and Ray trace on\n"
15 | "# * 7: Transparency: Refraction on\n"
16 | "# Reflection: Fresnel on and Ray trace on\n"
17 | "# * 8: Reflection on and Ray trace off\n"
18 | "# * 9: Transparency: Glass on\n"
19 | "# Reflection: Ray trace off\n"
20 | "# * 10: Casts shadows onto invisible surfaces\n"
21 | "\n"
22 | "newmtl 0D\n"
23 | "Ka 1 0.6 0.78\n"
24 | "Kd 1 0.6 0.78\n"
25 | "illum 1\n"
26 | "\n"
27 | "newmtl climbable\n"
28 | "Ka 0.75 0.5 0\n"
29 | "Kd 0.75 0.5 0\n"
30 | "illum 1\n"
31 | "\n"
32 | "newmtl deathfloor\n"
33 | "Ka 0 0 0\n"
34 | "Kd 0 0 0\n"
35 | "illum 1\n"
36 | "\n"
37 | "newmtl fence\n"
38 | "Ka 0.2 0.2 0.2\n"
39 | "Kd 0.2 0.2 0.2\n"
40 | "illum 1\n"
41 | "\n"
42 | "newmtl flat\n"
43 | "Ka 0 0.5 0.5\n"
44 | "Kd 0 0.5 0.5\n"
45 | "illum 1\n"
46 | "\n"
47 | "newmtl grass\n"
48 | "Ka 0 0.9 0\n"
49 | "Kd 0 0.9 0\n"
50 | "illum 1\n"
51 | "\n"
52 | "newmtl hang\n"
53 | "Ka 0.9 0 0\n"
54 | "Kd 0.9 0 0\n"
55 | "illum 1\n"
56 | "\n"
57 | "newmtl icy\n"
58 | "Ka 0.2 0.2 0.9\n"
59 | "Kd 0.2 0.2 0.9\n"
60 | "illum 1\n"
61 | "\n"
62 | "newmtl lethal_lava\n"
63 | "Ka 1 0 0\n"
64 | "Kd 1 0 0\n"
65 | "illum 1\n"
66 | "\n"
67 | "newmtl normal\n"
68 | "Ka 0.98 0.98 0\n"
69 | "Kd 0.98 0.98 0\n"
70 | "illum 1\n"
71 | "\n"
72 | "newmtl pool_warp\n"
73 | "Ka 0.1 0.1 0.1\n"
74 | "Kd 0.1 0.1 0.1\n"
75 | "illum 1\n"
76 | "\n"
77 | "newmtl slippery\n"
78 | "Ka 0.1 0.1 1.0\n"
79 | "Kd 0.1 0.1 1.0\n"
80 | "illum 1\n"
81 | "\n"
82 | "newmtl snowy\n"
83 | "Ka 0.9 0.9 0.9\n"
84 | "Kd 0.9 0.9 0.9\n"
85 | "illum 1\n"
86 | "\n"
87 | "newmtl snowy2\n"
88 | "Ka 1 1 1\n"
89 | "Kd 1 1 1\n"
90 | "illum 1\n"
91 | "\n"
92 | "newmtl unclimbable\n"
93 | "Ka 1.0 1.0 1.0\n"
94 | "Kd 1.0 1.0 1.0\n"
95 | "illum 1\n"
96 | "\n"
97 | "newmtl very_slippery\n"
98 | "Ka 0 0 1.0\n"
99 | "Kd 0 0 1.0\n"
100 | "illum 1\n"
101 | "\n"
102 | "newmtl wall\n"
103 | "Ka 0.5 0.5 0.5\n"
104 | "Kd 0.5 0.5 0.5\n"
105 | "illum 1\n"
106 | "\n"
107 | "newmtl water_currents\n"
108 | "Ka 0.5 0.5 1.0\n"
109 | "Kd 0.5 0.5 1.0\n"
110 | "illum 1\n"
111 | "\n"
112 | ;
113 |
--------------------------------------------------------------------------------
/n64split.makefile.h:
--------------------------------------------------------------------------------
1 | static const char makefile_data[] =
2 | "# Makefile to rebuild SM64 split image\n"
3 | "\n"
4 | "################ Target Executable and Sources ###############\n"
5 | "\n"
6 | "# BUILD_DIR is location where all build artifacts are placed\n"
7 | "BUILD_DIR = build\n"
8 | "\n"
9 | "##################### Compiler Options #######################\n"
10 | "CROSS = mips64-elf-\n"
11 | "AS = $(CROSS)as\n"
12 | "CC = $(CROSS)gcc\n"
13 | "LD = $(CROSS)ld\n"
14 | "OBJDUMP = $(CROSS)objdump\n"
15 | "OBJCOPY = $(CROSS)objcopy\n"
16 | "\n"
17 | "ASFLAGS = -mtune=vr4300 -march=vr4300\n"
18 | "CFLAGS = -Wall -O2 -mtune=vr4300 -march=vr4300 -G 0 -c\n"
19 | "LDFLAGS = -T $(LD_SCRIPT) -Map $(BUILD_DIR)/sm64.map\n"
20 | "\n"
21 | "####################### Other Tools #########################\n"
22 | "\n"
23 | "# N64 tools\n"
24 | "TOOLS_DIR = ../tools\n"
25 | "MIO0TOOL = $(TOOLS_DIR)/mio0\n"
26 | "N64CKSUM = $(TOOLS_DIR)/n64cksum\n"
27 | "N64GRAPHICS = $(TOOLS_DIR)/n64graphics\n"
28 | "EMULATOR = mupen64plus\n"
29 | "EMU_FLAGS = --noosd\n"
30 | "LOADER = loader64\n"
31 | "LOADER_FLAGS = -vwf\n"
32 | "\n"
33 | "FixPath = $(subst /,\\,$1)\n"
34 | "\n"
35 | "######################## Targets #############################\n"
36 | "\n"
37 | "default: all\n"
38 | "\n"
39 | "# file dependencies generated by splitter\n"
40 | "MAKEFILE_SPLIT = Makefile.split\n"
41 | "include $(MAKEFILE_SPLIT)\n"
42 | "\n"
43 | "all: $(TARGET).z64\n"
44 | "\n"
45 | "clean:\n"
46 | "\tdel /Q $(call FixPath,$(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).o $(BUILD_DIR)/$(TARGET).bin $(BUILD_DIR)/$(TARGET).map $(TARGET).z64)\n"
47 | "\n"
48 | "$(MIO0_DIR)/%%.mio0: $(MIO0_DIR)/%%.bin\n"
49 | "\t$(MIO0TOOL) $< $@\n"
50 | "\n"
51 | "$(BUILD_DIR):\n"
52 | "\tmkdir $(BUILD_DIR)\n"
53 | "\n"
54 | "$(BUILD_DIR)/$(TARGET).o: $(TARGET).s Makefile $(MAKEFILE_SPLIT) $(MIO0_FILES) $(LEVEL_FILES) $(MUSIC_FILES) | $(BUILD_DIR)\n"
55 | "\t$(AS) $(ASFLAGS) -o $@ $<\n"
56 | "\n"
57 | "$(BUILD_DIR)/%%.o: %%.c Makefile.as | $(BUILD_DIR)\n"
58 | "\t$(CC) $(CFLAGS) -o $@ $<\n"
59 | "\n"
60 | "$(BUILD_DIR)/$(TARGET).elf: $(BUILD_DIR)/$(TARGET).o $(LD_SCRIPT)\n"
61 | "\t$(LD) $(LDFLAGS) -o $@ $< $(LIBS)\n"
62 | "\n"
63 | "$(BUILD_DIR)/$(TARGET).bin: $(BUILD_DIR)/$(TARGET).elf\n"
64 | "\t$(OBJCOPY) $< $@ -O binary\n"
65 | "\n"
66 | "# final z64 updates checksum\n"
67 | "$(TARGET).z64: $(BUILD_DIR)/$(TARGET).bin\n"
68 | "\t$(N64CKSUM) $< $@\n"
69 | "\n"
70 | "$(BUILD_DIR)/$(TARGET).hex: $(TARGET).z64\n"
71 | "\txxd $< > $@\n"
72 | "\n"
73 | "$(BUILD_DIR)/$(TARGET).objdump: $(BUILD_DIR)/$(TARGET).elf\n"
74 | "\t$(OBJDUMP) -D $< > $@\n"
75 | "\n"
76 | "test: $(TARGET).z64\n"
77 | "\t$(EMULATOR) $(EMU_FLAGS) $<\n"
78 | "\n"
79 | "load: $(TARGET).z64\n"
80 | "\t$(LOADER) $(LOADER_FLAGS) $<\n"
81 | "\n"
82 | ".PHONY: all clean default diff test\n"
83 | ;
84 |
--------------------------------------------------------------------------------
/release/licenses/capstone.LICENSE:
--------------------------------------------------------------------------------
1 | This is the software license for Capstone disassembly framework.
2 | Capstone has been designed & implemented by Nguyen Anh Quynh
3 |
4 | See http://www.capstone-engine.org for further information.
5 |
6 | Copyright (c) 2013, COSEINC.
7 | All rights reserved.
8 |
9 | Redistribution and use in source and binary forms, with or without
10 | modification, are permitted provided that the following conditions are met:
11 |
12 | * Redistributions of source code must retain the above copyright notice,
13 | this list of conditions and the following disclaimer.
14 | * Redistributions in binary form must reproduce the above copyright notice,
15 | this list of conditions and the following disclaimer in the documentation
16 | and/or other materials provided with the distribution.
17 | * Neither the name of the developer(s) nor the names of its
18 | contributors may be used to endorse or promote products derived from this
19 | software without specific prior written permission.
20 |
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 | POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/release/licenses/libyaml.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2006 Kirill Simonov
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/release/licenses/n64split.LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Q
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/release/n64split.README.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/release/n64split.README.txt
--------------------------------------------------------------------------------
/release/sm64extend.README.txt:
--------------------------------------------------------------------------------
1 | ## sm64extend: Super Mario 64 ROM Extender
2 | - accepts Z64 (BE), V64 (byte-swapped), or N64 (little-endian) ROMs as input
3 | - works with US, European, Japanese, Shindou, and iQue ROMs
4 | - decompresses all MIO0 blocks from ROM to extended area
5 | - configurable extended ROM size (default 64 MB)
6 | - configurable padding between MIO0 blocks (default 32 KB)
7 | - configurable MIO0 block alignment (default 1 byte)
8 | - changes all 0x18 level commands to 0x17
9 | - creates MIO0 headers for all 0x1A level commands
10 | - optionally dump compressed and uncompressed MIO0 data to files
11 | - optionally fills old MIO0 blocks with 0x01
12 | - updates assembly reference to MIO0 blocks
13 | - recalculates ROM header checksums
14 |
15 | ### Usage
16 | ```
17 | sm64extend [-a ALIGNMENT] [-p PADDING] [-s SIZE] [-d] [-f] [-v] FILE [OUT_FILE]
18 | ```
19 | Options:
20 | -a ALIGNMENT Byte boundary to align MIO0 blocks (default = 1).
21 | -p PADDING Padding to insert between MIO0 blocks in KB (default = 32).
22 | -s SIZE Size of the extended ROM in MB (default: 64).
23 | -d dump MIO0 blocks to files in 'mio0files' directory
24 | -f Fill old MIO0 blocks with 0x01.
25 | -v Verbose output.
26 |
27 | File arguments:
28 | FILE input ROM file
29 | OUT_FILE output ROM file (default: replaces FILE extension with .ext.z64)
30 |
31 | ### Examples
32 | 64 MB extended ROM that is bit compatible with with generated from the M64ROMExtender1.3b, after extending to 64 MB
33 | ```
34 | sm64extend sm64.z64
35 | ```
36 |
37 | 24 MB extended ROM that is bit compatible with the ROM generated from the M64ROMExtender1.3b
38 | ```
39 | sm64extend -s 24 sm64.z64
40 | ```
41 |
42 | Enable verbose messages and specify output filename:
43 | ```
44 | sm64extend -v sm64.z64 sm64_output.ext.z64
45 | ```
46 |
47 | Pad 64 KB between blocks, align blocks to 16-byte boundaries, fill old MIO0 blocks with 0x01:
48 | ```
49 | sm64extend -p 64 -a 16 -f sm64.z64 sm64_output.ext.z64
50 | ```
51 | ### Changelog:
52 | v0.3.2: add support for SM64 iQue ROM
53 | v0.3.1: add little-endian ROM support and error checking
54 | - add support for .n64 little-endian ROMs
55 | - add further validation on SM64 ROM version
56 | - restrict range of output size to between 16 and 64MB
57 | v0.3: add support for (E) and Shindou ROMs
58 | - increase detection of level script and asm references
59 | - detect optimized ASM references
60 | - statically link win32 build to drop MSVCR120.dll dependency
61 | v0.2.1: add dump option and ROM validity checks
62 | - add dump (-d) command line option
63 | - add more ROM validity checks on input file
64 | v0.2: more options, error checking, and allow extending SM64 (J)
65 | - add fill (-f) command line option
66 | - add more error checking up front and while extending
67 | - dynamically find ASM references to MIO0 blocks to support SM64 (J) ROM
68 | v0.1: Initial release
69 | - supports extending SM64 (U) ROM
70 |
--------------------------------------------------------------------------------
/release/split.bat:
--------------------------------------------------------------------------------
1 | :: change to batch file's directory so tools and config file can be referenced
2 | pushd %~dp0
3 | :: split input ROM using verbose mode and let it autodetect the config file
4 | tools\n64split.exe -v %1
5 | popd
6 | :: wait for user
7 | pause
8 |
--------------------------------------------------------------------------------
/sm64extend.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "libsm64.h"
6 | #include "utils.h"
7 |
8 | #define SM64EXTEND_VERSION "0.3.2"
9 |
10 | // default configuration
11 | static const sm64_config default_config =
12 | {
13 | NULL, // input filename
14 | NULL, // extended filename
15 | 64, // extended size
16 | 32, // MIO0 padding
17 | 1, // MIO0 alignment
18 | 0, // fill old MIO0 blocks
19 | 0, // dump MIO0 blocks to files
20 | };
21 |
22 | static void print_usage(void)
23 | {
24 | ERROR("Usage: sm64extend [-a ALIGNMENT] [-p PADDING] [-s SIZE] [-d] [-f] [-v] FILE [OUT_FILE]\n"
25 | "\n"
26 | "sm64extend v" SM64EXTEND_VERSION ": Super Mario 64 ROM extender\n"
27 | "Supports (E), (J), (U), Shindou, and iQue ROMs in .n64, .v64, or .z64 formats\n"
28 | "\n"
29 | "Optional arguments:\n"
30 | " -a ALIGNMENT byte boundary to align MIO0 blocks (default: %d)\n"
31 | " -p PADDING padding to insert between MIO0 blocks in KB (default: %d)\n"
32 | " -s SIZE size of the extended ROM in MB (default: %d)\n"
33 | " -d dump MIO0 blocks to files in 'mio0files' directory\n"
34 | " -f fill old MIO0 blocks with 0x01\n"
35 | " -v verbose progress output\n"
36 | "\n"
37 | "File arguments:\n"
38 | " FILE input ROM file\n"
39 | " OUT_FILE output ROM file (default: replaces FILE extension with .ext.z64)\n",
40 | default_config.alignment, default_config.padding, default_config.ext_size);
41 | exit(EXIT_FAILURE);
42 | }
43 |
44 | // parse command line arguments
45 | static void parse_arguments(int argc, char *argv[], sm64_config *config)
46 | {
47 | int i;
48 | int file_count = 0;
49 | if (argc < 2) {
50 | print_usage();
51 | }
52 | for (i = 1; i < argc; i++) {
53 | if (argv[i][0] == '-') {
54 | switch (argv[i][1]) {
55 | case 'a':
56 | if (++i >= argc) {
57 | print_usage();
58 | }
59 | config->alignment = strtoul(argv[i], NULL, 0);
60 | break;
61 | case 'd':
62 | config->dump = 1;
63 | break;
64 | case 'f':
65 | config->fill = 1;
66 | break;
67 | case 'p':
68 | if (++i >= argc) {
69 | print_usage();
70 | }
71 | config->padding = strtoul(argv[i], NULL, 0);
72 | break;
73 | case 's':
74 | if (++i >= argc) {
75 | print_usage();
76 | }
77 | config->ext_size = strtoul(argv[i], NULL, 0);
78 | break;
79 | case 'v':
80 | g_verbosity = 1;
81 | break;
82 | default:
83 | print_usage();
84 | break;
85 | }
86 | } else {
87 | switch (file_count) {
88 | case 0:
89 | config->in_filename = argv[i];
90 | break;
91 | case 1:
92 | config->ext_filename = argv[i];
93 | break;
94 | default: // too many
95 | print_usage();
96 | break;
97 | }
98 | file_count++;
99 | }
100 | }
101 | if (file_count < 1) {
102 | print_usage();
103 | }
104 | }
105 |
106 | int main(int argc, char *argv[])
107 | {
108 | char ext_filename[FILENAME_MAX];
109 | sm64_config config;
110 | unsigned char *in_buf = NULL;
111 | unsigned char *out_buf = NULL;
112 | long in_size;
113 | long bytes_written;
114 | rom_type rtype;
115 | rom_version rversion;
116 |
117 | // get configuration from arguments
118 | config = default_config;
119 | parse_arguments(argc, argv, &config);
120 | if (config.ext_filename == NULL) {
121 | config.ext_filename = ext_filename;
122 | generate_filename(config.in_filename, config.ext_filename, "ext.z64");
123 | }
124 |
125 | // validate arguments
126 | if (config.ext_size < 16 || config.ext_size > 64) {
127 | ERROR("Error: Extended size must be between 16 and 64 MB\n");
128 | exit(EXIT_FAILURE);
129 | }
130 | if (!is_power2(config.alignment)) {
131 | ERROR("Error: Alignment must be power of 2\n");
132 | exit(EXIT_FAILURE);
133 | }
134 |
135 | // convert sizes to bytes
136 | config.ext_size *= MB;
137 | config.padding *= KB;
138 |
139 | // generate MIO0 directory
140 | if (config.dump) {
141 | make_dir(MIO0_DIR);
142 | }
143 |
144 | // read input file into memory
145 | in_size = read_file(config.in_filename, &in_buf);
146 | if (in_size <= 0) {
147 | ERROR("Error reading input file \"%s\"\n", config.in_filename);
148 | exit(EXIT_FAILURE);
149 | }
150 |
151 | // confirm valid SM64
152 | rtype = sm64_rom_type(in_buf, in_size);
153 | switch (rtype) {
154 | case ROM_INVALID:
155 | ERROR("This does not appear to be a valid SM64 ROM\n");
156 | exit(EXIT_FAILURE);
157 | break;
158 | case ROM_SM64_BS:
159 | INFO("Converting ROM from byte-swapped to big-endian\n");
160 | swap_bytes(in_buf, in_size);
161 | break;
162 | case ROM_SM64_BE:
163 | break;
164 | case ROM_SM64_LE:
165 | INFO("Converting ROM from little to big-endian\n");
166 | reverse_endian(in_buf, in_size);
167 | break;
168 | case ROM_SM64_BE_EXT:
169 | ERROR("This ROM is already extended!\n");
170 | exit(EXIT_FAILURE);
171 | break;
172 | }
173 |
174 | rversion = sm64_rom_version(in_buf);
175 | if (rversion == VERSION_UNKNOWN) {
176 | ERROR("Unknown SM64 ROM version\n");
177 | exit(EXIT_FAILURE);
178 | }
179 |
180 | // allocate output memory
181 | out_buf = malloc(config.ext_size);
182 |
183 | // copy file from input to output
184 | memcpy(out_buf, in_buf, in_size);
185 |
186 | // fill new space with 0x01
187 | memset(&out_buf[in_size], 0x01, config.ext_size - in_size);
188 |
189 | // decode SM64 MIO0 files and adjust pointers
190 | sm64_decompress_mio0(&config, in_buf, in_size, out_buf);
191 |
192 | // update N64 header CRC
193 | sm64_update_checksums(out_buf);
194 |
195 | // write to output file
196 | bytes_written = write_file(config.ext_filename, out_buf, config.ext_size);
197 | if (bytes_written < (long)config.ext_size) {
198 | ERROR("Error writing bytes to output file \"%s\"\n", config.ext_filename);
199 | exit(EXIT_FAILURE);
200 | }
201 |
202 | return EXIT_SUCCESS;
203 | }
204 |
--------------------------------------------------------------------------------
/sm64geo.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "utils.h"
6 |
7 | #define SM64GEO_VERSION "0.1"
8 |
9 | typedef struct
10 | {
11 | char *in_filename;
12 | char *out_filename;
13 | unsigned int offset;
14 | unsigned int length;
15 | } arg_config;
16 |
17 | static arg_config default_config =
18 | {
19 | NULL,
20 | NULL,
21 | 0,
22 | 0
23 | };
24 |
25 | static void print_spaces(FILE *fp, int count)
26 | {
27 | int i;
28 | for (i = 0; i < count; i++) {
29 | fputc(' ', fp);
30 | }
31 | }
32 |
33 | void print_geo(FILE *out, unsigned char *data, unsigned int offset, unsigned int length)
34 | {
35 | unsigned int a = offset;
36 | int indent = 0;
37 | int i;
38 | while (a < offset + length) {
39 | switch (data[a]) {
40 | case 0x00: // end
41 | case 0x01:
42 | case 0x03:
43 | case 0x04:
44 | case 0x05:
45 | case 0x09:
46 | case 0x0B:
47 | case 0x0C:
48 | case 0x17:
49 | case 0x20:
50 | i = 4;
51 | break;
52 | case 0x02:
53 | case 0x0D:
54 | case 0x0E:
55 | case 0x12:
56 | case 0x14:
57 | case 0x15:
58 | case 0x16:
59 | case 0x18:
60 | case 0x19:
61 | i = 8;
62 | break;
63 | case 0x08:
64 | case 0x13:
65 | case 0x1C:
66 | i = 12;
67 | break;
68 | case 0x10:
69 | i = 16;
70 | break;
71 | case 0x0F:
72 | i = 20;
73 | break;
74 | case 0x0A:
75 | i = 8;
76 | if (data[a+1]) {
77 | i += 4;
78 | }
79 | break;
80 | case 0x11:
81 | case 0x1D:
82 | i = 8;
83 | if (data[a+1] & 0x80) {
84 | i += 4;
85 | }
86 | break;
87 | default:
88 | i = 4;
89 | ERROR("WHY? %06X %2X\n", a, data[a]);
90 | }
91 | if (data[a] == 0x05 && indent > 1) {
92 | indent -= 2;
93 | }
94 | if (data[a] == 0x01) {
95 | indent = 0;
96 | }
97 | fprintf(out, "%4X: ", a);
98 | print_spaces(out, indent);
99 | fprintf(out, "[ ");
100 | fprint_hex(out, &data[a], i);
101 | fprintf(out, "]\n");
102 | if (data[a] == 0x04) {
103 | indent += 2;
104 | }
105 | a += i;
106 | }
107 | }
108 |
109 | static void print_usage(void)
110 | {
111 | ERROR("Usage: sm64geo [-l LENGTH] [-o OFFSET] FILE\n"
112 | "\n"
113 | "sm64geo v" SM64GEO_VERSION ": Super Mario 64 geometry layout decoder\n"
114 | "\n"
115 | "Optional arguments:\n"
116 | " -l LENGTH length of data to decode in bytes (default: length of file)\n"
117 | " -o OFFSET starting offset in FILE (default: 0)\n"
118 | "\n"
119 | "File arguments:\n"
120 | " FILE input file\n"
121 | " [OUTPUT] output file (default: stdout)\n");
122 | exit(1);
123 | }
124 |
125 | // parse command line arguments
126 | static void parse_arguments(int argc, char *argv[], arg_config *config)
127 | {
128 | int i;
129 | int file_count = 0;
130 | if (argc < 2) {
131 | print_usage();
132 | exit(1);
133 | }
134 | for (i = 1; i < argc; i++) {
135 | if (argv[i][0] == '-') {
136 | switch (argv[i][1]) {
137 | case 'l':
138 | if (++i >= argc) {
139 | print_usage();
140 | }
141 | config->length = strtoul(argv[i], NULL, 0);
142 | break;
143 | case 'o':
144 | if (++i >= argc) {
145 | print_usage();
146 | }
147 | config->offset = strtoul(argv[i], NULL, 0);
148 | break;
149 | default:
150 | print_usage();
151 | break;
152 | }
153 | } else {
154 | switch (file_count) {
155 | case 0:
156 | config->in_filename = argv[i];
157 | break;
158 | case 1:
159 | config->out_filename = argv[i];
160 | break;
161 | default: // too many
162 | print_usage();
163 | break;
164 | }
165 | file_count++;
166 | }
167 | }
168 | if (file_count < 1) {
169 | print_usage();
170 | }
171 | }
172 |
173 | int main(int argc, char *argv[])
174 | {
175 | arg_config config;
176 | FILE *fout;
177 | unsigned char *data;
178 | long size;
179 |
180 | // get configuration from arguments
181 | config = default_config;
182 | parse_arguments(argc, argv, &config);
183 | if (config.out_filename == NULL) {
184 | fout = stdout;
185 | } else {
186 | fout = fopen(config.out_filename, "w");
187 | if (fout == NULL) {
188 | perror("Error opening output file");
189 | return EXIT_FAILURE;
190 | }
191 | }
192 |
193 | // operation
194 | size = read_file(config.in_filename, &data);
195 | if (size < 0) {
196 | perror("Error opening input file");
197 | return EXIT_FAILURE;
198 | }
199 | if (config.length == 0) {
200 | config.length = size - config.offset;
201 | }
202 | if (config.offset >= (unsigned int)size) {
203 | ERROR("Error: offset greater than file size (%X > %X)\n",
204 | config.offset, (unsigned int)size);
205 | return EXIT_FAILURE;
206 | }
207 | if (config.offset + config.length > (unsigned int)size) {
208 | ERROR("Warning: length goes beyond file size (%X > %X), truncating\n",
209 | config.offset + config.length, (unsigned int)size);
210 | config.length = size - config.offset;
211 | }
212 | print_geo(fout, data, config.offset, config.length);
213 | free(data);
214 |
215 | if (fout != stdout) {
216 | fclose(fout);
217 | }
218 |
219 | return EXIT_SUCCESS;
220 | }
221 |
--------------------------------------------------------------------------------
/sm64walk.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "libsm64.h"
6 | #include "utils.h"
7 |
8 | #define SM64WALK_VERSION "0.1"
9 |
10 | static void print_usage(void)
11 | {
12 | ERROR("Usage: sm64walk [-o OFFSET] [-r REGION] [-v] FILE\n"
13 | "\n"
14 | "sm64walk v" SM64WALK_VERSION ": Super Mario 64 script walker\n"
15 | "\n"
16 | "Optional arguments:\n"
17 | " -o OFFSET start decoding level scripts at OFFSET (default: auto-detect)\n"
18 | " -r REGION region to use. valid: Europe, US, JP, Shindou\n"
19 | " -v verbose progress output\n"
20 | "\n"
21 | "File arguments:\n"
22 | " FILE input ROM file\n");
23 | exit(EXIT_FAILURE);
24 | }
25 |
26 | // parse command line arguments
27 | static void parse_arguments(int argc, char *argv[], unsigned *offset, char *region, char *in_filename)
28 | {
29 | int i;
30 | int file_count = 0;
31 | if (argc < 2) {
32 | print_usage();
33 | }
34 | for (i = 1; i < argc; i++) {
35 | if (argv[i][0] == '-') {
36 | switch (argv[i][1]) {
37 | case 'o':
38 | if (++i >= argc) {
39 | print_usage();
40 | }
41 | *offset = strtoul(argv[i], NULL, 0);
42 | break;
43 | case 'r':
44 | if (++i >= argc) {
45 | print_usage();
46 | }
47 | *region = argv[i][0];
48 | break;
49 | case 'v':
50 | g_verbosity = 1;
51 | break;
52 | default:
53 | print_usage();
54 | break;
55 | }
56 | } else {
57 | switch (file_count) {
58 | case 0:
59 | strcpy(in_filename, argv[i]);
60 | break;
61 | default: // too many
62 | print_usage();
63 | break;
64 | }
65 | file_count++;
66 | }
67 | }
68 | if (file_count < 1) {
69 | print_usage();
70 | }
71 | }
72 |
73 | typedef struct
74 | {
75 | unsigned start;
76 | unsigned end;
77 | } level_t;
78 |
79 | static void add_level(level_t levels[], unsigned *lcount, unsigned start, unsigned end)
80 | {
81 | unsigned i;
82 | INFO("Adding level %06X - %06X\n", start, end);
83 | for (i = 0; i < *lcount; i++) {
84 | if (levels[i].start == start) {
85 | return;
86 | }
87 | }
88 | levels[*lcount].start = start;
89 | levels[*lcount].end = end;
90 | (*lcount)++;
91 | }
92 |
93 | static void decode_level(unsigned char *data, level_t levels[], unsigned int l, unsigned *lcount)
94 | {
95 | unsigned int ptr_start;
96 | unsigned int ptr_end;
97 | unsigned int dst;
98 | unsigned int a;
99 | int i;
100 |
101 | printf("Decoding level script %X\n", levels[l].start);
102 |
103 | a = levels[l].start;
104 | // length = 0 ends level script
105 | while (a < levels[l].end && data[a+1] != 0) {
106 | printf("%06X [%03X] ", a, a - levels[l].start);
107 | switch (data[a]) {
108 | case 0x00: printf("LoadJump0"); break; // load and jump from ROM into a RAM segment
109 | case 0x01: printf("LoadJump1"); break; // load and jump from ROM into a RAM segment
110 | case 0x02: printf("EndLevel "); break; // end of level layout data
111 | case 0x03: printf("Delay03 "); break; // delay frames
112 | case 0x04: printf("Delay04 "); break; // delay frames and signal end
113 | case 0x05: printf("JumpSeg "); break; // jump to level script at segmented address
114 | case 0x06: printf("PushJump "); break; // push script stack and jump to segmented address
115 | case 0x07: printf("PopScript"); break; // pop script stack, return to prev 0x06 or 0x0C
116 | case 0x08: printf("Push16 "); break; // push script stack and 16-bit value
117 | case 0x09: printf("Pop16 "); break; // pop script stack and 16-bit value
118 | case 0x0A: printf("PushNull "); break; // push script stack and 32-bit 0x00000000
119 | case 0x0B: printf("CondPop "); break; // conditional stack pop
120 | case 0x0C: printf("CondJump "); break; // conditional jump to segmented address
121 | case 0x0D: printf("CondPush "); break; // conditional stack push
122 | case 0x0E: printf("CondSkip "); break; // conditional skip over following 0x0F and 0x10 commands
123 | case 0x0F: printf("SkipNext "); break; // skip over following 0x10 commands
124 | case 0x10: printf("NoOp "); break; // no operation
125 | case 0x11: printf("AccumAsm1"); break; // set accumulator from ASM function
126 | case 0x12: printf("AccumAsm2"); break; // actively set accumulator from ASM function
127 | case 0x13: printf("SetAccum "); break; // set accumulator to constant value
128 | case 0x14: printf("PushPool "); break; // push pool state
129 | case 0x15: printf("PopPool "); break; // pop pool state
130 | case 0x16: printf("LoadASM "); break; // load ASM into RAM
131 | case 0x17: printf("ROM->Seg "); break; // copy uncompressed data from ROM to a RAM segment
132 | case 0x18: printf("MIO0->Seg"); break; // decompress MIO0 data from ROM and copy it into a RAM segment
133 | case 0x19: printf("MarioFace"); break; // create Mario face for demo screen
134 | case 0x1A: printf("MIO0Textr"); break; // decompress MIO0 data from ROM and copy it into a RAM segment (for texture only segments?)
135 | case 0x1B: printf("StartLoad"); break; // start RAM loading sequence (before 17, 18, 1A)
136 | case 0x1D: printf("EndLoad "); break; // end RAM loading sequence (after 17, 18, 1A)
137 | case 0x1F: printf("StartArea"); break; // start of an area
138 | case 0x20: printf("EndArea "); break; // end of an area
139 | case 0x21: printf("LoadPoly "); break; // load polygon data without geo layout
140 | case 0x22: printf("LdPolyGeo"); break; // load polygon data with geo layout
141 | case 0x24: printf("PlaceObj "); break; // place object in level with behavior
142 | case 0x25: printf("LoadMario"); break; // load mario object with behavior
143 | case 0x26: printf("ConctWarp"); break; // connect warps
144 | case 0x27: printf("PaintWarp"); break; // level warps for paintings
145 | case 0x28: printf("Transport"); break; // transport Mario to an area
146 | case 0x2B: printf("MarioStrt"); break; // Mario's default position
147 | case 0x2E: printf("Collision"); break; // load collision data
148 | case 0x2F: printf("RendrArea"); break; // decide which area of level geo to render
149 | case 0x31: printf("Terrain "); break; // set default terrain type
150 | case 0x33: printf("FadeColor"); break; // fade/overlay screen with color
151 | case 0x34: printf("Blackout "); break; // blackout screen
152 | case 0x36: printf("Music36 "); break; // set music
153 | case 0x37: printf("Music37 "); break; // set music
154 | case 0x39: printf("MulObject"); break; // multiple objects from main level segment
155 | case 0x3B: printf("JetStream"); break; // define jet streams that repulse / pull Mario
156 | case 0x3C: printf("GetPut "); break; // get/put remote value
157 | default: printf(" "); break;
158 | }
159 | printf(" %02X %02X %02X%02X ", data[a], data[a+1], data[a+2], data[a+3]);
160 | switch (data[a]) {
161 | case 0x00: // load and jump from ROM into a RAM segment
162 | case 0x01: // load and jump from ROM into a RAM segment
163 | ptr_start = read_u32_be(&data[a+4]);
164 | ptr_end = read_u32_be(&data[a+8]);
165 | printf("%08X %08X %08X\n", ptr_start, ptr_end, read_u32_be(&data[a+0xc]));
166 | add_level(levels, lcount, ptr_start, ptr_end);
167 | break;
168 | case 0x17: // copy uncompressed data from ROM to a RAM segment
169 | case 0x18: // decompress MIO0 data from ROM and copy it into a RAM segment
170 | case 0x1A: // decompress MIO0 data from ROM and copy it into a RAM segment (for texture only segments?)
171 | ptr_start = read_u32_be(&data[a+4]);
172 | ptr_end = read_u32_be(&data[a+8]);
173 | printf("%08X %08X\n", ptr_start, ptr_end);
174 | break;
175 | case 0x11: // call function
176 | case 0x12: // call function
177 | ptr_start = read_u32_be(&data[a+0x4]);
178 | printf("%08X\n", ptr_start);
179 | break;
180 | case 0x16: // load ASM into RAM
181 | dst = read_u32_be(&data[a+0x4]);
182 | ptr_start = read_u32_be(&data[a+0x8]);
183 | ptr_end = read_u32_be(&data[a+0xc]);
184 | printf("%08X %08X %08X\n", dst, ptr_start, ptr_end);
185 | break;
186 | case 0x25: // load mario object with behavior
187 | case 0x24: // load object with behavior
188 | printf("%08X", read_u32_be(&data[a]));
189 | for (i = 4; i < data[a+1]-4; i+=4) {
190 | printf(" %08X", read_u32_be(&data[a+i]));
191 | }
192 | dst = read_u32_be(&data[a+i]);
193 | printf(" %08X\n", dst);
194 | break;
195 | default:
196 | for (i = 4; i < data[a+1]; i+=4) {
197 | printf("%08X ", read_u32_be(&data[a+i]));
198 | }
199 | printf("\n");
200 | break;
201 | }
202 | a += data[a+1];
203 | }
204 | printf("Done %X\n\n", levels[l].start);
205 | }
206 |
207 | char detectRegion(unsigned char *data)
208 | {
209 | unsigned checksum = read_u32_be(&data[0x10]);
210 | // add main entry level script
211 | switch (checksum) {
212 | case 0xA03CF036: return 'E';
213 | case 0x4EAA3D0E: return 'J';
214 | case 0xD6FBA4A8: return 'S'; // Shindou Edition (J)
215 | case 0x635A2BFF: return 'U';
216 | default:
217 | ERROR("Unknown ROM checksum: 0x%08X\n", checksum);
218 | exit(1);
219 | }
220 | }
221 |
222 | unsigned getRegionOffset(char region)
223 | {
224 | switch (region) {
225 | case 'E': return 0xDE160;
226 | case 'J': return 0x1076A0;
227 | case 'S': return 0xE42C0;
228 | case 'U': return 0x108A10;
229 | default:
230 | ERROR("Unknown region: '%c'\n", region);
231 | exit(1);
232 | }
233 | return 0;
234 | }
235 |
236 | static void walk_scripts(unsigned char *data, unsigned offset)
237 | {
238 | level_t levelscripts[100];
239 | unsigned lcount = 0;
240 | unsigned l = 0;
241 | levelscripts[0].start = offset;
242 | levelscripts[0].end = offset + 0x30;
243 | lcount++;
244 | while (l < lcount) {
245 | decode_level(data, levelscripts, l, &lcount);
246 | l++;
247 | }
248 | }
249 |
250 | int main(int argc, char *argv[])
251 | {
252 | char in_filename[FILENAME_MAX];
253 | unsigned char *in_buf = NULL;
254 | unsigned offset = 0xFFFFFFFF;
255 | long in_size;
256 | int rom_type;
257 | char region = 0;
258 |
259 | // get configuration from arguments
260 | parse_arguments(argc, argv, &offset, ®ion, in_filename);
261 |
262 | // read input file into memory
263 | in_size = read_file(in_filename, &in_buf);
264 | if (in_size <= 0) {
265 | ERROR("Error reading input file \"%s\"\n", in_filename);
266 | exit(EXIT_FAILURE);
267 | }
268 |
269 | // confirm valid SM64
270 | rom_type = sm64_rom_type(in_buf, in_size);
271 | if (rom_type < 0) {
272 | ERROR("This does not appear to be a valid SM64 ROM\n");
273 | exit(EXIT_FAILURE);
274 | } else if (rom_type == 1) {
275 | // byte-swapped BADC format, swap to big-endian ABCD format for processing
276 | INFO("Byte-swapping ROM\n");
277 | swap_bytes(in_buf, in_size);
278 | }
279 |
280 | if (offset == 0xFFFFFFFF) {
281 | if (region == 0) {
282 | region = detectRegion(in_buf);
283 | }
284 | offset = getRegionOffset(region);
285 | }
286 |
287 | // walk those scripts
288 | walk_scripts(in_buf, offset);
289 |
290 | // cleanup
291 | free(in_buf);
292 |
293 | return EXIT_SUCCESS;
294 | }
295 |
--------------------------------------------------------------------------------
/strutils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "strutils.h"
7 |
8 | // buffer for local sprintf
9 | static char tmpbuf[4096];
10 |
11 | void strbuf_alloc(strbuf *sbuf, size_t allocate)
12 | {
13 | // some sane default allocation
14 | if (allocate <= 0) {
15 | allocate = 512;
16 | }
17 | sbuf->buf = malloc(allocate);
18 | sbuf->allocated = allocate;
19 | sbuf->index = 0;
20 | }
21 |
22 | void strbuf_sprintf(strbuf *sbuf, const char *format, ...)
23 | {
24 | va_list args;
25 |
26 | va_start(args, format);
27 | int len = vsprintf(tmpbuf, format, args);
28 | va_end(args);
29 |
30 | while (sbuf->allocated <= sbuf->index + len) {
31 | sbuf->allocated *= 2;
32 | sbuf->buf = realloc(sbuf->buf, sbuf->allocated);
33 | }
34 | memcpy(&sbuf->buf[sbuf->index], tmpbuf, len + 1);
35 | sbuf->index += len;
36 | }
37 |
38 | void strbuf_free(strbuf *sbuf)
39 | {
40 | if (sbuf->buf) {
41 | free(sbuf->buf);
42 | sbuf->allocated = 0;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/strutils.h:
--------------------------------------------------------------------------------
1 | #ifndef STRUTILS_H
2 | #define STRUTILS_H
3 |
4 | typedef struct
5 | {
6 | char *buf;
7 | size_t allocated;
8 | size_t index;
9 | } strbuf;
10 |
11 | void strbuf_alloc(strbuf *sbuf, size_t allocate);
12 |
13 | // sprintf and strcat to end of buffer
14 | void strbuf_sprintf(strbuf *sbuf, const char *format, ...);
15 |
16 | void strbuf_free(strbuf *sbuf);
17 |
18 | #endif /* STRUTILS_H */
19 |
--------------------------------------------------------------------------------
/tests/example1/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = example1.bin
2 |
3 | BIN_DIR = ./bin
4 |
5 | AS = armips
6 | MIO0 = ../../mio0
7 | N64GRAPHICS = ../../n64graphics
8 |
9 | # targets
10 |
11 | default: $(TARGET)
12 |
13 | example1.bin: example1.asm bin/texture_block.bin.gz bin/texture_block.mio0 bin/texture_ia16.bin bin/texture_rgba16.bin
14 | $(AS) $<
15 |
16 | $(BIN_DIR):
17 | mkdir -p $(BIN_DIR)
18 |
19 | # graphics conversion
20 | $(BIN_DIR)/texture_rgba16.bin: textures/heart.0.rgba16.png $(BIN_DIR)
21 | $(N64GRAPHICS) -f rgba16 -g $< -i $@
22 |
23 | $(BIN_DIR)/texture_ia16.bin: textures/heart.0.ia16.png $(BIN_DIR)
24 | $(N64GRAPHICS) -f ia16 -g $< -i $@
25 |
26 | # concatenate texture files to form texture_block
27 | $(BIN_DIR)/texture_block.bin: bin/texture_rgba16.bin bin/texture_ia16.bin
28 | cat $^ > $@
29 |
30 | $(BIN_DIR)/texture_block.bin.gz: bin/texture_block.bin
31 | @[ -d $(BIN_DIR) ] || mkdir -p $(BIN_DIR)
32 | gzip -c $< > $@
33 |
34 | $(BIN_DIR)/texture_block.mio0: bin/texture_block.bin
35 | @[ -d $(BIN_DIR) ] || mkdir -p $(BIN_DIR)
36 | $(MIO0) -c $< $@
37 |
38 | clean:
39 | rm -rf $(TARGET) $(BIN_DIR)
40 |
41 | .PHONY: clean default
42 |
--------------------------------------------------------------------------------
/tests/example1/example1.asm:
--------------------------------------------------------------------------------
1 | .n64
2 | .create "example1.bin", 0x0
3 |
4 | //-------------------------------------------------
5 | // N64 header
6 | //-------------------------------------------------
7 | .word 0x80371240 // PI BSD Domain 1 register
8 | .word 0x0000000F // clock rate setting
9 | .word EntryPoint // entry point
10 | .word 0x00001444 // release
11 | .word 0x635A2BFF // checksum1
12 | .word 0x8B022326 // checksum2
13 | .word 0x00000000 // unknown
14 | .word 0x00000000 // unknown"
15 | .ascii "TEST BINARY ROM " // ROM name: 20 bytes
16 | .word 0x00000000 // unknown
17 | .word 0x0000004E // cartridge
18 | .ascii "TS" // cartridge ID
19 | .ascii "E" // country
20 | .byte 0x00 // version
21 |
22 | //-------------------------------------------------
23 | // begin asm section
24 | //-------------------------------------------------
25 | .definelabel stack_start, 0x80400000
26 |
27 | .headersize 0x80100000 - orga()
28 |
29 | // .text
30 | EntryPoint:
31 | lw sp, stack_start
32 | jal main
33 | nop
34 | j EntryPoint
35 | nop
36 |
37 | main:
38 | addiu sp, sp, -0x18
39 | sw ra, 0x14(sp)
40 | la t1, data0
41 | la t2, data1
42 | beq t1, t2, @@done
43 | nop
44 | @@loop:
45 | lw t3, 0(t1)
46 | addiu t1, t1, 4
47 | bne t1, t2, @@loop
48 | nop
49 | @@done:
50 | lw ra, 0x14(sp)
51 | jr ra
52 | addiu sp, sp, 0x18
53 |
54 | // .data
55 | .align 0x10
56 | data0:
57 | .dw 0x00000000, 0x11111111, 0x22222222, 0x33333333
58 | data1:
59 | .dw 0x44444444, 0x55555555, 0x66666666, 0x77777777
60 | data_ptrs:
61 | .dw data0, data1
62 | texture_ptrs:
63 | .dw texture_rgba, texture_ia
64 | file_ptrs:
65 | .dw block_mio0_start, block_mio0_end, block_gz_start, block_gz_end
66 |
67 | // put textures in its own section
68 | .align 0x10
69 | .headersize 0x04000000 - orga()
70 |
71 | texture_rgba:
72 | .incbin "bin/texture_rgba16.bin"
73 | texture_ia:
74 | .incbin "bin/texture_ia16.bin"
75 |
76 | .dw 0xcafeface
77 |
78 | // binary blocks use absolute
79 | .headersize 0x10
80 | .align 16
81 |
82 | //-------------------------------------------------
83 | // MIO0 block
84 | //-------------------------------------------------
85 | block_mio0_start:
86 | .incbin "bin/texture_block.mio0"
87 | block_mio0_end:
88 |
89 | .dw 0xdeadbeef
90 |
91 | //-------------------------------------------------
92 | // gzip block
93 | //-------------------------------------------------
94 | .align 16
95 | block_gz_start:
96 | .incbin "bin/texture_block.bin.gz"
97 | block_gz_end:
98 |
99 | .close
100 |
--------------------------------------------------------------------------------
/tests/example1/textures/heart.0.ia16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/tests/example1/textures/heart.0.ia16.png
--------------------------------------------------------------------------------
/tests/example1/textures/heart.0.rgba16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/queueRAM/sm64tools/81de9e5a8f0fa96686a16441d5b9f25742f4d17d/tests/example1/textures/heart.0.rgba16.png
--------------------------------------------------------------------------------
/tools/Makefile:
--------------------------------------------------------------------------------
1 | ################ Target Executable and Sources ###############
2 |
3 | TARGET := montage
4 |
5 | SRC_FILES := montage.c \
6 | ../yamlconfig.c \
7 | ../utils.c
8 |
9 | ##################### Compiler Options #######################
10 |
11 | WIN64_CROSS = x86_64-w64-mingw32-
12 | WIN32_CROSS = i686-w64-mingw32-
13 | #CROSS = $(WIN32_CROSS)
14 | CC = $(CROSS)gcc
15 | LD = $(CC)
16 |
17 | INCLUDES =
18 | DEFS =
19 | CFLAGS = -Wall -Wextra -O2 -ffunction-sections -fdata-sections $(INCLUDES) $(DEFS)
20 |
21 | LDFLAGS = -s -Wl,--gc-sections
22 | LIBS = -lconfig
23 |
24 | ######################## Targets #############################
25 |
26 | default: all
27 |
28 | all: $(TARGET) matchsigs sm64collision sm64walk
29 |
30 | $(TARGET): $(SRC_FILES)
31 | $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
32 |
33 | matchsigs: match_signatures.c ../utils.c
34 | $(CC) $(CFLAGS) -o $@ $^ -lcapstone
35 |
36 | sm64collision: sm64collision.c ../utils.c
37 | $(CC) $(CFLAGS) -o $@ $^
38 |
39 | sm64text: sm64text.c
40 | $(CC) $(CFLAGS) -o $@ $^
41 |
42 | clean:
43 | rm -f $(TARGET)
44 |
45 | .PHONY: all clean default
46 |
47 |
--------------------------------------------------------------------------------
/tools/dma2config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from __future__ import print_function
4 | import csv
5 | import sys
6 |
7 | def eprint(*args, **kwargs):
8 | print(*args, file=sys.stderr, **kwargs)
9 | sys.stderr.flush()
10 |
11 | # find most recent DMA that matches JAL
12 | def FindLatestDma(dmas, jal):
13 | jal_mask = jal & 0x0FFFFFFF
14 | for dma in reversed(dmas):
15 | if jal_mask >= dma.dest and jal_mask < dma.dest + dma.length:
16 | return dma
17 | return None
18 |
19 | # DMA class stores information about DMA from ROM to RDRAM
20 | class DMA():
21 | def __init__(self, source, dest, length):
22 | self.source = source
23 | self.dest = dest
24 | self.length = length
25 | self.jals = []
26 |
27 | # ROM class stores detected ROM information
28 | class ROM():
29 | def __init__(self, rom_id, regions, description, cksum1, cksum2):
30 | self.rom_id = rom_id
31 | self.regions = regions
32 | self.description = description
33 | self.cksum1 = cksum1
34 | self.cksum2 = cksum2
35 |
36 | rom = ROM("rom", "", "noname", 0x0, 0x0)
37 | dmas = []
38 | jals = []
39 |
40 | # command line input checking
41 | if len(sys.argv) < 2:
42 | eprint("Usage: dma2config.py ")
43 | sys.exit(1)
44 |
45 | # read in log file as CSV and parse rows
46 | eprint("Parsing '{}'...".format(sys.argv[1]))
47 | with open(sys.argv[1], 'rb') as csvfile:
48 | spamreader = csv.reader(csvfile, delimiter=',')
49 | for row in spamreader:
50 | if row[0] == 'ROM':
51 | rom = ROM(row[1], row[2], row[3], int(row[4], 16), int(row[5], 16))
52 | eprint("ROM info: {}".format(row))
53 | elif row[0] == 'DMA':
54 | source = int(row[1], 16)
55 | if not any(x.source == source for x in dmas):
56 | dmas.append(DMA(source, int(row[2], 16), int(row[3], 16)))
57 | elif row[0] == 'JAL' or row[0] == 'JALR':
58 | jal = int(row[1], 16)
59 | jals.append(jal)
60 | dma = FindLatestDma(dmas, jal)
61 | if dma is None:
62 | eprint("Error no DMA for JAL %08X" % jal)
63 | else:
64 | dma.jals.append(jal)
65 |
66 | # sort arrays
67 | eprint("Sorting arrays...")
68 | dmas.sort(key=lambda x: x.dest)
69 | jals.sort()
70 |
71 | # merge consecutive DMA regions
72 | eprint("Merging DMA regions...")
73 | dmas_new = []
74 | for dma in dmas:
75 | merged = False
76 | for n in dmas_new:
77 | if dma.source == n.source + n.length and dma.dest == n.dest + n.length:
78 | n.length += dma.length
79 | merged = True
80 | elif n.source == dma.source + dma.length and n.dest == dma.dest + dma.length:
81 | n.source = dma.source
82 | n.length += dma.length
83 | merged = True
84 | if not merged:
85 | dmas_new.append(dma)
86 | dmas = dmas_new
87 |
88 | # copy of DMAs, sorted by ROM
89 | dmas_rom = sorted(dmas, key=lambda x: x.source)
90 |
91 | # output n64split config file
92 | eprint("Generating config file...")
93 | print("// n64split configuration file")
94 | print("// generated by dma2config")
95 | print("name = \"%s\";" % rom.description)
96 | print("")
97 |
98 | print("// checksums from ROM header offsets 0x10 and 0x14")
99 | print("// used for auto configuration detection")
100 | print("checksum1 = 0x%08X;" % rom.cksum1)
101 | print("checksum2 = 0x%08X;" % rom.cksum2)
102 | print("")
103 |
104 | print("// base filename used for outputs (please, no spaces)")
105 | print("basename = \"%s\";" % rom.rom_id)
106 | print("")
107 |
108 | print("// memory map from KSEG0 RAM addresses to ROM offsets")
109 | print("// these were decoded from DMA accesses")
110 | print("memory =")
111 | print("(")
112 | print(" // start end ram-to-rom")
113 | last_dma = None
114 | for dma in dmas:
115 | if dma.jals:
116 | start = 0x80000000 + dma.dest
117 | end = start + dma.length
118 | ram2rom = start - dma.source
119 | if last_dma is not None:
120 | print(", // 0x%06X-0x%06X 0x%06X" % (last_dma.source, last_dma.source + last_dma.length, last_dma.length))
121 | sys.stdout.write(" (0x%08X, 0x%08X, 0x%08X)" % (start, end, ram2rom))
122 | last_dma = dma
123 | # last DMA gets no comma
124 | if last_dma is not None:
125 | print(" // 0x%06X-0x%06X 0x%06X" % (last_dma.source, last_dma.source + last_dma.length, last_dma.length))
126 |
127 | print(");")
128 | print("")
129 | print("// ranges to split the ROM into")
130 | print("// types:")
131 | print("// asm - MIPS assembly block. Symbol names are in 'labels' list below")
132 | print("// behavior - behavior script")
133 | print("// bin - raw binary, usually data")
134 | print("// header - ROM header block")
135 | print("// instrset - instrument set")
136 | print("// level - level commands")
137 | print("// m64 - M64 music sequence bank")
138 | print("// mio0 - MIO0 compressed data block. may have texture breakdown")
139 | print("// ptr - RAM address or ROM offset pointer")
140 | print("//")
141 | print("// textures types:")
142 | print("// rgba - 16-bit RGBA (5-5-5-1)")
143 | print("// ia - 16/8/4/1-bit greyscale")
144 | print("// skybox - grid of 32x32 16-bit RGBA")
145 | print("ranges =")
146 | print("(")
147 | print(" // start, end, type, label")
148 | first = True
149 | for dma in dmas_rom:
150 | if not first:
151 | print(",")
152 | else:
153 | first = False
154 | sys.stdout.write(" (0x%06X, 0x%06X, \"%s\")" % (dma.source, dma.source + dma.length, "asm" if dma.jals else "bin" ))
155 | print();
156 | print(");")
157 | print("")
158 |
159 | print("// Labels for functions or data memory addresses")
160 | print("// All label addresses are RAM addresses")
161 | print("// Order does not matter")
162 | print("labels =")
163 | print("(")
164 | first = True
165 | for jal in jals:
166 | if not first:
167 | print(",")
168 | else:
169 | first = False
170 | sys.stdout.write(" (0x%08X, \"proc_%08X\")" % (jal, jal))
171 | print();
172 | print(");")
173 | print("")
174 |
--------------------------------------------------------------------------------
/tools/hudtable.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "../utils.h"
6 |
7 | #define NUM_COLS 4
8 | #define NUM_ROWS (0x80/NUM_COLS)
9 |
10 | char lookupchar(int hex)
11 | {
12 | if (hex >= ' ' && hex <= '~') {
13 | return (char)hex;
14 | }
15 | return ' ';
16 | }
17 |
18 | int convertchar(int ascii)
19 | {
20 | if (ascii >= 0x41 && ascii < 0x5B) {
21 | return ascii - 0x37;
22 | } else if (ascii >= 0x61 && ascii < 0x7B) {
23 | return ascii - 0x57;
24 | } else if (ascii >= 0x30 && ascii < 0x3A) {
25 | return ascii - 0x30;
26 | } else {
27 | switch (ascii) {
28 | case 0x20: return -1; break;
29 | case 0x21: return 0x24; break;
30 | case 0x23: return 0x25; break;
31 | case 0x3F: return 0x26; break;
32 | case 0x26: return 0x27; break;
33 | case 0x25: return 0x28; break;
34 | case 0x2A: return 0x32; break;
35 | case 0x2B: return 0x33; break;
36 | case 0x2C: return 0x34; break;
37 | case 0x2D: return 0x35; break;
38 | case 0x2E: return 0x36; break;
39 | case 0x2F: return 0x37; break;
40 | }
41 | }
42 | return -1;
43 | }
44 |
45 | int main(int argc, char *argv[])
46 | {
47 | unsigned char *data;
48 | long len = read_file("sm64.split/bin/font_graphics.bin", &data);
49 | unsigned int r, c, hexchar;
50 | int convchar;
51 | unsigned int seg;
52 | unsigned int offset;
53 | char printchar;
54 | char printstr[8];
55 |
56 | for (c = 0; c < NUM_COLS - 1; c++) {
57 | printf("^ Hex ^ A ^ Index ^ Seg Addr ^ T ");
58 | }
59 | printf("^\n");
60 | for (r = 0; r < 0x80/NUM_COLS; r++) {
61 | for (c = 1; c < NUM_COLS; c++) {
62 | hexchar = r + NUM_ROWS*c;
63 | convchar = convertchar(hexchar);
64 | if (convchar == -1) {
65 | seg = 0;
66 | } else {
67 | seg = read_u32_be(&data[0x7700 + 4*convchar]);
68 | }
69 | offset = 0xFFFFFF & seg;
70 | printchar = lookupchar(hexchar);
71 | if (printchar == '|' || printchar == '^') {
72 | sprintf(printstr, "%%%%%c%%%%", printchar);
73 | } else {
74 | sprintf(printstr, "%c", printchar);
75 | }
76 | printf("| %02X | %s | ", hexchar, printstr);
77 | if (seg == 0) {
78 | if (convchar == -1) {
79 | printf(" - | - | ");
80 | } else {
81 | printf(" %02X | %08X | ", convchar, seg);
82 | }
83 | } else {
84 | printf(" %02X | %08X | {{http://queueram.com/n64/sm64/textures/textures/font_graphics.0x%05X.png}} ", convchar, seg, offset);
85 | }
86 | }
87 | printf("|\n");
88 | }
89 | free(data);
90 | return 0;
91 | }
92 |
--------------------------------------------------------------------------------
/tools/jalfind.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #define JALFIND_VERSION "0.1"
5 |
6 | #define read_u32_be(buf) (unsigned int)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3]))
7 |
8 | static void print_usage(void)
9 | {
10 | fprintf(stderr,
11 | "jalfind [ADDRESS...]\n"
12 | "\n"
13 | "jalfind v" JALFIND_VERSION ": search for MIPS JAL, LUI/ADDIU, and direct references in a file\n"
14 | "\n"
15 | "Arguments:\n"
16 | " FILE input ROM file\n"
17 | " ADDRESS address to find references to (assumes hex)\n");
18 | }
19 |
20 | int read_file(const char *file_name, unsigned char **data)
21 | {
22 | FILE *in;
23 | unsigned char *in_buf = NULL;
24 | size_t file_size;
25 | size_t bytes_read;
26 |
27 | in = fopen(file_name, "rb");
28 | if (in == NULL) {
29 | return -1;
30 | }
31 |
32 | // determine file size
33 | fseek(in, 0, SEEK_END);
34 | file_size = ftell(in);
35 | fseek(in, 0, SEEK_SET);
36 | // allocate buffer and read entire file in
37 | in_buf = malloc(file_size);
38 | bytes_read = fread(in_buf, 1, file_size, in);
39 | if (bytes_read != file_size) {
40 | return -2;
41 | }
42 |
43 | fclose(in);
44 | *data = in_buf;
45 | return (int)bytes_read;
46 | }
47 |
48 | #define OPCODE_MASK 0xFC000000
49 | #define OPCODE_ADDIU 0x24000000
50 | #define OPCODE_JAL 0x0C000000
51 | #define OPCODE_LUI 0x3C000000
52 | #define OPCODE_ORI 0x34000000
53 | #define IMM_MASK 0x0000FFFF
54 | #define RS_MASK 0x03E00000
55 | #define RT_MASK 0x001F0000
56 |
57 | static const char * const regs[] =
58 | {
59 | "zero",
60 | "at",
61 | "v0",
62 | "v1",
63 | "a0",
64 | "a1",
65 | "a2",
66 | "a3",
67 | "t0",
68 | "t1",
69 | "t2",
70 | "t3",
71 | "t4",
72 | "t5",
73 | "t6",
74 | "t7",
75 | "s0",
76 | "s1",
77 | "s2",
78 | "s3",
79 | "s4",
80 | "s5",
81 | "s6",
82 | "s7",
83 | "t8",
84 | "t9",
85 | "k0",
86 | "k1",
87 | "gp",
88 | "sp",
89 | "s8",
90 | "ra",
91 | };
92 |
93 | void find_reference(unsigned char *data, int len, unsigned int addr)
94 | {
95 | unsigned int jal = OPCODE_JAL | ((0x0FFFFFFF & addr) >> 2);
96 | unsigned int lui_imm = addr >> 16;
97 | unsigned int addiu_imm = addr & 0xFFFF;
98 | int i, j;
99 |
100 | if (addr & 0x8000) {
101 | lui_imm++;
102 | }
103 |
104 | printf("--> Looking for %08X/%08X\n", addr, jal);
105 | for (i = 0; i < len; i += 4) {
106 | unsigned int ival = read_u32_be(&data[i]);
107 |
108 | // look for direct address
109 | if (addr == ival) {
110 | printf("%06X: %08X\n", i, ival);
111 |
112 | // find direct JAL
113 | } else if (jal == ival) {
114 | printf("%06X: %08X JAL 0x%08X\n", i, ival, addr);
115 |
116 | // look for LUI/ADDIU pairs that match the address
117 | } else if (((ival & OPCODE_MASK) == OPCODE_LUI) && ((ival & IMM_MASK) == lui_imm)) {
118 | unsigned int lui_rt = (ival & RT_MASK) >> 16;
119 | // look up to 32 instructions
120 | for (j = i + 4; j < len && j < i + 32*4; j += 4) {
121 | unsigned int jval = read_u32_be(&data[j]);
122 | if ((jval & OPCODE_MASK) == OPCODE_ADDIU) {
123 | unsigned int addiu_rs = (jval & RS_MASK) >> 21;
124 | unsigned int addiu_rt = (jval & RT_MASK) >> 16;
125 | if (addiu_rs == lui_rt) {
126 | if ((jval & IMM_MASK) == addiu_imm) {
127 | printf("%06X: %08X LUI %s, 0x%04X // %%hi(0x%08X)\n"
128 | "%06X: %08X ADDIU %s, %s, 0x%04X // %%lo(0x%08X)\n",
129 | i, ival, regs[lui_rt], lui_imm, addr,
130 | j, jval, regs[addiu_rt], regs[addiu_rs], addiu_imm, addr);
131 | }
132 | break; // stop looking for a matching ADDIU
133 | }
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
140 | int main(int argc, char *argv[])
141 | {
142 | unsigned char *data;
143 | char *fname;
144 | unsigned int addr;
145 | int len;
146 | int i;
147 |
148 | if (argc < 3) {
149 | print_usage();
150 | return 1;
151 | }
152 |
153 | fname = argv[1];
154 | len = read_file(fname, &data);
155 | if (len > 0) {
156 | for (i = 2; i < argc; i++) {
157 | addr = strtoul(argv[i], NULL, 16);
158 | find_reference(data, len, addr);
159 | }
160 | } else {
161 | fprintf(stderr, "Error opening/reading \"%s\"\n", fname);
162 | return 1;
163 | }
164 |
165 | return 0;
166 | }
167 |
--------------------------------------------------------------------------------
/tools/mk64karts.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "../libmio0.h"
6 | #include "../n64graphics.h"
7 | #include "../utils.h"
8 |
9 | #define MK64KARTS_VERSION "0.2"
10 |
11 | // first and last MIO0 blocks for kart textures
12 | #define MIO0_FIRST 0x145470
13 | #define MIO0_LAST 0x619730
14 |
15 | #define WIDTH 64
16 | #define HEIGHT 64
17 |
18 | typedef struct
19 | {
20 | char png_dir[FILENAME_MAX];
21 | char rom_filename[FILENAME_MAX];
22 | int wheel;
23 | } arg_config;
24 |
25 | // default configuration
26 | static const arg_config default_args =
27 | {
28 | "karts", // PNG directory
29 | "", // ROM filename
30 | 0, // wheel animation index
31 | };
32 |
33 | // start of wheel palette data, kart palette is +0x24200
34 | static unsigned palette_groups[] =
35 | {
36 | 0x1BBE6C, // Luigi
37 | 0x24E6A0, // Mario
38 | 0x2E5BC8, // Yoshi
39 | 0x379D38, // Peach
40 | 0x41705C, // Wario
41 | 0x4A7AC8, // Toad
42 | 0x559AE4, // DK
43 | 0x619EF8, // Bowser
44 | };
45 |
46 | static void print_usage(void)
47 | {
48 | ERROR("Usage: mk64karts [-d PNG_DIR] [-w WHEEL] [-v] MK64_ROM\n"
49 | "\n"
50 | "mk64karts v" MK64KARTS_VERSION ": MK64 kart texture dumper\n"
51 | "\n"
52 | "Optional arguments:\n"
53 | " -d PNG_DIR output directory for PNG textures (default: \"%s\")\n"
54 | " -w WHEEL wheel animation index [0-3] (default: %d)\n"
55 | " -v verbose output\n"
56 | "\n"
57 | "File arguments:\n"
58 | " MK64_ROM input MK64 ROM file\n",
59 | default_args.png_dir, default_args.wheel);
60 | exit(1);
61 | }
62 |
63 | // parse command line arguments
64 | static void parse_arguments(int argc, char *argv[], arg_config *config)
65 | {
66 | int i;
67 | int file_count = 0;
68 | if (argc < 2) {
69 | print_usage();
70 | exit(1);
71 | }
72 | for (i = 1; i < argc; i++) {
73 | if (argv[i][0] == '-') {
74 | switch (argv[i][1]) {
75 | case 'd':
76 | if (++i >= argc) {
77 | print_usage();
78 | }
79 | strcpy(config->png_dir, argv[i]);
80 | break;
81 | case 'w':
82 | if (++i >= argc) {
83 | print_usage();
84 | }
85 | config->wheel = strtol(argv[i], NULL, 0);
86 | if (config->wheel < 0 || config->wheel > 3) {
87 | print_usage();
88 | }
89 | break;
90 | case 'v':
91 | g_verbosity = 1;
92 | break;
93 | default:
94 | print_usage();
95 | break;
96 | }
97 | } else {
98 | if (file_count == 0) {
99 | strcpy(config->rom_filename, argv[i]);
100 | } else {
101 | // too many
102 | print_usage();
103 | }
104 | file_count++;
105 | }
106 | }
107 | if (file_count < 1) {
108 | print_usage();
109 | }
110 | }
111 |
112 | int main(int argc, char *argv[])
113 | {
114 | char pngfilename[FILENAME_MAX];
115 | arg_config args;
116 | char *palette;
117 | unsigned char *rom;
118 | unsigned char *inflated;
119 | rgba *imgr;
120 | int i;
121 | int kart;
122 | int cur_count;
123 |
124 | args = default_args;
125 | parse_arguments(argc, argv, &args);
126 | INFO("Arguments: \"%s\" \"%s\" %d\n", args.rom_filename, args.png_dir, args.wheel);
127 |
128 | INFO("Loading \"%s\"\n", args.rom_filename);
129 | long rom_len = read_file(args.rom_filename, &rom);
130 |
131 | if (rom_len <= 0) {
132 | ERROR("Error reading in \"%s\"\n", args.rom_filename);
133 | exit(1);
134 | }
135 | INFO("Loaded 0x%lX bytes from \"%s\"\n", rom_len, args.rom_filename);
136 |
137 | // ensure PNG directory exists
138 | make_dir(args.png_dir);
139 |
140 | // prepare palette - wheels are from index 0xC0-0xFF (offset 0x180-0x1FF)
141 | kart = -1;
142 | palette = malloc(2*256);
143 | inflated = malloc(2*WIDTH*HEIGHT);
144 | cur_count = 0;
145 | for (i = MIO0_FIRST; i <= MIO0_LAST; i += 4) {
146 | if (!memcmp(&rom[i], "MIO0", 4)) {
147 | unsigned int end;
148 | if (kart < 0 || i > palette_groups[kart]) {
149 | kart++;
150 | cur_count = 0;
151 | memcpy(palette, &rom[palette_groups[kart] + 0x24200], 0x180);
152 | }
153 | unsigned wheel_offset = palette_groups[kart] + 0x80*(4*cur_count + args.wheel);
154 | memcpy(&palette[0x180], &rom[wheel_offset], 0x80);
155 | INFO("Inflating MIO0 block 0x%X\n", i);
156 | int len = mio0_decode(&rom[i], inflated, &end);
157 | if (len != WIDTH*HEIGHT) {
158 | ERROR("%X: %X > %X\n", i, len, WIDTH*HEIGHT);
159 | exit(1);
160 | }
161 | sprintf(pngfilename, "%s/%X.png", args.png_dir, i);
162 | INFO("Converting 0x%X bytes from raw CI to RGBA\n", len);
163 | imgr = rawci2rgba(inflated, palette, WIDTH, HEIGHT, 16);
164 | INFO("Writing out PNG \"%s\"\n", pngfilename);
165 | rgba2png(imgr, WIDTH, HEIGHT, pngfilename);
166 |
167 | i += end - 4;
168 | i &= ~(0x3); // ensure still aligned
169 | cur_count++;
170 | }
171 | }
172 |
173 | free(inflated);
174 | free(palette);
175 |
176 | return 0;
177 | }
178 |
--------------------------------------------------------------------------------
/tools/montage.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "../config.h"
7 | #include "../utils.h"
8 |
9 | #define DEFAULT_CONFIG "../configs/sm64.u.config"
10 |
11 | typedef struct
12 | {
13 | unsigned int rom;
14 | unsigned int ext;
15 | } sm64_offset;
16 |
17 | // extended ROM mapping based on output from sm64extend
18 | static const sm64_offset mapping[] =
19 | {
20 | {0x00108A40, 0x00803156}, // 0x00800000}, // 0081BB64 as raw data with a MIO0 header
21 | {0x00114750, 0x00823B64}, // 00858EDC as raw data
22 | {0x0012A7E0, 0x00860EDC}, // 0087623C as raw data
23 | {0x00132C60, 0x0087E23C}, // 008843BC as raw data
24 | {0x00134D20, 0x0088C3BC}, // 0089D45C as raw data
25 | {0x0013B910, 0x008A545C}, // 008B918C as raw data
26 | {0x00145E90, 0x008C118C}, // 008D57DC as raw data
27 | {0x001521D0, 0x008DD7DC}, // 008F3894 as raw data
28 | {0x00160670, 0x008FB894}, // 009089C4 as raw data
29 | {0x00165A50, 0x009109C4}, // 00913E8C as raw data
30 | {0x00166C60, 0x0091BE8C}, // 0092C004 as raw data
31 | {0x0016D870, 0x00934004}, // 00958204 as raw data
32 | {0x00180BB0, 0x00960204}, // 009770C4 as raw data
33 | {0x00188440, 0x0097F0C4}, // 009E1FD4 as raw data
34 | {0x001B9CC0, 0x009E9FD4}, // 00A01934 as raw data
35 | {0x001C4230, 0x00A09934}, // 00A2EABC as raw data
36 | {0x001D8310, 0x00A36ABC}, // 00A4E934 as raw data
37 | {0x001E51F0, 0x00A56934}, // 00A5C7AC as raw data
38 | {0x001E7EE0, 0x00A647AC}, // 00A7981C as raw data
39 | {0x001F2200, 0x00A8181C}, // 00AAA40C as raw data
40 | {0x00201410, 0x00AB240C}, // 00AE5714 as raw data
41 | {0x0026A3A0, 0x00AED714}, // 00AFA054 as raw data
42 | {0x0026F420, 0x00B02054}, // 00B085FC as raw data
43 | {0x002708C0, 0x00B112CD}, // 0x00B105FC}, // 00B178B5 as raw data with a MIO0 header
44 | {0x002A65B0, 0x00B1F8B5}, // 00B2D715 as raw data
45 | {0x002AC6B0, 0x00B35715}, // 00B55855 as raw data
46 | {0x002B8F10, 0x00B5D855}, // 00B7D995 as raw data
47 | {0x002C73D0, 0x00B85995}, // 00B9A2D5 as raw data
48 | {0x002D0040, 0x00BA22D5}, // 00BBAC15 as raw data
49 | {0x002D64F0, 0x00BC2C15}, // 00BE2D55 as raw data
50 | {0x002E7880, 0x00BEAD55}, // 00C0AE95 as raw data
51 | {0x002F14E0, 0x00C12E95}, // 00C32FD5 as raw data
52 | {0x002FB1B0, 0x00C3AFD5}, // 00C4F915 as raw data
53 | {0x00301CD0, 0x00C57915}, // 00C77A55 as raw data
54 | {0x0030CEC0, 0x00C7FA55}, // 00C9FB95 as raw data
55 | {0x0031E1D0, 0x00CA93A9}, // 0x00CA7B95}, // 00CB53A9 as raw data with a MIO0 header
56 | {0x00326E40, 0x00CBECBD}, // 0x00CBD3A9}, // 00CCB4BD as raw data with a MIO0 header
57 | {0x0032D070, 0x00CD4BD1}, // 0x00CD34BD}, // 00CE03D1 as raw data with a MIO0 header
58 | {0x00334B30, 0x00CE9CE5}, // 0x00CE83D1}, // 00CF64E5 as raw data with a MIO0 header
59 | {0x0033D710, 0x00CFF5F9}, // 0x00CFE4E5}, // 00D07DF9 as raw data with a MIO0 header
60 | {0x00341140, 0x00D1120D}, // 0x00D0FDF9}, // 00D1B20D as raw data with a MIO0 header
61 | {0x00347A50, 0x00D24B21}, // 0x00D2320D}, // 00D31321 as raw data with a MIO0 header
62 | {0x0034E760, 0x00D3A4B5}, // 0x00D39321}, // 00D430B5 as raw data with a MIO0 header
63 | {0x00351960, 0x00D4C9C9}, // 0x00D4B0B5}, // 00D591C9 as raw data with a MIO0 header
64 | {0x00357350, 0x00D629DD}, // 0x00D611C9}, // 00D6E9DD as raw data with a MIO0 header
65 | {0x0035ED10, 0x00D78271}, // 0x00D769DD}, // 00D84671 as raw data with a MIO0 header
66 | {0x00365980, 0x00D8DF85}, // 0x00D8C671}, // 00D9A785 as raw data with a MIO0 header
67 | {0x0036F530, 0x00DA2785}, // 00DA951D as raw data
68 | {0x00371C40, 0x00DB151D}, // 00DD8361 as raw data
69 | {0x00383950, 0x00DE0361}, // 00E03B07 as raw data
70 | {0x00396340, 0x00E0BB07}, // 00E84C1F as raw data
71 | {0x003D0DC0, 0x00E8CC1F}, // 00EB8587 as raw data
72 | {0x003E76B0, 0x00EC0587}, // 00EE8E37 as raw data
73 | {0x003FC2B0, 0x00EF0E37}, // 00F025F9 as raw data
74 | {0x00405FB0, 0x00F0A5F9}, // 00F1A081 as raw data
75 | {0x0040ED70, 0x00F22081}, // 00F3A809 as raw data
76 | {0x0041A760, 0x00F42809}, // 00F53BB5 as raw data
77 | {0x004246D0, 0x00F5BBB5}, // 00F69F71 as raw data
78 | {0x0042CF20, 0x00F71F71}, // 00F88991 as raw data
79 | {0x00437870, 0x00F90991}, // 00FBF807 as raw data
80 | {0x0044ABC0, 0x00FC7807}, // 00FD907F as raw data
81 | {0x00454E00, 0x00FE107F}, // 00FF0EAF as raw data
82 | {0x0045C600, 0x00FF8EAF}, // 01003B77 as raw data
83 | {0x004614D0, 0x0100BB77}, // 0102177F as raw data
84 | {0x0046B090, 0x0102977F}, // 0102CAAF as raw data
85 | {0x0046C3A0, 0x01034AAF}, // 010502A3 as raw data
86 | {0x004784A0, 0x010582A3}, // 01080B73 as raw data
87 | {0x0048D930, 0x01088B73}, // 01098883 as raw data
88 | {0x00496090, 0x010A0883}, // 010B269B as raw data
89 | {0x0049E710, 0x010BA69B}, // 010E19EB as raw data
90 | {0x004AC570, 0x010E99EB}, // 010F0867 as raw data
91 | {0x004AF930, 0x010F8867}, // 01109903 as raw data
92 | {0x004B80D0, 0x01111903}, // 0111D8AB as raw data
93 | {0x004BEC30, 0x011258AB}, // 0112E271 as raw data
94 | {0x004C2920, 0x01136271}, // 01138D39 as raw data
95 | {0x004C4320, 0x01140D39}, // 011544E7 as raw data
96 | {0x004CDBD0, 0x0115C4E7}, // 0115E087 as raw data
97 | {0x004CEC00, 0x01166087}, // 0116B143 as raw data
98 | {0x004D1910, 0x01173143}, // 011A35B7 as raw data
99 | };
100 |
101 | static unsigned int map(unsigned int rom)
102 | {
103 | unsigned i;
104 | for (i = 0; i < DIM(mapping); i++) {
105 | if (mapping[i].rom == rom) {
106 | return mapping[i].ext;
107 | }
108 | }
109 | return 0;
110 | }
111 |
112 | int main(int argc, char *argv[])
113 | {
114 | rom_config config;
115 | FILE *out;
116 | int i;
117 | unsigned int w, h;
118 | unsigned int offset;
119 |
120 | // load defaults and parse arguments
121 | out = stdout;
122 |
123 | // parse config file
124 | INFO("Parsing config file '%s'\n", DEFAULT_CONFIG);
125 | if (parse_config_file(DEFAULT_CONFIG, &config)) {
126 | ERROR("Error parsing config file '%s'\n", DEFAULT_CONFIG);
127 | return 1;
128 | }
129 |
130 | fprintf(out, "mkdir -p montages\n\n");
131 |
132 | for (i = 0; i < config.section_count; i++) {
133 | split_section *sec = &config.sections[i];
134 | if (sec->type == TYPE_MIO0) {
135 | if (sec->extra) {
136 | texture *texts = sec->extra;
137 | int t;
138 | fprintf(out, "montage \\\n");
139 | for (t = 0; t < sec->extra_len; t++) {
140 | char name[256];
141 | char format[8];
142 | w = texts[t].width;
143 | h = texts[t].height;
144 | offset = texts[t].offset;
145 | switch (texts[t].format) {
146 | case FORMAT_IA:
147 | sprintf(name, "%s.0x%05X.ia%d.png", sec->label, offset, texts[t].depth);
148 | sprintf(format, "ia%d", texts[t].depth);
149 | break;
150 | case FORMAT_RGBA:
151 | sprintf(name, "%s.0x%05X.png", sec->label, offset);
152 | sprintf(format, "rgba");
153 | break;
154 | case FORMAT_SKYBOX:
155 | sprintf(name, "%s.0x%05X.skybox.png", sec->label, offset);
156 | sprintf(format, "sky");
157 | break;
158 | default:
159 | continue;
160 | }
161 | fprintf(out, " -label '%05X\\n%s\\n%dx%d' ../sm64.split/textures/%s \\\n", offset, format, w, h, name);
162 | }
163 | int x = MIN(10, sec->extra_len);
164 | int y = MAX(1, (sec->extra_len + 9) / 10);
165 | fprintf(out, " -tile %dx%d -background none -geometry '64x64+2+2>' montages/%s.png\n\n",
166 | x, y, sec->label);
167 | fprintf(out, "pngcrush -ow montages/%s.png\n\n", sec->label);
168 | }
169 | }
170 | }
171 |
172 | fprintf(out, "cat << EOF > index.html\n");
173 | fprintf(out, "\n"
174 | "\n"
175 | "%s Textures\n", config.name);
176 | fprintf(out,
177 | "\n");
236 | fprintf(out, "\n");
237 | fprintf(out, "\n");
238 | fprintf(out, "\n");
239 | fprintf(out, "ROM MIO0 | Extended ROM | Textures and offset in block |
\n");
240 | for (i = 0; i < config.section_count; i++) {
241 | split_section *sec = &config.sections[i];
242 | if (sec->type == TYPE_MIO0) {
243 | if (sec->extra) {
244 | fprintf(out, "%X | %X |  |
\n",
245 | sec->start, map(sec->start), sec->label);
246 | }
247 | }
248 | }
249 | fprintf(out, "
\n");
250 | fprintf(out, "\n");
251 | fprintf(out, "\n");
252 | fprintf(out, "\n");
253 | fprintf(out, "EOF\n");
254 |
255 | return 0;
256 | }
257 |
258 |
--------------------------------------------------------------------------------
/tools/n64ci.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "../n64graphics.h"
6 | #include "../utils.h"
7 |
8 | #define N64CI_VERSION "0.1"
9 |
10 | #define SCALE_8_5(VAL_) (((VAL_) * 0x1F) / 0xFF)
11 |
12 | typedef struct
13 | {
14 | char pal_filename[FILENAME_MAX];
15 | unsigned pal_entries;
16 | char **input_files;
17 | unsigned input_count;
18 | } arg_config;
19 |
20 | typedef struct
21 | {
22 | rgba *data;
23 | unsigned char *ci;
24 | int width;
25 | int height;
26 | } image_t;
27 |
28 | typedef struct
29 | {
30 | unsigned short data[256];
31 | unsigned max; // max number of entries
32 | unsigned used;
33 | } palette_t;
34 |
35 | // default configuration
36 | static const arg_config default_args =
37 | {
38 | "palette.bin", // output palette filename
39 | 256, // number of palette entries
40 | NULL, // array of input file names
41 | 0 // count of input files
42 | };
43 |
44 | // find index of palette color
45 | // return -1 if not found
46 | static int pal_find_color(palette_t *pal, unsigned short col)
47 | {
48 | unsigned i;
49 | for (i = 0; i < pal->used; i++) {
50 | if (pal->data[i] == col) {
51 | return i;
52 | }
53 | }
54 | return -1;
55 | }
56 |
57 | // find color in palette, or add if not there
58 | // returns palette index entered or -1 if palette full
59 | static int pal_add_color(palette_t *pal, rgba *col)
60 | {
61 | unsigned short rgba16;
62 | char r, g, b, a;
63 | int idx;
64 | r = SCALE_8_5(col->red);
65 | g = SCALE_8_5(col->green);
66 | b = SCALE_8_5(col->blue);
67 | a = col->alpha ? 0x1 : 0x0;
68 | rgba16 = (((r << 3) | (g >> 2)) << 8) | ((g & 0x3) << 6) | (b << 1) | a;
69 | idx = pal_find_color(pal, rgba16);
70 | if (idx < 0) {
71 | if (pal->used == pal->max) {
72 | ERROR("Error: trying to use more than %d\n", pal->max);
73 | } else {
74 | idx = pal->used;
75 | pal->data[pal->used] = rgba16;
76 | pal->used++;
77 | }
78 | }
79 | return idx;
80 | }
81 |
82 | static void print_usage(void)
83 | {
84 | ERROR("Usage: n64ci [-e PAL_ENTIRES] [-p PAL_FILE] [-v] [PNG images]\n"
85 | "\n"
86 | "n64ci v" N64CI_VERSION ": N64 CI image encoder\n"
87 | "\n"
88 | "Optional arguments:\n"
89 | " -e PAL_ENTRIES number of palette entires (default: %d)\n"
90 | " -p PAL_FILE output palette file (default: \"%s\")\n"
91 | " -v verbose progress output\n"
92 | "\n"
93 | "File arguments:\n"
94 | " PNG images input PNG images to encode\n",
95 | default_args.pal_entries, default_args.pal_filename);
96 | exit(1);
97 | }
98 |
99 | // parse command line arguments
100 | static void parse_arguments(int argc, char *argv[], arg_config *config)
101 | {
102 | int i;
103 | // allocate max input files
104 | config->input_files = malloc(sizeof(config->input_files) * argc);
105 | config->input_count = 0;
106 | if (argc < 2) {
107 | print_usage();
108 | exit(1);
109 | }
110 | for (i = 1; i < argc; i++) {
111 | if (argv[i][0] == '-') {
112 | switch (argv[i][1]) {
113 | case 'e':
114 | if (++i >= argc) {
115 | print_usage();
116 | }
117 | config->pal_entries = strtoul(argv[i], NULL, 0);
118 | break;
119 | case 'p':
120 | if (++i >= argc) {
121 | print_usage();
122 | }
123 | strcpy(config->pal_filename, argv[i]);
124 | break;
125 | case 'v':
126 | g_verbosity = 1;
127 | break;
128 | default:
129 | print_usage();
130 | break;
131 | }
132 | } else {
133 | // assume input filename
134 | config->input_files[config->input_count] = argv[i];
135 | config->input_count++;
136 | }
137 | }
138 | if (config->input_count < 1) {
139 | print_usage();
140 | }
141 | }
142 |
143 | int main(int argc, char *argv[])
144 | {
145 | char bin_filename[FILENAME_MAX];
146 | unsigned char *palette_bin;
147 | arg_config config;
148 | palette_t palette;
149 | image_t *images;
150 | unsigned pal_length;
151 | unsigned i;
152 | int x, y;
153 |
154 | config = default_args;
155 | parse_arguments(argc, argv, &config);
156 | INFO("Arguments: \"%s\" %d %d\n", config.pal_filename, config.pal_entries, config.input_count);
157 |
158 | images = malloc(sizeof(*images) * config.input_count);
159 |
160 | // load all images
161 | for (i = 0; i < config.input_count; i++) {
162 | images[i].data = pngfile2rgba(config.input_files[i], &images[i].width, &images[i].height);
163 | }
164 |
165 | // assign colors to palette
166 | palette.max = config.pal_entries;
167 | palette.used = 0;
168 | for (i = 0; i < config.input_count; i++) {
169 | images[i].ci = malloc(sizeof(*images[i].ci) * images[i].width * images[i].height);
170 | for (x = 0; x < images[i].width; x++) {
171 | for (y = 0; y < images[i].height; y++) {
172 | unsigned img_idx = y * images[i].width + x;
173 | int pal_idx = pal_add_color(&palette, &images[i].data[img_idx]);
174 | if (pal_idx < 0) {
175 | ERROR("Error adding color @ (%d, %d): %d (used: %u)\n", x, y, pal_idx, palette.used);
176 | exit(1);
177 | } else {
178 | images[i].ci[img_idx] = (unsigned char)pal_idx;
179 | }
180 | }
181 | }
182 | }
183 |
184 | // output bin files
185 | for (i = 0; i < config.input_count; i++) {
186 | generate_filename(config.input_files[i], bin_filename, "bin");
187 | write_file(bin_filename, images[i].ci, images[i].width * images[i].height);
188 | }
189 |
190 | // output palette file
191 | pal_length = config.pal_entries*2;
192 | // unused entries set to 0xFFFF
193 | palette_bin = malloc(pal_length);
194 | memset(palette_bin, 0xFF, pal_length);
195 | for (i = 0; i < palette.used; i++) {
196 | write_u16_be(&palette_bin[i*2], palette.data[i]);
197 | }
198 | write_file(config.pal_filename, palette_bin, pal_length);
199 |
200 | ERROR("Used: %d\n", palette.used);
201 |
202 | free(config.input_files);
203 | free(palette_bin);
204 | free(images);
205 |
206 | return 0;
207 | }
208 |
--------------------------------------------------------------------------------
/tools/sm64collision.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "../utils.h"
6 |
7 | #define SM64COLLISION_VERSION "0.1"
8 |
9 | typedef struct
10 | {
11 | char *in_filename;
12 | char *out_filename;
13 | char *name;
14 | unsigned offset;
15 | unsigned scale;
16 | short x;
17 | short y;
18 | short z;
19 | } arg_config;
20 |
21 | typedef struct
22 | {
23 | short x, y, z;
24 | } vertex;
25 |
26 | typedef struct
27 | {
28 | unsigned vidx[3];
29 | } triangle;
30 |
31 | typedef struct
32 | {
33 | vertex *verts;
34 | unsigned vcount;
35 | triangle *tris;
36 | unsigned tcount;
37 | } collision;
38 |
39 | // default configuration
40 | static const arg_config default_config =
41 | {
42 | NULL, // input filename
43 | NULL, // output filename
44 | "collision", // model name
45 | 0xF3A0, // offset for castle grounds
46 | 4096, // scale for OBJ export
47 | 0, // shift X
48 | 0, // shift Y
49 | 0, // shift Z
50 | };
51 |
52 | static void print_usage(void)
53 | {
54 | ERROR("Usage: sm64collision [-o OFFSET] [-n NAME] [-s SCALE] [-x X] [-y Y] [-z Z] [-v] FILE [OUT_FILE]\n"
55 | "\n"
56 | "sm64collision v" SM64COLLISION_VERSION ": Super Mario 64 collision decoder\n"
57 | "\n"
58 | "Optional arguments:\n"
59 | " -o OFFSET offset to pull collision data from in bytes (default: 0x%X)\n"
60 | " -n NAME name specified in obj model (default: %s)\n"
61 | " -s SCALE scale obj data by this amount (default: %d)\n"
62 | " -x X amount to shift X values (default: %d)\n"
63 | " -y Y amount to shift Y values (default: %d)\n"
64 | " -z Z amount to shift Z values (default: %d)\n"
65 | " -v verbose progress output\n"
66 | "\n"
67 | "File arguments:\n"
68 | " FILE input binary file\n"
69 | " OUT_FILE output OBJ file (default: no obj output)\n",
70 | default_config.offset, default_config.name, default_config.scale,
71 | default_config.x, default_config.y, default_config.z);
72 | exit(EXIT_FAILURE);
73 | }
74 |
75 | // parse command line arguments
76 | static void parse_arguments(int argc, char *argv[], arg_config *args)
77 | {
78 | int i;
79 | int file_count = 0;
80 | if (argc < 2) {
81 | print_usage();
82 | }
83 | for (i = 1; i < argc; i++) {
84 | if (argv[i][0] == '-') {
85 | switch (argv[i][1]) {
86 | case 'o':
87 | if (++i >= argc) {
88 | print_usage();
89 | }
90 | args->offset = strtoul(argv[i], NULL, 0);
91 | break;
92 | case 'n':
93 | if (++i >= argc) {
94 | print_usage();
95 | }
96 | args->name = argv[i];
97 | break;
98 | case 's':
99 | if (++i >= argc) {
100 | print_usage();
101 | }
102 | args->scale = strtol(argv[i], NULL, 0);
103 | break;
104 | case 'x':
105 | if (++i >= argc) {
106 | print_usage();
107 | }
108 | args->x = strtol(argv[i], NULL, 0);
109 | break;
110 | case 'y':
111 | if (++i >= argc) {
112 | print_usage();
113 | }
114 | args->y = strtol(argv[i], NULL, 0);
115 | break;
116 | case 'z':
117 | if (++i >= argc) {
118 | print_usage();
119 | }
120 | args->z = strtol(argv[i], NULL, 0);
121 | break;
122 | case 'v':
123 | g_verbosity = 1;
124 | break;
125 | default:
126 | print_usage();
127 | break;
128 | }
129 | } else {
130 | switch (file_count) {
131 | case 0:
132 | args->in_filename = argv[i];
133 | break;
134 | case 1:
135 | args->out_filename = argv[i];
136 | break;
137 | default: // too many
138 | print_usage();
139 | break;
140 | }
141 | file_count++;
142 | }
143 | }
144 | if (file_count < 1) {
145 | print_usage();
146 | }
147 | }
148 |
149 | void decode_collision(unsigned char *data, collision *col)
150 | {
151 | unsigned vcount;
152 | unsigned tcount;
153 | unsigned cur_tcount;
154 | unsigned offset;
155 | unsigned terrain;
156 | unsigned v_per_t;
157 | unsigned processing;
158 | unsigned i;
159 | if (data[0] != 0x00 || data[1] != 0x40) {
160 | ERROR("Unknown data: %08X\n", read_u32_be(data));
161 | return;
162 | }
163 | vcount = read_u16_be(&data[2]);
164 | INFO("Loading %u vertices\n", vcount);
165 | col->verts = malloc(vcount * sizeof(*col->verts));
166 | // load vetices
167 | offset = 4;
168 | for (i = 0; i < vcount; i++) {
169 | col->verts[i].x = read_s16_be(&data[offset + i*6]);
170 | col->verts[i].y = read_s16_be(&data[offset + i*6+2]);
171 | col->verts[i].z = read_s16_be(&data[offset + i*6+4]);
172 | }
173 | offset += vcount*6;
174 | tcount = 0;
175 | col->tris = NULL;
176 | processing = 1;
177 | while (processing) {
178 | terrain = read_u16_be(&data[offset]);
179 | cur_tcount = read_u16_be(&data[offset+2]);
180 | if (terrain == 0x41 || terrain > 0xFF) {
181 | ERROR("terrain: %X, tcount: %X\n", terrain, cur_tcount);
182 | processing = 0;
183 | break;
184 | }
185 | switch (terrain) {
186 | case 0x0E:
187 | case 0x2C:
188 | case 0x24:
189 | case 0x25:
190 | case 0x27:
191 | case 0x2D:
192 | v_per_t = 4;
193 | break;
194 | default:
195 | v_per_t = 3;
196 | break;
197 | }
198 | INFO("Loading %u triangles of terrain %X\n", cur_tcount, terrain);
199 | col->tris = realloc(col->tris, (tcount + cur_tcount) * sizeof(*col->tris));
200 | // load triangles
201 | offset += 4;
202 | for (i = 0; i < cur_tcount; i++) {
203 | col->tris[tcount+i].vidx[0] = read_u16_be(&data[offset + i*v_per_t*2]);
204 | col->tris[tcount+i].vidx[1] = read_u16_be(&data[offset + i*v_per_t*2+2]);
205 | col->tris[tcount+i].vidx[2] = read_u16_be(&data[offset + i*v_per_t*2+4]);
206 | }
207 | tcount += cur_tcount;
208 | offset += cur_tcount*v_per_t*2;
209 | }
210 | col->vcount = vcount;
211 | col->tcount = tcount;
212 | }
213 |
214 | static void generate_obj(char *filename, char *name, collision *col, unsigned scale)
215 | {
216 | FILE *out;
217 | unsigned i;
218 |
219 | out = fopen(filename, "w");
220 | if (out == NULL) {
221 | ERROR("Error opening %s\n", filename);
222 | exit(EXIT_FAILURE);
223 | }
224 |
225 | fprintf(out, "g %s\n", name);
226 |
227 | for (i = 0; i < col->vcount; i++) {
228 | float x, y, z;
229 | x = (float)col->verts[i].x / (float)scale;
230 | y = (float)col->verts[i].y / (float)scale;
231 | z = (float)col->verts[i].z / (float)scale;
232 | fprintf(out, "v %f %f %f\n", x, y, z);
233 | }
234 |
235 | for (i = 0; i < col->tcount; i++) {
236 | fprintf(out, "f %d %d %d\n", col->tris[i].vidx[0]+1, col->tris[i].vidx[1]+1, col->tris[i].vidx[2]+1);
237 | }
238 |
239 | fclose(out);
240 | }
241 |
242 | int main(int argc, char *argv[])
243 | {
244 | arg_config config;
245 | collision col;
246 | unsigned char *in_buf = NULL;
247 | long in_size;
248 | unsigned i;
249 |
250 | // get configuration from arguments
251 | config = default_config;
252 | parse_arguments(argc, argv, &config);
253 |
254 | // read input file into memory
255 | in_size = read_file(config.in_filename, &in_buf);
256 | if (in_size <= 0) {
257 | ERROR("Error reading input file \"%s\"\n", config.in_filename);
258 | exit(EXIT_FAILURE);
259 | }
260 |
261 | // decode collision vertices and triangles
262 | decode_collision(&in_buf[config.offset], &col);
263 |
264 | ERROR("Read: %d vertices, %d triangles\n", col.vcount, col.tcount);
265 | // output obj
266 | if (config.out_filename != NULL) {
267 | INFO("Generating OBJ file \"%s\"\n", config.out_filename);
268 | generate_obj(config.out_filename, config.name, &col, config.scale);
269 | }
270 |
271 | // if shifting values
272 | if (config.x || config.y || config.z) {
273 | INFO("Shifting vertices by: {%d %d %d}\n", config.x, config.y, config.z);
274 | for (i = 0; i < col.vcount; i++) {
275 | col.verts[i].x += config.x;
276 | col.verts[i].y += config.y;
277 | col.verts[i].z += config.z;
278 | }
279 | for (i = 0; i < col.vcount; i++) {
280 | write_u16_be(&in_buf[config.offset+4+i*6], col.verts[i].x);
281 | write_u16_be(&in_buf[config.offset+4+i*6+2], col.verts[i].y);
282 | write_u16_be(&in_buf[config.offset+4+i*6+4], col.verts[i].z);
283 | }
284 | write_file(config.in_filename, in_buf, in_size);
285 | }
286 |
287 | // cleanup
288 | free(in_buf);
289 |
290 | return EXIT_SUCCESS;
291 | }
292 |
--------------------------------------------------------------------------------
/tools/sm64text.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #define SM64TEXT_VERSION "0.2"
9 |
10 | #define COUNT_OF(ARR) (sizeof(ARR)/sizeof(ARR[0]))
11 |
12 | typedef struct {
13 | enum {REGION_U, REGION_J} reg;
14 | enum {CONVERT_BYTES, CONVERT_TEXT, DUMP_TABLE} conv;
15 | union {
16 | uint8_t *bytes;
17 | char *text;
18 | };
19 | size_t length;
20 | } config;
21 |
22 | static const config default_config = {
23 | .reg = REGION_J,
24 | .conv = CONVERT_BYTES,
25 | .bytes = NULL,
26 | .length = 0,
27 | };
28 |
29 | typedef struct {
30 | uint8_t bytes[2];
31 | size_t blen;
32 | char *text;
33 | } mapping;
34 |
35 | const uint8_t sm64_string_terminator = 0xFF;
36 |
37 | const mapping j_mapping[] = {
38 | {{0x00}, 1, "0"},
39 | {{0x01}, 1, "1"},
40 | {{0x02}, 1, "2"},
41 | {{0x03}, 1, "3"},
42 | {{0x04}, 1, "4"},
43 | {{0x05}, 1, "5"},
44 | {{0x06}, 1, "6"},
45 | {{0x07}, 1, "7"},
46 | {{0x08}, 1, "8"},
47 | {{0x09}, 1, "9"},
48 | {{0x0A}, 1, "A"},
49 | {{0x0B}, 1, "B"},
50 | {{0x0C}, 1, "C"},
51 | {{0x0D}, 1, "D"},
52 | {{0x0E}, 1, "E"},
53 | {{0x0F}, 1, "F"},
54 | {{0x10}, 1, "G"},
55 | {{0x11}, 1, "H"},
56 | {{0x12}, 1, "I"},
57 | {{0x13}, 1, "J"},
58 | {{0x14}, 1, "K"},
59 | {{0x15}, 1, "L"},
60 | {{0x16}, 1, "M"},
61 | {{0x17}, 1, "N"},
62 | {{0x18}, 1, "O"},
63 | {{0x19}, 1, "P"},
64 | {{0x1A}, 1, "Q"},
65 | {{0x1B}, 1, "R"},
66 | {{0x1C}, 1, "S"},
67 | {{0x1D}, 1, "T"},
68 | {{0x1E}, 1, "U"},
69 | {{0x1F}, 1, "V"},
70 | {{0x20}, 1, "W"},
71 | {{0x21}, 1, "X"},
72 | {{0x22}, 1, "Y"},
73 | {{0x23}, 1, "Z"},
74 | {{0x40}, 1, "あ"},
75 | {{0x41}, 1, "い"},
76 | {{0x42}, 1, "う"},
77 | {{0x43}, 1, "え"},
78 | {{0x44}, 1, "お"},
79 | {{0x45}, 1, "か"},
80 | {{0x46}, 1, "き"},
81 | {{0x47}, 1, "く"},
82 | {{0x48}, 1, "け"},
83 | {{0x49}, 1, "こ"},
84 | {{0x4A}, 1, "さ"},
85 | {{0x4B}, 1, "し"},
86 | {{0x4C}, 1, "す"},
87 | {{0x4D}, 1, "せ"},
88 | {{0x4E}, 1, "そ"},
89 | {{0x4F}, 1, "た"},
90 | {{0x50}, 1, "ち"},
91 | {{0x51}, 1, "つ"},
92 | {{0x52}, 1, "て"},
93 | {{0x53}, 1, "と"},
94 | {{0x54}, 1, "な"},
95 | {{0x55}, 1, "に"},
96 | {{0x56}, 1, "ぬ"},
97 | {{0x57}, 1, "ね"},
98 | {{0x58}, 1, "の"},
99 | {{0x59}, 1, "は"},
100 | {{0x5A}, 1, "ひ"},
101 | {{0x5B}, 1, "ふ"},
102 | {{0x5C}, 1, "へ"},
103 | {{0x5D}, 1, "ほ"},
104 | {{0x5E}, 1, "ま"},
105 | {{0x5F}, 1, "み"},
106 | {{0x60}, 1, "む"},
107 | {{0x61}, 1, "め"},
108 | {{0x62}, 1, "も"},
109 | {{0x63}, 1, "や"},
110 | {{0x64}, 1, "ゆ"},
111 | {{0x65}, 1, "よ"},
112 | {{0x66}, 1, "ら"},
113 | {{0x67}, 1, "り"},
114 | {{0x68}, 1, "る"},
115 | {{0x69}, 1, "れ"},
116 | {{0x6A}, 1, "ろ"},
117 | {{0x6B}, 1, "わ"},
118 | {{0x6C}, 1, "を"},
119 | {{0x6D}, 1, "ん"},
120 | {{0x6E}, 1, "。"},
121 | {{0x6F}, 1, ","},
122 | {{0x70}, 1, "ア"},
123 | {{0x71}, 1, "イ"},
124 | {{0x72}, 1, "ウ"},
125 | {{0x73}, 1, "エ"},
126 | {{0x74}, 1, "オ"},
127 | {{0x75}, 1, "カ"},
128 | {{0x76}, 1, "キ"},
129 | {{0x77}, 1, "ク"},
130 | {{0x78}, 1, "ケ"},
131 | {{0x79}, 1, "コ"},
132 | {{0x7A}, 1, "サ"},
133 | {{0x7B}, 1, "シ"},
134 | {{0x7C}, 1, "ス"},
135 | {{0x7D}, 1, "セ"},
136 | {{0x7E}, 1, "ソ"},
137 | {{0x7F}, 1, "タ"},
138 | {{0x80}, 1, "チ"},
139 | {{0x81}, 1, "ツ"},
140 | {{0x82}, 1, "テ"},
141 | {{0x83}, 1, "ト"},
142 | {{0x84}, 1, "ナ"},
143 | {{0x85}, 1, "ニ"},
144 | {{0x86}, 1, "ヌ"},
145 | {{0x87}, 1, "ネ"},
146 | {{0x88}, 1, "ノ"},
147 | {{0x89}, 1, "ハ"},
148 | {{0x8A}, 1, "ヒ"},
149 | {{0x8B}, 1, "フ"},
150 | {{0x8C}, 1, "ヘ"},
151 | {{0x8D}, 1, "ホ"},
152 | {{0x8E}, 1, "マ"},
153 | {{0x8F}, 1, "ミ"},
154 | {{0x90}, 1, "ム"},
155 | {{0x91}, 1, "メ"},
156 | {{0x92}, 1, "モ"},
157 | {{0x93}, 1, "ヤ"},
158 | {{0x94}, 1, "ユ"},
159 | {{0x95}, 1, "ヨ"},
160 | {{0x96}, 1, "ラ"},
161 | {{0x97}, 1, "リ"},
162 | {{0x98}, 1, "ル"},
163 | {{0x99}, 1, "レ"},
164 | {{0x9A}, 1, "ロ"},
165 | {{0x9B}, 1, "ワ"},
166 | {{0x9D}, 1, "ン"},
167 | {{0x9E}, 1, " "},
168 | {{0x9F}, 1, "ー"},
169 | {{0xA0}, 1, "ぇ"},
170 | {{0xA1}, 1, "っ"},
171 | {{0xA2}, 1, "ゃ"},
172 | {{0xA3}, 1, "ゅ"},
173 | {{0xA4}, 1, "ょ"},
174 | {{0xA5}, 1, "ぁ"},
175 | {{0xA6}, 1, "ぃ"},
176 | {{0xA7}, 1, "ぅ"},
177 | {{0xA8}, 1, "ぉ"},
178 | {{0xD0}, 1, "ェ"},
179 | {{0xD1}, 1, "ッ"},
180 | {{0xD2}, 1, "ャ"},
181 | {{0xD3}, 1, "ュ"},
182 | {{0xD4}, 1, "ョ"},
183 | {{0xD5}, 1, "ァ"},
184 | {{0xD6}, 1, "ィ"},
185 | {{0xD7}, 1, "ゥ"},
186 | {{0xD8}, 1, "ォ"},
187 | {{0xE0}, 1, "@"},
188 | {{0xE1}, 1, "("},
189 | {{0xE2}, 1, ")("},
190 | {{0xE3}, 1, ")"},
191 | {{0xE4}, 1, "<->"},
192 | {{0xF2}, 1, "!"},
193 | {{0xF3}, 1, "%"},
194 | {{0xF4}, 1, "?"},
195 | {{0xF5}, 1, "『"},
196 | {{0xF6}, 1, "』"},
197 | {{0xF7}, 1, "~"},
198 | {{0xF8}, 1, "…"},
199 | {{0xF9}, 1, "$"},
200 | {{0xFA}, 1, "*"},
201 | {{0xFB}, 1, "x"},
202 | {{0xFC}, 1, "・"},
203 | {{0xFD}, 1, "#"},
204 | {{0xFE}, 1, "\n"},
205 | {{0xF0, 0x45}, 2, "が"},
206 | {{0xF0, 0x46}, 2, "ぎ"},
207 | {{0xF0, 0x47}, 2, "ぐ"},
208 | {{0xF0, 0x48}, 2, "げ"},
209 | {{0xF0, 0x49}, 2, "ご"},
210 | {{0xF0, 0x4A}, 2, "ざ"},
211 | {{0xF0, 0x4B}, 2, "じ"},
212 | {{0xF0, 0x4C}, 2, "ず"},
213 | {{0xF0, 0x4D}, 2, "ぜ"},
214 | {{0xF0, 0x4E}, 2, "ぞ"},
215 | {{0xF0, 0x4F}, 2, "だ"},
216 | {{0xF0, 0x50}, 2, "ぢ"},
217 | {{0xF0, 0x51}, 2, "づ"},
218 | {{0xF0, 0x52}, 2, "で"},
219 | {{0xF0, 0x53}, 2, "ど"},
220 | {{0xF0, 0x59}, 2, "ば"},
221 | {{0xF0, 0x5A}, 2, "び"},
222 | {{0xF0, 0x5B}, 2, "ぶ"},
223 | {{0xF0, 0x5C}, 2, "べ"},
224 | {{0xF0, 0x5D}, 2, "ぼ"},
225 | {{0xF0, 0x75}, 2, "ガ"},
226 | {{0xF0, 0x76}, 2, "ギ"},
227 | {{0xF0, 0x77}, 2, "グ"},
228 | {{0xF0, 0x78}, 2, "ゲ"},
229 | {{0xF0, 0x79}, 2, "ゴ"},
230 | {{0xF0, 0x7A}, 2, "ザ"},
231 | {{0xF0, 0x7B}, 2, "ジ"},
232 | {{0xF0, 0x7C}, 2, "ズ"},
233 | {{0xF0, 0x7D}, 2, "ゼ"},
234 | {{0xF0, 0x7E}, 2, "ゾ"},
235 | {{0xF0, 0x7F}, 2, "ダ"},
236 | {{0xF0, 0x80}, 2, "ヂ"},
237 | {{0xF0, 0x81}, 2, "ヅ"},
238 | {{0xF0, 0x82}, 2, "デ"},
239 | {{0xF0, 0x83}, 2, "ド"},
240 | {{0xF0, 0x89}, 2, "バ"},
241 | {{0xF0, 0x8A}, 2, "ビ"},
242 | {{0xF0, 0x8B}, 2, "ブ"},
243 | {{0xF0, 0x8C}, 2, "ベ"},
244 | {{0xF0, 0x8D}, 2, "ボ"},
245 | {{0xF1, 0x59}, 2, "ぱ"},
246 | {{0xF1, 0x5A}, 2, "ぴ"},
247 | {{0xF1, 0x5B}, 2, "ぷ"},
248 | {{0xF1, 0x5C}, 2, "ぺ"},
249 | {{0xF1, 0x5D}, 2, "ぽ"},
250 | {{0xF1, 0x89}, 2, "パ"},
251 | {{0xF1, 0x8A}, 2, "ピ"},
252 | {{0xF1, 0x8B}, 2, "プ"},
253 | {{0xF1, 0x8C}, 2, "ペ"},
254 | {{0xF1, 0x8D}, 2, "ポ"},
255 | };
256 |
257 | const mapping us_mapping[] = {
258 | {{0x00}, 1, "0"},
259 | {{0x01}, 1, "1"},
260 | {{0x02}, 1, "2"},
261 | {{0x03}, 1, "3"},
262 | {{0x04}, 1, "4"},
263 | {{0x05}, 1, "5"},
264 | {{0x06}, 1, "6"},
265 | {{0x07}, 1, "7"},
266 | {{0x08}, 1, "8"},
267 | {{0x09}, 1, "9"},
268 | {{0x0A}, 1, "A"},
269 | {{0x0B}, 1, "B"},
270 | {{0x0C}, 1, "C"},
271 | {{0x0D}, 1, "D"},
272 | {{0x0E}, 1, "E"},
273 | {{0x0F}, 1, "F"},
274 | {{0x10}, 1, "G"},
275 | {{0x11}, 1, "H"},
276 | {{0x12}, 1, "I"},
277 | {{0x13}, 1, "J"},
278 | {{0x14}, 1, "K"},
279 | {{0x15}, 1, "L"},
280 | {{0x16}, 1, "M"},
281 | {{0x17}, 1, "N"},
282 | {{0x18}, 1, "O"},
283 | {{0x19}, 1, "P"},
284 | {{0x1A}, 1, "Q"},
285 | {{0x1B}, 1, "R"},
286 | {{0x1C}, 1, "S"},
287 | {{0x1D}, 1, "T"},
288 | {{0x1E}, 1, "U"},
289 | {{0x1F}, 1, "V"},
290 | {{0x20}, 1, "W"},
291 | {{0x21}, 1, "X"},
292 | {{0x22}, 1, "Y"},
293 | {{0x23}, 1, "Z"},
294 | {{0x24}, 1, "a"},
295 | {{0x25}, 1, "b"},
296 | {{0x26}, 1, "c"},
297 | {{0x27}, 1, "d"},
298 | {{0x28}, 1, "e"},
299 | {{0x29}, 1, "f"},
300 | {{0x2A}, 1, "g"},
301 | {{0x2B}, 1, "h"},
302 | {{0x2C}, 1, "i"},
303 | {{0x2D}, 1, "j"},
304 | {{0x2E}, 1, "k"},
305 | {{0x2F}, 1, "l"},
306 | {{0x30}, 1, "m"},
307 | {{0x31}, 1, "n"},
308 | {{0x32}, 1, "o"},
309 | {{0x33}, 1, "p"},
310 | {{0x34}, 1, "q"},
311 | {{0x35}, 1, "r"},
312 | {{0x36}, 1, "s"},
313 | {{0x37}, 1, "t"},
314 | {{0x38}, 1, "u"},
315 | {{0x39}, 1, "v"},
316 | {{0x3A}, 1, "w"},
317 | {{0x3B}, 1, "x"},
318 | {{0x3C}, 1, "y"},
319 | {{0x3D}, 1, "z"},
320 | {{0x3E}, 1, "'"},
321 | {{0x3F}, 1, "."},
322 | {{0x50}, 1, "^"}, // up
323 | {{0x51}, 1, "|"}, // down
324 | {{0x52}, 1, "<"}, // left
325 | {{0x53}, 1, ">"}, // right
326 | {{0x54}, 1, "[A]"},
327 | {{0x55}, 1, "[B]"},
328 | {{0x56}, 1, "[C]"},
329 | {{0x57}, 1, "[Z]"},
330 | {{0x58}, 1, "[R]"},
331 | {{0x6F}, 1, ","},
332 | {{0xD0}, 1, "/"},
333 | {{0xD1}, 1, "the"},
334 | {{0xD2}, 1, "you"},
335 | {{0x9E}, 1, " "},
336 | {{0x9F}, 1, "-"},
337 | {{0xE1}, 1, "("},
338 | {{0xE2}, 1, "\""},
339 | {{0xE3}, 1, ")"},
340 | {{0xE4}, 1, "+"},
341 | {{0xE5}, 1, "&"},
342 | {{0xE6}, 1, ":"},
343 | {{0xF2}, 1, "!"},
344 | {{0xF4}, 1, "?"},
345 | {{0xF5}, 1, "{"}, // opening "
346 | {{0xF6}, 1, "}"}, // closing "
347 | {{0xF7}, 1, "~"},
348 | {{0xF9}, 1, "$"},
349 | {{0xFA}, 1, "*"}, // filled star
350 | {{0xFB}, 1, "[x]"},
351 | {{0xFC}, 1, ";"},
352 | {{0xFD}, 1, "#"}, // open star
353 | {{0xFE}, 1, "\n"},
354 | };
355 |
356 | static void print_usage(void)
357 | {
358 | printf("Usage: sm64text [-b] [-t] [-r REGION] [-d] INPUT\n"
359 | "\n"
360 | "sm64text v" SM64TEXT_VERSION ": SM64 dialog text encoder/decoder\n"
361 | "\n"
362 | "Optional arguments:\n"
363 | " -b INPUT is bytes to convert to utf8 text\n"
364 | " -t INPUT is utf8 text convert to SM64 dialog encoded bytes (appends 0xFF end of string)\n"
365 | " -r REGION region to use: U or J (default: J)\n"
366 | " -d dump table to format suitable for armips\n"
367 | "Required arguments:\n"
368 | " INPUT either text string (if using -t) or hex byte pairs (if using -b)\n"
369 | "\n"
370 | "Examples:\n"
371 | " $ sm64text -r u 2B 28 2F 2F 32\n"
372 | " hello\n"
373 | " $ sm64text -r u -t hello\n"
374 | " 0x2B, 0x28, 0x2F, 0x2F, 0x32, 0xFF\n");
375 | }
376 |
377 | static int is_hex(char val)
378 | {
379 | return ((val >= '0' && val <= '9') || (val >= 'A' && val <= 'F') || (val >= 'a' && val <= 'f'));
380 | }
381 |
382 | static size_t parse_bytes(uint8_t *bytes, const char *hex)
383 | {
384 | size_t count = 0;
385 | int i = 0;
386 | while (hex[i]) {
387 | if (is_hex(hex[i]) && is_hex(hex[i+1])) {
388 | const char val[3] = {hex[i], hex[i+1], '\0'};
389 | bytes[count++] = strtoul(val, NULL, 16);
390 | i += 2;
391 | } else {
392 | i++;
393 | }
394 | }
395 | return count;
396 | }
397 |
398 | static void parse_config(config *conf, int argc, char *argv[])
399 | {
400 | int c;
401 | while ((c = getopt(argc, argv, "bdtr:")) != -1) {
402 | switch (c) {
403 | case 'b':
404 | conf->conv = CONVERT_BYTES;
405 | break;
406 | case 'd':
407 | conf->conv = DUMP_TABLE;
408 | break;
409 | case 't':
410 | conf->conv = CONVERT_TEXT;
411 | break;
412 | case 'r':
413 | switch (tolower(optarg[0])) {
414 | case 'j': conf->reg = REGION_J; break;
415 | case 'u': conf->reg = REGION_U; break;
416 | default: print_usage(); exit(1); break;
417 | }
418 | break;
419 | case '?':
420 | default:
421 | print_usage();
422 | exit(1);
423 | }
424 | }
425 |
426 | switch (conf->conv) {
427 | case CONVERT_BYTES:
428 | if (optind < argc) {
429 | size_t allocation = 1024;
430 | uint8_t *bytes = malloc(allocation);
431 | size_t count = 0;
432 | for (int i = optind; i < argc; i++) {
433 | count += parse_bytes(&bytes[count], argv[i]);
434 | if (count >= allocation) {
435 | allocation *= 2;
436 | bytes = realloc(bytes, allocation);
437 | }
438 | }
439 | conf->bytes = bytes;
440 | conf->length = count;
441 | }
442 | break;
443 | case CONVERT_TEXT:
444 | if (optind < argc) {
445 | conf->text = argv[optind];
446 | }
447 | break;
448 | default:
449 | break;
450 | }
451 | }
452 |
453 | // find longest byte pattern in mapping table that matches 'bytes'
454 | int lookup_longest_bytes(const mapping *map, size_t map_count, const uint8_t *bytes)
455 | {
456 | int best_idx = -1;
457 | for (size_t i = 0; i < map_count; i++) {
458 | if (!memcmp(bytes, map[i].bytes, map[i].blen)) {
459 | if (best_idx < 0 || map[i].blen > map[best_idx].blen) {
460 | best_idx = i;
461 | }
462 | }
463 | }
464 | return best_idx;
465 | }
466 |
467 | // decode bytes to text for given mapping table
468 | void print_text(const mapping *map, size_t map_count, uint8_t *bytes, int length)
469 | {
470 | int i = 0;
471 | while (i < length && bytes[i] != sm64_string_terminator) {
472 | int best = lookup_longest_bytes(map, map_count, &bytes[i]);
473 | if (best < 0) {
474 | fprintf(stderr, "Error: couldn't find %02X\n", bytes[i]);
475 | exit(1);
476 | } else {
477 | printf("%s", map[best].text);
478 | i += map[best].blen;
479 | }
480 | }
481 | }
482 |
483 | // find longest matching text in mapping tables that matches 'text'
484 | int lookup_longest_text(const mapping *map, size_t map_count, const char *text)
485 | {
486 | int best_idx = -1;
487 | size_t best_len = 0;
488 | for (size_t i = 0; i < map_count; i++) {
489 | size_t len = strlen(map[i].text);
490 | if (!strncmp(text, map[i].text, len)) {
491 | if (best_idx < 0 || len > best_len) {
492 | best_idx = i;
493 | best_len = len;
494 | }
495 | }
496 | }
497 | return best_idx;
498 | }
499 |
500 | void print_bytes(const mapping *map, size_t map_count, const char *text)
501 | {
502 | size_t i = 0;
503 | int first = 1;
504 | size_t len = strlen(text);
505 | while (i < len) {
506 | int best = lookup_longest_text(map, map_count, &text[i]);
507 | if (best < 0) {
508 | fprintf(stderr, "Error: couldn't find %c\n", text[i]);
509 | exit(1);
510 | } else {
511 | for (size_t b = 0; b < map[best].blen; b++) {
512 | if (!first) printf(", ");
513 | printf("0x%02X", map[best].bytes[b]);
514 | first = 0;
515 | }
516 | i += strlen(map[best].text);
517 | }
518 | }
519 | printf(", 0x%02X\n", sm64_string_terminator);
520 | }
521 |
522 | static void dump_table(const mapping *map, size_t map_count)
523 | {
524 | for (size_t i = 0; i < map_count; i++) {
525 | for (size_t b = 0; b < map[i].blen; b++) {
526 | printf("%02X", map[i].bytes[b]);
527 | }
528 | printf("=");
529 | switch (map[i].text[0]) {
530 | case '\n': printf("\\n"); break;
531 | case '\r': printf("\\r"); break;
532 | default: printf("%s", map[i].text); break;
533 | }
534 | printf("\n");
535 | }
536 | printf("/%02X\n", sm64_string_terminator);
537 | }
538 |
539 | int main(int argc, char *argv[])
540 | {
541 | config conf = default_config;
542 | const mapping *map = us_mapping;
543 | size_t map_count = COUNT_OF(us_mapping);
544 |
545 | parse_config(&conf, argc, argv);
546 | if (conf.conv != DUMP_TABLE && !conf.bytes) {
547 | print_usage();
548 | return 1;
549 | }
550 |
551 | // select mapping table
552 | switch (conf.reg) {
553 | case REGION_U:
554 | map = us_mapping;
555 | map_count = COUNT_OF(us_mapping);
556 | break;
557 | case REGION_J:
558 | map = j_mapping;
559 | map_count = COUNT_OF(j_mapping);
560 | break;
561 | }
562 |
563 | // run conversion
564 | switch (conf.conv) {
565 | case CONVERT_BYTES:
566 | print_text(map, map_count, conf.bytes, conf.length);
567 | printf("\n");
568 | break;
569 | case CONVERT_TEXT:
570 | print_bytes(map, map_count, conf.text);
571 | break;
572 | case DUMP_TABLE:
573 | dump_table(map, map_count);
574 | break;
575 | }
576 |
577 | return 0;
578 | }
579 |
--------------------------------------------------------------------------------
/utils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #if defined(_MSC_VER) || defined(__MINGW32__)
9 | #include
10 | #include
11 | #else
12 | #include
13 | #include
14 | #endif
15 |
16 | #include "utils.h"
17 |
18 | // global verbosity setting
19 | int g_verbosity = 0;
20 |
21 | int read_s16_be(unsigned char *buf)
22 | {
23 | unsigned tmp = read_u16_be(buf);
24 | int ret;
25 | if (tmp > 0x7FFF) {
26 | ret = -((int)0x10000 - (int)tmp);
27 | } else {
28 | ret = (int)tmp;
29 | }
30 | return ret;
31 | }
32 |
33 | float read_f32_be(unsigned char *buf)
34 | {
35 | union {uint32_t i; float f;} ret;
36 | ret.i = read_u32_be(buf);
37 | return ret.f;
38 | }
39 |
40 | int is_power2(unsigned int val)
41 | {
42 | while (((val & 1) == 0) && (val > 1)) {
43 | val >>= 1;
44 | }
45 | return (val == 1);
46 | }
47 |
48 | void fprint_hex(FILE *fp, const unsigned char *buf, int length)
49 | {
50 | int i;
51 | for (i = 0; i < length; i++) {
52 | fprint_byte(fp, buf[i]);
53 | fputc(' ', fp);
54 | }
55 | }
56 |
57 | void fprint_hex_source(FILE *fp, const unsigned char *buf, int length)
58 | {
59 | int i;
60 | for (i = 0; i < length; i++) {
61 | if (i > 0) fputs(", ", fp);
62 | fputs("0x", fp);
63 | fprint_byte(fp, buf[i]);
64 | }
65 | }
66 |
67 | void print_hex(const unsigned char *buf, int length)
68 | {
69 | fprint_hex(stdout, buf, length);
70 | }
71 |
72 | void swap_bytes(unsigned char *data, long length)
73 | {
74 | long i;
75 | unsigned char tmp;
76 | for (i = 0; i < length; i += 2) {
77 | tmp = data[i];
78 | data[i] = data[i+1];
79 | data[i+1] = tmp;
80 | }
81 | }
82 |
83 | void reverse_endian(unsigned char *data, long length)
84 | {
85 | long i;
86 | unsigned char tmp;
87 | for (i = 0; i < length; i += 4) {
88 | tmp = data[i];
89 | data[i] = data[i+3];
90 | data[i+3] = tmp;
91 | tmp = data[i+1];
92 | data[i+1] = data[i+2];
93 | data[i+2] = tmp;
94 | }
95 | }
96 |
97 | long filesize(const char *filename)
98 | {
99 | struct stat st;
100 |
101 | if (stat(filename, &st) == 0) {
102 | return st.st_size;
103 | }
104 |
105 | return -1;
106 | }
107 |
108 | void touch_file(const char *filename)
109 | {
110 | int fd;
111 | //fd = open(filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
112 | fd = open(filename, O_WRONLY|O_CREAT, 0666);
113 | if (fd >= 0) {
114 | utime(filename, NULL);
115 | close(fd);
116 | }
117 | }
118 |
119 | long read_file(const char *file_name, unsigned char **data)
120 | {
121 | FILE *in;
122 | unsigned char *in_buf = NULL;
123 | long file_size;
124 | long bytes_read;
125 | in = fopen(file_name, "rb");
126 | if (in == NULL) {
127 | return -1;
128 | }
129 |
130 | // allocate buffer to read from offset to end of file
131 | fseek(in, 0, SEEK_END);
132 | file_size = ftell(in);
133 |
134 | // sanity check
135 | if (file_size > 256*MB) {
136 | return -2;
137 | }
138 |
139 | in_buf = malloc(file_size);
140 | fseek(in, 0, SEEK_SET);
141 |
142 | // read bytes
143 | bytes_read = fread(in_buf, 1, file_size, in);
144 | if (bytes_read != file_size) {
145 | return -3;
146 | }
147 |
148 | fclose(in);
149 | *data = in_buf;
150 | return bytes_read;
151 | }
152 |
153 | long write_file(const char *file_name, unsigned char *data, long length)
154 | {
155 | FILE *out;
156 | long bytes_written;
157 | // open output file
158 | out = fopen(file_name, "wb");
159 | if (out == NULL) {
160 | perror(file_name);
161 | return -1;
162 | }
163 | bytes_written = fwrite(data, 1, length, out);
164 | fclose(out);
165 | return bytes_written;
166 | }
167 |
168 | void generate_filename(const char *in_name, char *out_name, char *extension)
169 | {
170 | char tmp_name[FILENAME_MAX];
171 | int len;
172 | int i;
173 | strcpy(tmp_name, in_name);
174 | len = strlen(tmp_name);
175 | for (i = len - 1; i > 0; i--) {
176 | if (tmp_name[i] == '.') {
177 | break;
178 | }
179 | }
180 | if (i <= 0) {
181 | i = len;
182 | }
183 | tmp_name[i] = '\0';
184 | sprintf(out_name, "%s.%s", tmp_name, extension);
185 | }
186 |
187 | char *basename(const char *name)
188 | {
189 | const char *base = name;
190 | while (*name) {
191 | if (*name++ == '/') {
192 | base = name;
193 | }
194 | }
195 | return (char *)base;
196 | }
197 |
198 | void make_dir(const char *dir_name)
199 | {
200 | struct stat st = {0};
201 | if (stat(dir_name, &st) == -1) {
202 | mkdir(dir_name, 0755);
203 | }
204 | }
205 |
206 | long copy_file(const char *src_name, const char *dst_name)
207 | {
208 | unsigned char *buf;
209 | long bytes_written;
210 | long bytes_read;
211 |
212 | bytes_read = read_file(src_name, &buf);
213 |
214 | if (bytes_read > 0) {
215 | bytes_written = write_file(dst_name, buf, bytes_read);
216 | if (bytes_written != bytes_read) {
217 | bytes_read = -1;
218 | }
219 | free(buf);
220 | }
221 |
222 | return bytes_read;
223 | }
224 |
225 | void dir_list_ext(const char *dir, const char *extension, dir_list *list)
226 | {
227 | char *pool;
228 | char *pool_ptr;
229 | struct dirent *entry;
230 | DIR *dfd;
231 | int idx;
232 |
233 | dfd = opendir(dir);
234 | if (dfd == NULL) {
235 | ERROR("Can't open '%s'\n", dir);
236 | exit(1);
237 | }
238 |
239 | pool = malloc(FILENAME_MAX * MAX_DIR_FILES);
240 | pool_ptr = pool;
241 |
242 | idx = 0;
243 | while ((entry = readdir(dfd)) != NULL && idx < MAX_DIR_FILES) {
244 | if (!extension || str_ends_with(entry->d_name, extension)) {
245 | sprintf(pool_ptr, "%s/%s", dir, entry->d_name);
246 | list->files[idx] = pool_ptr;
247 | pool_ptr += strlen(pool_ptr) + 1;
248 | idx++;
249 | }
250 | }
251 | list->count = idx;
252 |
253 | closedir(dfd);
254 | }
255 |
256 | void dir_list_free(dir_list *list)
257 | {
258 | // assume first entry in array is allocated
259 | if (list->files[0]) {
260 | free(list->files[0]);
261 | list->files[0] = NULL;
262 | }
263 | }
264 |
265 | int str_ends_with(const char *str, const char *suffix)
266 | {
267 | if (!str || !suffix) {
268 | return 0;
269 | }
270 | size_t len_str = strlen(str);
271 | size_t len_suffix = strlen(suffix);
272 | if (len_suffix > len_str) {
273 | return 0;
274 | }
275 | return (0 == strncmp(str + len_str - len_suffix, suffix, len_suffix));
276 | }
277 |
--------------------------------------------------------------------------------
/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_H_
2 | #define UTILS_H_
3 |
4 | #include
5 |
6 | // defines
7 |
8 | // printing size_t varies by compiler
9 | #if defined(_MSC_VER) || defined(__MINGW32__)
10 | #define SIZE_T_FORMAT "%Iu"
11 | #else
12 | #define SIZE_T_FORMAT "%zu"
13 | #endif
14 |
15 | #define KB 1024
16 | #define MB (1024 * KB)
17 |
18 | // number of elements in statically declared array
19 | #define DIM(S_ARR_) (sizeof(S_ARR_) / sizeof(S_ARR_[0]))
20 |
21 | #define MIN(A_, B_) ((A_) < (B_) ? (A_) : (B_))
22 | #define MAX(A_, B_) ((A_) > (B_) ? (A_) : (B_))
23 |
24 | // align value to N-byte boundary
25 | #define ALIGN(VAL_, ALIGNMENT_) (((VAL_) + ((ALIGNMENT_) - 1)) & ~((ALIGNMENT_) - 1))
26 |
27 | // read/write u32/16 big/little endian
28 | #define read_u32_be(buf) (unsigned int)(((buf)[0] << 24) + ((buf)[1] << 16) + ((buf)[2] << 8) + ((buf)[3]))
29 | #define read_u32_le(buf) (unsigned int)(((buf)[1] << 24) + ((buf)[0] << 16) + ((buf)[3] << 8) + ((buf)[2]))
30 | #define write_u32_be(buf, val) do { \
31 | (buf)[0] = ((val) >> 24) & 0xFF; \
32 | (buf)[1] = ((val) >> 16) & 0xFF; \
33 | (buf)[2] = ((val) >> 8) & 0xFF; \
34 | (buf)[3] = (val) & 0xFF; \
35 | } while(0)
36 | #define read_u16_be(buf) (((buf)[0] << 8) + ((buf)[1]))
37 | #define write_u16_be(buf, val) do { \
38 | (buf)[0] = ((val) >> 8) & 0xFF; \
39 | (buf)[1] = ((val)) & 0xFF; \
40 | } while(0)
41 |
42 | // print nibbles and bytes
43 | #define fprint_nibble(FP, NIB_) fputc((NIB_) < 10 ? ('0' + (NIB_)) : ('A' + (NIB_) - 0xA), FP)
44 | #define fprint_byte(FP, BYTE_) do { \
45 | fprint_nibble(FP, (BYTE_) >> 4); \
46 | fprint_nibble(FP, (BYTE_) & 0x0F); \
47 | } while(0)
48 | #define print_nibble(NIB_) fprint_nibble(stdout, NIB_)
49 | #define print_byte(BYTE_) fprint_byte(stdout, BYTE_)
50 |
51 | // Windows compatibility
52 | #if defined(_MSC_VER) || defined(__MINGW32__)
53 | #include
54 | #define mkdir(DIR_, PERM_) _mkdir(DIR_)
55 | #ifndef strcasecmp
56 | #define strcasecmp(A, B) stricmp(A, B)
57 | #endif
58 | #endif
59 |
60 | // typedefs
61 |
62 | #define MAX_DIR_FILES 128
63 | typedef struct
64 | {
65 | char *files[MAX_DIR_FILES];
66 | int count;
67 | } dir_list;
68 |
69 | // global verbosity setting
70 | extern int g_verbosity;
71 |
72 | #define ERROR(...) fprintf(stderr, __VA_ARGS__)
73 | #define INFO(...) if (g_verbosity) printf(__VA_ARGS__)
74 | #define INFO_HEX(...) if (g_verbosity) print_hex(__VA_ARGS__)
75 |
76 | // functions
77 |
78 | // convert two bytes in big-endian to signed int
79 | int read_s16_be(unsigned char *buf);
80 |
81 | // convert four bytes in big-endian to float
82 | float read_f32_be(unsigned char *buf);
83 |
84 | // determine if value is power of 2
85 | // returns 1 if val is power of 2, 0 otherwise
86 | int is_power2(unsigned int val);
87 |
88 | // print buffer as hex bytes
89 | // fp: file pointer
90 | // buf: buffer to read bytes from
91 | // length: length of buffer to print
92 | void fprint_hex(FILE *fp, const unsigned char *buf, int length);
93 | void fprint_hex_source(FILE *fp, const unsigned char *buf, int length);
94 | void print_hex(const unsigned char *buf, int length);
95 |
96 | // perform byteswapping to convert from v64 to z64 ordering
97 | void swap_bytes(unsigned char *data, long length);
98 |
99 | // reverse endian to convert from n64 to z64 ordering
100 | void reverse_endian(unsigned char *data, long length);
101 |
102 | // get size of file without opening it;
103 | // returns file size or negative on error
104 | long filesize(const char *file_name);
105 |
106 | // update file timestamp to now, creating it if it doesn't exist
107 | void touch_file(const char *filename);
108 |
109 | // read entire contents of file into buffer
110 | // returns file size or negative on error
111 | long read_file(const char *file_name, unsigned char **data);
112 |
113 | // write buffer to file
114 | // returns number of bytes written out or -1 on failure
115 | long write_file(const char *file_name, unsigned char *data, long length);
116 |
117 | // generate an output file name from input name by replacing file extension
118 | // in_name: input file name
119 | // out_name: buffer to write output name in
120 | // extension: new file extension to use
121 | void generate_filename(const char *in_name, char *out_name, char *extension);
122 |
123 | // extract base filename from file path
124 | // name: path to file
125 | // returns just the file name after the last '/'
126 | char *basename(const char *name);
127 |
128 | // make a directory if it doesn't exist
129 | // dir_name: name of the directory
130 | void make_dir(const char *dir_name);
131 |
132 | // copy a file from src_name to dst_name. will not make directories
133 | // src_name: source file name
134 | // dst_name: destination file name
135 | long copy_file(const char *src_name, const char *dst_name);
136 |
137 | // list a directory, optionally filtering files by extension
138 | // dir: directory to list files in
139 | // extension: extension to filter files by (NULL if no filtering)
140 | // list: output list and count
141 | void dir_list_ext(const char *dir, const char *extension, dir_list *list);
142 |
143 | // free associated date from a directory list
144 | // list: directory list filled in by dir_list_ext() call
145 | void dir_list_free(dir_list *list);
146 |
147 | // determine if a string ends with another string
148 | // str: string to check if ends with 'suffix'
149 | // suffix: string to see if 'str' ends with
150 | // returns 1 if 'str' ends with 'suffix'
151 | int str_ends_with(const char *str, const char *suffix);
152 |
153 | #endif // UTILS_H_
154 |
--------------------------------------------------------------------------------