Merge pull request #216 from DavidSM64/rev2_b

This commit is contained in:
David Benepe
2022-04-05 09:00:33 -04:00
committed by GitHub
107 changed files with 37480 additions and 11686 deletions
+130 -179
View File
@@ -12,6 +12,16 @@ VERSION := us_1.0
NON_MATCHING ?= 0
$(eval $(call validate-option,NON_MATCHING,0 1))
COMPILE_ASSETS ?= 0
$(eval $(call validate-option,COMPILE_ASSETS,0 1))
ifeq ($(COMPILE_ASSETS),1)
DUMMY != ./tools/dkr_assets_tool -c $(VERSION) ./assets >&2 || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Failed to compile assets)
endif
endif
ifeq ($(VERSION),us_1.0)
DEFINES += VERSION_US_1_0=1
endif
@@ -37,6 +47,7 @@ COLOR ?= 1
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),clean_lib)
ifneq ($(MAKECMDGOALS),clean_src)
ifneq ($(MAKECMDGOALS),distclean)
ifneq ($(MAKECMDGOALS),reset)
################ Check if a baserom exists ################
@@ -75,7 +86,11 @@ RECOMP_PROJECT := ./tools/ido-static-recomp/
DUMMY != ls $(RECOMP_PROJECT)ido >/dev/null || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Missing submodule ido-static-recomp. Please run 'git submodule update --init')
DUMMY != git submodule update --init
DUMMY != ls $(RECOMP_PROJECT)ido >/dev/null || echo FAIL
ifeq ($(DUMMY),FAIL)
$(error Missing submodule ido-static-recomp. Please run 'git submodule update --init')
endif
endif
# List of IDO tools required for the repo.
@@ -110,6 +125,12 @@ endif
endif
endif
endif
endif
################################
# Removes the enums_cache if it exists in the build folde, incase someone modified the include/enums.h file.
DUMMY != rm -Rf build/enums_cache
################ Target Executable and Sources ###############
@@ -175,8 +196,8 @@ FixPath = $(subst /,,$1)
N64CRC = $(TOOLS_DIR)/n64crc
FIXCHECKSUMS = python3 $(TOOLS_DIR)/python/calc_func_checksums.py $(VERSION)
TEXBUILDER = $(TOOLS_DIR)/dkr_texbuilder
COMPRESS = $(TOOLS_DIR)/dkr_decompressor -c
COMPRESS = $(TOOLS_DIR)/dkr_assets_tool -fc
BUILDER = $(TOOLS_DIR)/dkr_assets_tool -b $(VERSION) ./assets
LIB_DIRS := lib/
ASM_DIRS := asm/ asm/boot/ asm/assets/ lib/asm/ lib/asm/non_decompilable
@@ -208,8 +229,6 @@ CC_CHECK_CFLAGS += -Wno-builtin-declaration-mismatch -Wno-pointer-to-int-cast -W
####################### ASSETS #########################
# TODO: Clean this up if possible
# All the asset subfolders to create in the build folder.
ASSETS_DIRS := audio bin fonts ids levels levels/headers levels/models levels/names levels/objectMaps misc objects objects/animations objects/headers objects/models particles particles/behaviors particles/particles sprites text text/game text/menu textures textures/2d textures/3d tt_ghosts unknown_0 ucode
@@ -218,100 +237,67 @@ UCODE_DIR = ucode/$(VERSION)
ASSETS_COPY = cp
AUDIO_IN_DIR = $(ASSETS_DIR)/audio
AUDIO_OUT_DIR = $(BUILD_DIR)/audio
ALL_ASSETS_BUILT += $(patsubst $(AUDIO_IN_DIR)/%.bin,$(AUDIO_OUT_DIR)/%.bin,$(wildcard $(AUDIO_IN_DIR)/*.bin))
# Makes name uppercase, and also replaces '/' with '_' for subfolders.
# Doing all those subst calls *should* be faster than `$(shell echo '$1' | tr '[:lower:]' '[:upper:]')
GET_VAR_NAME = $(subst /,_,$(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$1)))))))))))))))))))))))))))
BIN_IN_DIR = $(ASSETS_DIR)/bin
BIN_OUT_DIR = $(BUILD_DIR)/bin
ALL_ASSETS_BUILT += $(patsubst $(BIN_IN_DIR)/%.bin,$(BIN_OUT_DIR)/%.bin,$(wildcard $(BIN_IN_DIR)/*.bin))
# $1 = Input/Output directories name
define DEFINE_BINARY_FILES
ALL_ASSETS_BUILT += $(patsubst $($1_IN_DIR)/%.bin,$($1_OUT_DIR)/%.bin,$(wildcard $($1_IN_DIR)/*.bin))
endef
# $1 = Input/Output directories name
define DEFINE_COMPRESSED_BINARY_FILES
ALL_ASSETS_BUILT += $(patsubst $($1_IN_DIR)/%.cbin,$($1_OUT_DIR)/%.bin,$(wildcard $($1_IN_DIR)/*.cbin))
endef
# $1 = Input/Output directories name
define DEFINE_JSON_FILES
ALL_ASSETS_BUILT += $(patsubst $($1_IN_DIR)/%.json,$($1_OUT_DIR)/%.bin,$(wildcard $($1_IN_DIR)/*.json))
endef
# $1 = Input/Output directories name
define DEFINE_JSON_AND_BINARY_FILES
$(eval $(call DEFINE_JSON_FILES,$1))
$(eval $(call DEFINE_BINARY_FILES,$1))
endef
FONTS_IN_DIR = $(ASSETS_DIR)/fonts
FONTS_OUT_DIR = $(BUILD_DIR)/fonts
ALL_ASSETS_BUILT += $(patsubst $(FONTS_IN_DIR)/%.bin,$(FONTS_OUT_DIR)/%.bin,$(wildcard $(FONTS_IN_DIR)/*.bin))
# $1 = folder name, $2 = define function
define DEFINE_SECTION_FILES
$(eval VAR_NAME := $(call GET_VAR_NAME,$1))
$(eval $(VAR_NAME)_IN_DIR = $(ASSETS_DIR)/$1)
$(eval $(VAR_NAME)_OUT_DIR = $(BUILD_DIR)/$1)
$(eval $(call $2,$(VAR_NAME)))
endef
IDS_IN_DIR = $(ASSETS_DIR)/ids
IDS_OUT_DIR = $(BUILD_DIR)/ids
ALL_ASSETS_BUILT += $(patsubst $(IDS_IN_DIR)/%.bin,$(IDS_OUT_DIR)/%.bin,$(wildcard $(IDS_IN_DIR)/*.bin))
###### Define section files into the ALL_ASSETS_BUILT variable ######
LEVELS_IN_DIR = $(ASSETS_DIR)/levels
LEVELS_OUT_DIR = $(BUILD_DIR)/levels
LEVEL_HEADERS_IN_DIR = $(LEVELS_IN_DIR)/headers
LEVEL_HEADERS_OUT_DIR = $(LEVELS_OUT_DIR)/headers
LEVEL_MODELS_IN_DIR = $(LEVELS_IN_DIR)/models
LEVEL_MODELS_OUT_DIR = $(LEVELS_OUT_DIR)/models
LEVEL_NAMES_IN_DIR = $(LEVELS_IN_DIR)/names
LEVEL_NAMES_OUT_DIR = $(LEVELS_OUT_DIR)/names
LEVEL_OBJMAPS_IN_DIR = $(LEVELS_IN_DIR)/objectMaps
LEVEL_OBJMAPS_OUT_DIR = $(LEVELS_OUT_DIR)/objectMaps
ALL_ASSETS_BUILT += $(patsubst $(LEVEL_HEADERS_IN_DIR)/%.bin,$(LEVEL_HEADERS_OUT_DIR)/%.bin,$(wildcard $(LEVEL_HEADERS_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(LEVEL_MODELS_IN_DIR)/%.cbin,$(LEVEL_MODELS_OUT_DIR)/%.bin,$(wildcard $(LEVEL_MODELS_IN_DIR)/*.cbin))
ALL_ASSETS_BUILT += $(patsubst $(LEVEL_NAMES_IN_DIR)/%.bin,$(LEVEL_NAMES_OUT_DIR)/%.bin,$(wildcard $(LEVEL_NAMES_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(LEVEL_OBJMAPS_IN_DIR)/%.cbin,$(LEVEL_OBJMAPS_OUT_DIR)/%.bin,$(wildcard $(LEVEL_OBJMAPS_IN_DIR)/*.cbin))
MISC_IN_DIR = $(ASSETS_DIR)/misc
MISC_OUT_DIR = $(BUILD_DIR)/misc
ALL_ASSETS_BUILT += $(patsubst $(MISC_IN_DIR)/%.bin,$(MISC_OUT_DIR)/%.bin,$(wildcard $(MISC_IN_DIR)/*.bin))
OBJECTS_IN_DIR = $(ASSETS_DIR)/objects
OBJECTS_OUT_DIR = $(BUILD_DIR)/objects
OBJECT_ANIMS_IN_DIR = $(OBJECTS_IN_DIR)/animations
OBJECT_ANIMS_OUT_DIR = $(OBJECTS_OUT_DIR)/animations
OBJECT_HEADERS_IN_DIR = $(OBJECTS_IN_DIR)/headers
OBJECT_HEADERS_OUT_DIR = $(OBJECTS_OUT_DIR)/headers
OBJECT_MODELS_IN_DIR = $(OBJECTS_IN_DIR)/models
OBJECT_MODELS_OUT_DIR = $(OBJECTS_OUT_DIR)/models
ALL_ASSETS_BUILT += $(patsubst $(OBJECTS_IN_DIR)/%.bin,$(OBJECTS_OUT_DIR)/%.bin,$(wildcard $(OBJECTS_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(OBJECT_ANIMS_IN_DIR)/%.cbin,$(OBJECT_ANIMS_OUT_DIR)/%.bin,$(wildcard $(OBJECT_ANIMS_IN_DIR)/*.cbin))
ALL_ASSETS_BUILT += $(patsubst $(OBJECT_HEADERS_IN_DIR)/%.bin,$(OBJECT_HEADERS_OUT_DIR)/%.bin,$(wildcard $(OBJECT_HEADERS_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(OBJECT_MODELS_IN_DIR)/%.cbin,$(OBJECT_MODELS_OUT_DIR)/%.bin,$(wildcard $(OBJECT_MODELS_IN_DIR)/*.cbin))
PARTICLES_IN_DIR = $(ASSETS_DIR)/particles
PARTICLES_OUT_DIR = $(BUILD_DIR)/particles
PART_BEHAVIORS_IN_DIR = $(PARTICLES_IN_DIR)/behaviors
PART_BEHAVIORS_OUT_DIR = $(PARTICLES_OUT_DIR)/behaviors
PART_PARTICLES_IN_DIR = $(PARTICLES_IN_DIR)/particles
PART_PARTICLES_OUT_DIR = $(PARTICLES_OUT_DIR)/particles
ALL_ASSETS_BUILT += $(patsubst $(PART_BEHAVIORS_IN_DIR)/%.bin,$(PART_BEHAVIORS_OUT_DIR)/%.bin,$(wildcard $(PART_BEHAVIORS_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(PART_PARTICLES_IN_DIR)/%.bin,$(PART_PARTICLES_OUT_DIR)/%.bin,$(wildcard $(PART_PARTICLES_IN_DIR)/*.bin))
SPRITES_IN_DIR = $(ASSETS_DIR)/sprites
SPRITES_OUT_DIR = $(BUILD_DIR)/sprites
ALL_ASSETS_BUILT += $(patsubst $(SPRITES_IN_DIR)/%.bin,$(SPRITES_OUT_DIR)/%.bin,$(wildcard $(SPRITES_IN_DIR)/*.bin))
TEXT_IN_DIR = $(ASSETS_DIR)/text
TEXT_OUT_DIR = $(BUILD_DIR)/text
TEXT_GAME_IN_DIR = $(TEXT_IN_DIR)/game
TEXT_GAME_OUT_DIR = $(TEXT_OUT_DIR)/game
TEXT_MENU_IN_DIR = $(TEXT_IN_DIR)/menu
TEXT_MENU_OUT_DIR = $(TEXT_OUT_DIR)/menu
ALL_ASSETS_BUILT += $(patsubst $(TEXT_GAME_IN_DIR)/%.bin,$(TEXT_GAME_OUT_DIR)/%.bin,$(wildcard $(TEXT_GAME_IN_DIR)/*.bin))
ALL_ASSETS_BUILT += $(patsubst $(TEXT_MENU_IN_DIR)/%.bin,$(TEXT_MENU_OUT_DIR)/%.bin,$(wildcard $(TEXT_MENU_IN_DIR)/*.bin))
TEXTURES_IN_DIR = $(ASSETS_DIR)/textures
TEXTURES_OUT_DIR = $(BUILD_DIR)/textures
TEXTURES_2D_IN_DIR = $(TEXTURES_IN_DIR)/2d
TEXTURES_2D_OUT_DIR = $(TEXTURES_OUT_DIR)/2d
TEXTURES_3D_IN_DIR = $(TEXTURES_IN_DIR)/3d
TEXTURES_3D_OUT_DIR = $(TEXTURES_OUT_DIR)/3d
ALL_ASSETS_BUILT += $(patsubst $(TEXTURES_2D_IN_DIR)/%.png,$(TEXTURES_2D_OUT_DIR)/%.bin,$(wildcard $(TEXTURES_2D_IN_DIR)/*.png))
ALL_ASSETS_BUILT += $(patsubst $(TEXTURES_3D_IN_DIR)/%.png,$(TEXTURES_3D_OUT_DIR)/%.bin,$(wildcard $(TEXTURES_3D_IN_DIR)/*.png))
TT_GHOSTS_IN_DIR = $(ASSETS_DIR)/tt_ghosts
TT_GHOSTS_OUT_DIR = $(BUILD_DIR)/tt_ghosts
ALL_ASSETS_BUILT += $(patsubst $(TT_GHOSTS_IN_DIR)/%.bin,$(TT_GHOSTS_OUT_DIR)/%.bin,$(wildcard $(TT_GHOSTS_IN_DIR)/*.bin))
UNKNOWN_0_IN_DIR = $(ASSETS_DIR)/unknown_0
UNKNOWN_0_OUT_DIR = $(BUILD_DIR)/unknown_0
ALL_ASSETS_BUILT += $(patsubst $(UNKNOWN_0_IN_DIR)/%.bin,$(UNKNOWN_0_OUT_DIR)/%.bin,$(wildcard $(UNKNOWN_0_IN_DIR)/*.bin))
$(call DEFINE_SECTION_FILES,audio,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,bin,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,fonts,DEFINE_JSON_AND_BINARY_FILES)
$(call DEFINE_SECTION_FILES,ids,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,levels/headers,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,levels/models,DEFINE_COMPRESSED_BINARY_FILES)
$(call DEFINE_SECTION_FILES,levels/names,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,levels/objectMaps,DEFINE_COMPRESSED_BINARY_FILES)
$(call DEFINE_SECTION_FILES,misc,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,objects,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,objects/animations,DEFINE_COMPRESSED_BINARY_FILES)
$(call DEFINE_SECTION_FILES,objects/headers,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,objects/models,DEFINE_COMPRESSED_BINARY_FILES)
$(call DEFINE_SECTION_FILES,particles/behaviors,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,particles/particles,DEFINE_BINARY_FILES)
$(call DEFINE_SECTION_FILES,sprites,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,text/game,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,text/menu,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,textures/2d,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,textures/3d,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,tt_ghosts,DEFINE_JSON_FILES)
$(call DEFINE_SECTION_FILES,unknown_0,DEFINE_BINARY_FILES)
# Microcode
UCODE_IN_DIR = $(UCODE_DIR)
UCODE_OUT_DIR = $(BUILD_DIR)/ucode
UCODE = $(wildcard $(UCODE_IN_DIR)/*.bin)
ALL_ASSETS_BUILT += $(patsubst $(UCODE_IN_DIR)/%.bin,$(UCODE_OUT_DIR)/%.bin,$(UCODE))
#ALL_ASSETS_BUILT := $(ANIMATIONS_BUILT) $(AUDIO_BUILT) $(BILLBOARDS_BUILT) $(BINS_BUILT) $(CHEATS_BUILT) $(FONTS_BUILT) $(LEVELS_BUILT) $(OBJECTS_BUILT) $(TEXTURES_BUILT) $(PARTICLES_BUILT) $(TEXT_BUILT) $(TT_GHOSTS_BUILT) $(UCODE_BUILT) $(LUT_BUILT)
####################### LIBULTRA #########################
$(BUILD_DIR)/lib/%.o: OPT_FLAGS := -O2 -Xfullwarn
@@ -358,7 +344,15 @@ ifneq ($(wildcard ./build/.*),)
rm -r build
else
@echo "/build/ directory has already been deleted."
endif
endif
distclean:
rm -rf build
rm -rf assets
rm -rf ucode
rm -rf dkr.ld
rm -rf tools/ido-static-recomp/{,.[!.],..?}* # Deletes all files, including hidden ones.
$(MAKE) -C tools distclean
clean_lib:
ifneq ($(wildcard $(BUILD_DIR)/lib/.*),)
@@ -388,98 +382,55 @@ dont_remove_asset_files: $(ALL_ASSETS_BUILT)
# All assets should output a .bin file
$(AUDIO_OUT_DIR)/%.bin: $(AUDIO_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
# $1 = folder name, $2 = Print Message
define CREATE_BINARY_ASSET_TARGET
$(eval VAR_NAME := $(call GET_VAR_NAME,$1))
$$($$(VAR_NAME)_OUT_DIR)/%.bin: $$($$(VAR_NAME)_IN_DIR)/%.bin
$$(call print,$2:,$$<,$$@)
$$(V)$$(ASSETS_COPY) $$^ $$@
endef
$(BIN_OUT_DIR)/%.bin: $(BIN_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(FONTS_OUT_DIR)/%.bin: $(FONTS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(IDS_OUT_DIR)/%.bin: $(IDS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(LEVEL_HEADERS_OUT_DIR)/%.bin: $(LEVEL_HEADERS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
# $1 = folder name, $2 = Print Message
define CREATE_COMPRESSED_ASSET_TARGET
$(eval VAR_NAME := $(call GET_VAR_NAME,$1))
$$($$(VAR_NAME)_OUT_DIR)/%.bin: $$($$(VAR_NAME)_IN_DIR)/%.cbin
$$(call print,$2:,$$<,$$@)
$$(V)$$(COMPRESS) $$^ $$@
endef
$(LEVEL_MODELS_OUT_DIR)/%.bin: $(LEVEL_MODELS_IN_DIR)/%.cbin
$(call print,Compressing:,$<,$@)
$(V)$(COMPRESS) $^ $@
$(LEVEL_NAMES_OUT_DIR)/%.bin: $(LEVEL_NAMES_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
# $1 = folder name, $2 = Print Message
define CREATE_JSON_ASSET_TARGET
$(eval VAR_NAME := $(call GET_VAR_NAME,$1))
$$($$(VAR_NAME)_OUT_DIR)/%.bin: $$($$(VAR_NAME)_IN_DIR)/%.json
$$(call print,$2:,$$<,$$@)
$$(V)$$(BUILDER) $$^ $$@
endef
$(LEVEL_OBJMAPS_OUT_DIR)/%.bin: $(LEVEL_OBJMAPS_IN_DIR)/%.cbin
$(call print,Compressing:,$<,$@)
$(V)$(COMPRESS) $^ $@
$(MISC_OUT_DIR)/%.bin: $(MISC_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(OBJECTS_OUT_DIR)/%.bin: $(OBJECTS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(OBJECT_ANIMS_OUT_DIR)/%.bin: $(OBJECT_ANIMS_IN_DIR)/%.cbin
$(call print,Compressing:,$<,$@)
$(V)$(COMPRESS) $^ $@
$(OBJECT_HEADERS_OUT_DIR)/%.bin: $(OBJECT_HEADERS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(OBJECT_MODELS_OUT_DIR)/%.bin: $(OBJECT_MODELS_IN_DIR)/%.cbin
$(call print,Compressing:,$<,$@)
$(V)$(COMPRESS) $^ $@
$(PART_BEHAVIORS_OUT_DIR)/%.bin: $(PART_BEHAVIORS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(PART_PARTICLES_OUT_DIR)/%.bin: $(PART_PARTICLES_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(SPRITES_OUT_DIR)/%.bin: $(SPRITES_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(TEXT_GAME_OUT_DIR)/%.bin: $(TEXT_GAME_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(TEXT_MENU_OUT_DIR)/%.bin: $(TEXT_MENU_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(TEXTURES_2D_OUT_DIR)/%.bin: $(TEXTURES_2D_IN_DIR)/%.png
$(call print,Building Texture:,$<,$@)
$(V)$(TEXBUILDER) $^ $@
$(TEXTURES_3D_OUT_DIR)/%.bin: $(TEXTURES_3D_IN_DIR)/%.png
$(call print,Building Texture:,$<,$@)
$(V)$(TEXBUILDER) $^ $@
$(TEXT_MENU_OUT_DIR)/%.bin: $(TEXT_MENU_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(TT_GHOSTS_OUT_DIR)/%.bin: $(TT_GHOSTS_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(UNKNOWN_0_OUT_DIR)/%.bin: $(UNKNOWN_0_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
$(eval $(call CREATE_BINARY_ASSET_TARGET,audio,Copying Audio Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,bin,Copying Bin Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,fonts,Copying Fonts Binary))
$(eval $(call CREATE_JSON_ASSET_TARGET,fonts,Building Fonts))
$(eval $(call CREATE_BINARY_ASSET_TARGET,ids,Copying IDs Binary))
$(eval $(call CREATE_JSON_ASSET_TARGET,levels/headers,Building Level Header))
$(eval $(call CREATE_COMPRESSED_ASSET_TARGET,levels/models,Compressing Level Model Binary))
$(eval $(call CREATE_JSON_ASSET_TARGET,levels/names,Building Level Name))
$(eval $(call CREATE_COMPRESSED_ASSET_TARGET,levels/objectMaps,Compressing Level Object Map Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,misc,Copying Misc Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,objects,Copying Object Binary))
$(eval $(call CREATE_COMPRESSED_ASSET_TARGET,objects/animations,Compressing Object Animation Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,objects/headers,Copying Object Header Binary))
$(eval $(call CREATE_COMPRESSED_ASSET_TARGET,objects/models,Compressing Object Model Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,particles/behaviors,Copying Particle Behavior Binary))
$(eval $(call CREATE_BINARY_ASSET_TARGET,particles/particles,Copying Particle Binary))
$(eval $(call CREATE_JSON_ASSET_TARGET,sprites,Building Sprite))
$(eval $(call CREATE_JSON_ASSET_TARGET,text/game,Building Game Text))
$(eval $(call CREATE_JSON_ASSET_TARGET,text/menu,Building Menu Text))
$(eval $(call CREATE_JSON_ASSET_TARGET,textures/2d,Building Texture (2D)))
$(eval $(call CREATE_JSON_ASSET_TARGET,textures/3d,Building Texture (3D)))
$(eval $(call CREATE_JSON_ASSET_TARGET,tt_ghosts,Building T.T. Ghost))
$(eval $(call CREATE_BINARY_ASSET_TARGET,unknown_0,Copying Unknown_0 Binary))
# Microcode target
$(UCODE_OUT_DIR)/%.bin: $(UCODE_IN_DIR)/%.bin
$(call print,Copying:,$<,$@)
$(V)$(ASSETS_COPY) $^ $@
@@ -540,7 +491,7 @@ test: $(BUILD_DIR)/$(TARGET).z64
load: $(BUILD_DIR)/$(TARGET).z64
$(LOADER) $(LOADER_FLAGS) $<
.PHONY: all clean default diff test
.PHONY: all clean distclean default diff test
# Remove built-in rules, to improve performance
MAKEFLAGS += --no-builtin-rules
+9392 -9319
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Regular → Executable
+1041 -557
View File
File diff suppressed because one or more lines are too long
+8 -10
View File
@@ -1,32 +1,30 @@
#!/bin/bash
if [[ $# == 0 || (($1 != "us_1.0") && ($1 != "us_1.1") && ($1 != "eu_1.0") && ($1 != "eu_1.1") && ($1 != "jp"))]]; then
echo 'Usage: ./extract.sh <version>'
echo 'Acceptable versions: us_1.0, us_1.1, eu_1.0, eu_1.1, jp'
exit 1
echo 'No valid version specified, defaulting to us_1.0...'
VER="us_1.0"
else
VER=$1
fi
echo 'Extracting Assets...'
# Remove assets directory if it exists.
ASSETS_DIR="./assets/$1"
ASSETS_DIR="./assets/vanilla/$VER"
if [ -d "$ASSETS_DIR" ]; then
rm -r $ASSETS_DIR
fi
# Remove ucode directory if it exists.
UCODE_DIR="./ucode/$1"
UCODE_DIR="./ucode/$VER"
if [ -d "$UCODE_DIR" ]; then
rm -r $UCODE_DIR
fi
if ! ./tools/dkr_extractor "$1" ./extract-ver ./baseroms . ; then
if ! ./tools/dkr_assets_tool -e "$VER" ./assets ./extract-ver ./baseroms . ; then
exit 1
fi
# Generate the linker file (dkr.ld)
./generate_ld.sh "$1"
echo 'Done.'
exit 0
exit 0
File diff suppressed because it is too large Load Diff
+65
View File
@@ -0,0 +1,65 @@
#ifndef ENUMS_H
#define ENUMS_H
/* All the enums defined here can be used in asset files */
typedef enum Vehicle {
VEHICLE_CAR,
VEHICLE_HOVERCRAFT,
VEHICLE_PLANE,
} Vehicle;
typedef enum Language {
LANGUAGE_ENGLISH,
LANGUAGE_GERMAN,
LANGUAGE_FRENCH,
LANGUAGE_JAPANESE,
} Language;
typedef enum World {
WORLD_NONE = -1, // This enum starts at -1 instead of 0.
WORLD_CENTRAL_AREA,
WORLD_DINO_DOMAIN,
WORLD_SHERBET_ISLAND,
WORLD_SNOWFLAKE_MOUNTAIN,
WORLD_DRAGON_FOREST,
WORLD_FUTURE_FUN_LAND,
} World;
typedef enum RaceType {
RACETYPE_DEFAULT = 0,
RACETYPE_HORSESHOE_GULCH = 3,
RACETYPE_HUBWORLD = 5,
RACETYPE_CUTSCENE_1 = 6, // Not sure what the difference between these two are.
RACETYPE_CUTSCENE_2 = 7,
RACETYPE_BOSS = 8,
RACETYPE_CHALLENGE_BATTLE = 64,
RACETYPE_CHALLENGE_BANANAS = 65,
RACETYPE_CHALLENGE_EGGS = 66,
} RaceType;
typedef enum HorizontalAlignmentFlags {
HORZ_ALIGN_LEFT = 0,
HORZ_ALIGN_RIGHT = 1,
HORZ_ALIGN_CENTER = 4,
} HorizontalAlignmentFlags;
typedef enum VerticalAlignmentFlags {
VERT_ALIGN_TOP = 0,
VERT_ALIGN_BOTTOM = 2,
VERT_ALIGN_MIDDLE = 8,
} VerticalAlignmentFlags;
typedef enum AlignmentFlags {
ALIGN_TOP_LEFT = VERT_ALIGN_TOP | HORZ_ALIGN_LEFT,
ALIGN_TOP_CENTER = VERT_ALIGN_TOP | HORZ_ALIGN_CENTER,
ALIGN_TOP_RIGHT = VERT_ALIGN_TOP | HORZ_ALIGN_RIGHT,
ALIGN_MIDDLE_LEFT = VERT_ALIGN_MIDDLE | HORZ_ALIGN_LEFT,
ALIGN_MIDDLE_CENTER = VERT_ALIGN_MIDDLE | HORZ_ALIGN_CENTER,
ALIGN_MIDDLE_RIGHT = VERT_ALIGN_MIDDLE | HORZ_ALIGN_RIGHT,
ALIGN_BOTTOM_LEFT = VERT_ALIGN_BOTTOM | HORZ_ALIGN_LEFT,
ALIGN_BOTTOM_CENTER = VERT_ALIGN_BOTTOM | HORZ_ALIGN_CENTER,
ALIGN_BOTTOM_RIGHT = VERT_ALIGN_BOTTOM | HORZ_ALIGN_RIGHT,
} AlignmentFlags;
#endif
+3 -5
View File
@@ -1,7 +1,5 @@
/n64crc
/dkr_decompressor
/dkr_cheats_encryptor
/dkr_extractor
/dkr_texbuilder
/dkr_assets_tool
/dkr_assets_tool_classes/_build
/binutils
/ido5.3_recomp
/ido5.3_recomp
+32 -24
View File
@@ -1,41 +1,49 @@
CC := gcc
CXX := g++
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s
CXXFLAGS := --std=c++17 -lstdc++fs -lcrypto -lssl -lpthread
LDFLAGS := -lm
PROGRAMS := n64crc
CXX_PROGRAMS := dkr_cheats_encryptor dkr_decompressor dkr_extractor dkr_texbuilder
CXX_PROGRAMS := dkr_assets_tool
BUILD_DIR := dkr_assets_tool_classes/_build
ENUMS_HEADER := ../include/enums.h
# From: https://stackoverflow.com/questions/2483182/recursive-wildcards-in-gnu-make/18258352#18258352
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
default: all
n64crc_SOURCES := n64crc.c
dkr_cheats_encryptor_SOURCES := dkr_cheats_encryptor.cpp
dkr_decompressor_SOURCES := dkr_decompressor.cpp $(wildcard dkr_decompressor_src/*.cpp dkr_decompressor_src/*.c)
dkr_decompressor_CXXFLAGS := -lstdc++fs -lcrypto -lssl
dkr_extractor_SOURCES := dkr_extractor.cpp $(wildcard dkr_decompressor_src/*.cpp dkr_decompressor_src/*.c dkr_extractor_classes/*.cpp n64graphics/*.c)
dkr_extractor_CXXFLAGS := -lstdc++fs -lcrypto -lssl -lpthread
dkr_texbuilder_SOURCES := dkr_texbuilder.cpp $(wildcard dkr_decompressor_src/*.cpp dkr_decompressor_src/*.c n64graphics/*.c)
dkr_texbuilder_CXXFLAGS := -lstdc++fs
all: $(PROGRAMS) $(CXX_PROGRAMS)
clean:
$(RM) $(PROGRAMS) $(CXX_PROGRAMS)
rm -Rf $(PROGRAMS) $(CXX_PROGRAMS) $(BUILD_DIR)
define COMPILE
$(1): $($1_SOURCES)
$(CC) $(CFLAGS) $($1_CFLAGS) $$^ -o $$@ $(LDFLAGS) $($1_LDFLAGS)
endef
distclean: clean
define COMPILE_CXX
$(1): $($1_SOURCES)
$(CXX) $$^ -o $$@ $($1_CXXFLAGS) $(LDFLAGS) $($1_LDFLAGS)
endef
n64crc: n64crc.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
$(foreach p,$(PROGRAMS),$(eval $(call COMPILE,$(p))))
$(foreach p,$(CXX_PROGRAMS),$(eval $(call COMPILE_CXX,$(p))))
dkr_assets_tool_CPP_FILES := dkr_assets_tool.cpp \
$(call rwildcard,dkr_assets_tool_classes,*.cpp)
dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_classes,*.c)
dkr_assets_tool_OBJ_FILES := $(foreach file,$(dkr_assets_tool_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) \
$(foreach file,$(dkr_assets_tool_CPP_FILES),$(BUILD_DIR)/$(file:.cpp=.o))
DUMMY != mkdir -p $(sort $(dir $(dkr_assets_tool_OBJ_FILES)))
$(BUILD_DIR)/%.o: %.c
$(CXX) -c $^ -o $@ $(CXXFLAGS) $(LDFLAGS)
$(BUILD_DIR)/%.o: %.cpp
$(CXX) -c $< -o $@ $(CXXFLAGS) $(LDFLAGS)
dkr_assets_tool: $(dkr_assets_tool_OBJ_FILES)
$(CXX) $^ -o $@ $(CXXFLAGS) $(LDFLAGS)
.PHONY: all clean distclean default
.PHONY: all clean default
+299
View File
@@ -0,0 +1,299 @@
/**
* This tool handles everything assets-related including extracting and building.
*/
#include <iostream>
#include <string>
#include <vector>
#include "dkr_assets_tool_classes/common/util.h"
#include "dkr_assets_tool_classes/extractor/extractor.h"
#include "dkr_assets_tool_classes/builder/builder.h"
#include "dkr_assets_tool_classes/make_asset_files/asset_enums_header.h"
#include "dkr_assets_tool_classes/make_asset_files/asset_asm_data.h"
#include "dkr_assets_tool_classes/compiler/compiler.h"
/**************************************************************************/
void print_usage() {
std::cout << "---- Usages -------------------------------------------------------------" << std::endl;
std::cout << "Extracting assets: ./dkr_assets_tool -e <version> <configs path> <baseroms path> <output path>" << std::endl;
std::cout << "Building an asset: ./dkr_assets_tool -b <version> <assets path> <source path> <output path>" << std::endl;
std::cout << "Creating includes: ./dkr_assets_tool -i <version> <assets path> <include directory> <build directory> <asm output directory>" << std::endl;
std::cout << "Compiling assets: ./dkr_assets_tool -c <version> <assets path>" << std::endl;
std::cout << "Compress file: ./dkr_assets_tool -fc <input_filename> <output_filename>" << std::endl;
std::cout << "Decompress file: ./dkr_assets_tool -fd <input_filename> <output_filename>" << std::endl;
std::cout << "-------------------------------------------------------------------------" << std::endl;
}
/**************************************************************************/
typedef enum _ToolType {
TT_DO_NOTHING,
TT_EXTRACT,
TT_BUILD,
TT_ASSET_INCLUDES,
TT_ASSET_COMPILE,
TT_ASSET_COMPRESS_FILE,
TT_ASSET_DECOMPRESS_FILE,
} ToolType;
typedef struct _CmdArgOptions {
ToolType type;
std::vector<std::string> paths;
} CmdArgOptions;
CmdArgOptions options;
/**************************************************************************/
typedef enum _CurrentParseOption {
PO_NONE,
PO_TYPE
} CurrentParseOption;
std::string get_cmd_from_parse_option(ToolType type) {
switch(type) {
case TT_EXTRACT: return "-e";
case TT_BUILD: return "-b";
case TT_ASSET_INCLUDES: return "-i";
case TT_ASSET_COMPILE: return "-c";
case TT_ASSET_COMPRESS_FILE: return "-fc";
case TT_ASSET_DECOMPRESS_FILE: return "-fd";
}
return "(Invalid option)";
}
bool parse_options(int argc, char *argv[]) {
std::vector<std::string> args(argv, argv+argc);
if(argc == 1) {
return false; // Display usage
}
// Parse options from command line.
bool parsingCmd = false;
int curOptionState = 0;
int curOptionArgs = 0;
CurrentParseOption curOption = PO_NONE;
for (size_t i = 1; i < args.size(); ++i) {
if(args[i][0] == '-') {
if(parsingCmd) {
display_error("Not enough args for the current command \"", get_cmd_from_parse_option(options.type), "\"");
return false;
}
if(args[i] == "-e") {
curOption = PO_TYPE;
curOptionState = 1;
options.type = TT_EXTRACT;
parsingCmd = true;
} else if(args[i] == "-b") {
curOption = PO_TYPE;
curOptionState = 2;
options.type = TT_BUILD;
parsingCmd = true;
} else if(args[i] == "-i") {
curOption = PO_TYPE;
curOptionState = 3;
options.type = TT_ASSET_INCLUDES;
parsingCmd = true;
} else if(args[i] == "-c") {
curOption = PO_TYPE;
curOptionState = 4;
options.type = TT_ASSET_COMPILE;
parsingCmd = true;
} else if(args[i] == "-fc") {
curOption = PO_TYPE;
curOptionState = 5;
options.type = TT_ASSET_COMPRESS_FILE;
parsingCmd = true;
} else if(args[i] == "-fd") {
curOption = PO_TYPE;
curOptionState = 6;
options.type = TT_ASSET_DECOMPRESS_FILE;
parsingCmd = true;
} else if(args[i] == "-h") {
return false;
} else {
display_error("Invalid option \"", args[i], "\"");
return false;
}
curOptionArgs = 0;
} else {
if(!parsingCmd) {
display_error("Too many args for the current command \"", get_cmd_from_parse_option(options.type), "\"");
return false;
}
switch(curOption) {
case PO_TYPE:
switch(curOptionState) {
case 1: // Extractor
switch(curOptionArgs) {
case 0: // version
case 1: // assets directory
case 2: // configs directory
case 3: // baseroms directory
options.paths.push_back(args[i]);
break;
case 4: // output
options.paths.push_back(args[i]);
// End of arguments.
parsingCmd = false;
curOption = PO_NONE;
break;
}
break;
case 2: // Builder
switch(curOptionArgs) {
case 0: // version
case 1: // assets directory
case 2: // source path
options.paths.push_back(args[i]);
break;
case 3: // output
options.paths.push_back(args[i]);
// End of arguments.
parsingCmd = false;
curOption = PO_NONE;
break;
}
break;
case 3: // Asset header
switch(curOptionArgs) {
case 0: // Assets directory
case 1: // Enum file output path
case 2: // Build directory
case 3: // Asm output directory
options.paths.push_back(args[i]);
break;
case 4: // DKR version
options.paths.push_back(args[i]);
// End of arguments.
parsingCmd = false;
curOption = PO_NONE;
break;
}
break;
case 4: // Compile assets
case 5: // Compress file
case 6: // Decompress file
switch(curOptionArgs) {
case 0: // Assets directory / Input filename
options.paths.push_back(args[i]);
break;
case 1: // version / Output filename
options.paths.push_back(args[i]);
// End of arguments.
parsingCmd = false;
curOption = PO_NONE;
break;
}
break;
}
break;
default: // This should hopefully never get called
display_error_and_abort("Invalid dkr_assets_tool option. You should not be seeing this message!");
}
curOptionArgs++;
}
}
if(parsingCmd) {
display_error("Not enough args for the current command \"", get_cmd_from_parse_option(options.type), "\"");
return false;
}
return true;
}
/**************************************************************************/
int main(int argc, char *argv[]) {
if(!parse_options(argc, argv)) {
print_usage();
return 1;
}
switch(options.type) {
case TT_EXTRACT:
{
std::string version = options.paths[0]; // us_1.0
std::string assetsDir = options.paths[1]; // <root>/assets
std::string configsPath = options.paths[2]; // <root>/extract-ver
std::string baseromsPath = options.paths[3]; // <root>/baseroms
std::string outputPath = options.paths[4]; // <root>
set_assets_folder_path(assetsDir + "/vanilla");
set_version(version);
Extractor extractor(version, configsPath, baseromsPath, outputPath);
}
break;
case TT_BUILD:
{
std::string version = options.paths[0]; // us_1.0
std::string assetsDir = options.paths[1]; // <root>/assets
std::string sourcePath = options.paths[2]; // Input .json filepath
std::string outputPath = options.paths[3]; // Output .bin filepath
set_assets_folder_path(assetsDir);
set_version(version);
Builder builder(sourcePath, outputPath);
}
break;
case TT_ASSET_INCLUDES:
{
std::string version = options.paths[0]; // us_1.0
std::string assetsDir = options.paths[1]; // <root>/assets
std::string includeDir = options.paths[2]; // <root>/include
std::string buildDir = options.paths[3]; // <root>/build
std::string assetsAsmDir = options.paths[4]; // <root>/asm/assets
set_assets_folder_path(assetsDir);
set_version(version);
AssetEnumsHeader assetEnumsHeader(includeDir);
AssetAsmIncludes assetAsmIncludes(assetsDir + "/" + version, buildDir + "/" + version, assetsAsmDir);
}
break;
case TT_ASSET_COMPILE:
{
std::string version = options.paths[0]; // us_1.0
std::string assetsDir = options.paths[1]; // <root>/assets
set_assets_folder_path(assetsDir);
set_version(version);
AssetCompiler compiler;
}
break;
case TT_ASSET_COMPRESS_FILE:
case TT_ASSET_DECOMPRESS_FILE:
{
DKRCompression compression;
std::string inputFilename = options.paths[0];
std::string outputFilename = options.paths[1];
std::vector<uint8_t> inputBinary, outputBinary;
if(compression.readBinaryFile(inputBinary, inputFilename)) {
if(inputBinary.size() == 0) {
compression.writeBinaryFile(inputBinary, outputFilename);
} else {
if (options.type == TT_ASSET_COMPRESS_FILE) {
outputBinary = compression.compressBuffer(inputBinary);
} else if (options.type == TT_ASSET_DECOMPRESS_FILE) {
outputBinary = compression.decompressBuffer(inputBinary);
}
compression.writeBinaryFile(outputBinary, outputFilename);
}
} else {
display_error_and_abort("Could not read file: ", inputFilename);
}
}
break;
}
return 0;
}
@@ -0,0 +1,137 @@
#include "build_fonts.h"
#define SIZEOF_FONTS_HEADER 4
// Note that these are just for DKR afaik. Other rare games have different sizes.
#define SIZEOF_FONT 0x400 // Larger in later Rare games
#define MAX_NUMBER_OF_TEXTURES 32 // Extended to 64 in later Rare games
#define CHAR_NODE_START_OFFSET 32
#define NUMBER_OF_CHAR_NODES 96 // Extended to 224 in later Rare games
#define CHAR_NODE_END_OFFSET CHAR_NODE_START_OFFSET + NUMBER_OF_CHAR_NODES
#define SIZEOF_CHAR_NODE 8
BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) {
std::string fontFolderPath = get_directory_from_full_path(srcPath);
std::vector<std::string> fontIds = get_array_from_section("ASSET_FONTS", "fonts-order");
int numberOfFonts = fontIds.size();
std::vector<uint8_t> out(align16(SIZEOF_FONT * numberOfFonts + SIZEOF_FONTS_HEADER));
// Write header.
write_big_endian_word(out, 0, numberOfFonts);
// Write fonts.
for(int font = 0; font < numberOfFonts; font++) {
std::string fontPath = fontFolderPath + "/" + get_string_from_json(srcPath, "fonts", fontIds[font]);
int fontOffset = font * SIZEOF_FONT + SIZEOF_FONTS_HEADER;
insert_ascii(out, fontOffset, get_string_from_json(fontPath, "name"));
write_big_endian_halfword(out, fontOffset + 0x20, get_int_from_json(fontPath, "fixed-width"));
write_big_endian_halfword(out, fontOffset + 0x22, get_int_from_json(fontPath, "y-offset"));
write_big_endian_halfword(out, fontOffset + 0x24, get_int_from_json(fontPath, "special-character-width"));
write_big_endian_halfword(out, fontOffset + 0x26, get_int_from_json(fontPath, "tab-width"));
insert_ascii(out, fontOffset + 0x28, get_string_from_json(fontPath, "unknown-text"));
int numberOfTextures = get_array_length_from_json(fontPath, "textures");
int texOffset = fontOffset + 0x40;
int texIndex = 0;
// Write texture ids.
for(; texIndex < numberOfTextures; texIndex++) {
write_big_endian_halfword(out, texOffset, get_tex_2d_index_from_build_id(get_string_from_json(fontPath, "textures", texIndex)));
texOffset += 2;
}
// Fill rest of the space with -1.
for(; texIndex < MAX_NUMBER_OF_TEXTURES; texIndex++) {
write_big_endian_halfword(out, texOffset, -1);
texOffset += 2;
}
std::string encoding = get_string_from_json(fontPath, "encoding", "type");
make_uppercase(encoding);
bool uppercaseOnly = false;
if(json_has_key(fontPath, "uppercase-only")) {
uppercaseOnly = get_bool_from_json(fontPath, "uppercase-only");
}
// Write character nodes
if(encoding == "ASCII") {
write_ascii_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly);
} else if(encoding == "CUSTOM") {
write_custom_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly);
} else {
display_error_and_abort("Unsupported font encoding type: \"", encoding, "\"");
}
}
write_binary_file(out, dstPath);
}
BuildFonts::~BuildFonts() {
}
void write_char_node(std::vector<uint8_t> &out, std::string fontPath, int nodeOffset, std::string &chr) {
if(json_has_key(fontPath, "characters", chr)) {
out[nodeOffset] = get_int_from_json(fontPath, "characters", chr, "tex-index");
out[nodeOffset + 1] = get_int_from_json(fontPath, "characters", chr, "char-width");
out[nodeOffset + 2] = get_int_from_json(fontPath, "characters", chr, "offset", 0); // X offset
out[nodeOffset + 3] = get_int_from_json(fontPath, "characters", chr, "offset", 1); // Y offset
out[nodeOffset + 4] = get_int_from_json(fontPath, "characters", chr, "uv", 0); // U coordinate
out[nodeOffset + 5] = get_int_from_json(fontPath, "characters", chr, "uv", 1); // V coordinate
out[nodeOffset + 6] = get_int_from_json(fontPath, "characters", chr, "tex-size", 0); // Width
out[nodeOffset + 7] = get_int_from_json(fontPath, "characters", chr, "tex-size", 1); // Height
} else { // Node doesn't exist, so just mark it as empty.
out[nodeOffset] = -1;
out[nodeOffset + 1] = 0;
out[nodeOffset + 2] = 0;
out[nodeOffset + 3] = 0;
out[nodeOffset + 4] = 0;
out[nodeOffset + 5] = 0;
out[nodeOffset + 6] = 0;
out[nodeOffset + 7] = 0;
}
}
void BuildFonts::write_ascii_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset, bool uppercaseOnly) {
for(int node = CHAR_NODE_START_OFFSET; node < CHAR_NODE_END_OFFSET; node++) {
std::string chr;
if(node == 127) {
chr = "DEL"; // Special case because the delete character itself is sometimes weird.
} else if (node == 92) {
chr = "\\\\";
} else if (node == 34) {
chr = "\\\"";
} else {
chr = (char)node;
}
int nodeOffset = offset + (node - CHAR_NODE_START_OFFSET) * SIZEOF_CHAR_NODE;
if(uppercaseOnly && node >= (int)'a' && node <= (int)'z') {
make_uppercase(chr);
}
write_char_node(out, fontPath, nodeOffset, chr);
}
}
void BuildFonts::write_custom_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset, bool uppercaseOnly) {
int index = 0;
std::vector<std::string> order = get_array_from_json(fontPath, "encoding", "order");
for(std::string &chr : order) {
if(index >= NUMBER_OF_CHAR_NODES) {
std::string fontName = get_string_from_json(fontPath, "name");
display_error_and_abort("Too many character nodes in ", fontName, ". The limit is ", NUMBER_OF_CHAR_NODES);
}
int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE);
write_char_node(out, fontPath, nodeOffset, chr);
}
// Set the rest of the nodes to show nothing.
while(index < NUMBER_OF_CHAR_NODES) {
int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE);
out[nodeOffset] = -1;
}
}
@@ -0,0 +1,13 @@
#pragma once
#include "../../common/util.h"
//#include "macros.h"
class BuildFonts {
public:
BuildFonts(std::string srcPath, std::string dstPath);
~BuildFonts();
private:
void write_ascii_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, bool uppercaseOnly);
void write_custom_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, bool uppercaseOnly);
};
@@ -0,0 +1,133 @@
#include "build_gametext.h"
// Dialog
#define END_OF_LINES 0x00
#define ACTIVE_LINE 0x01
#define CONTINUE 0x0C
// Textbox
#define NEXT_PAGE 0x01
BuildGameText::BuildGameText(std::string srcPath, std::string dstPath) {
std::vector<uint8_t> out;
// TODO: Figure this out!
std::string textType = get_string_from_json(srcPath, "text-type");
if(textType == "Dialog") {
// This is temporary until the game text format is figured out
int numRawBytes = get_array_length_from_json(srcPath, "raw");
for(int i = 0; i < numRawBytes; i++) {
out.push_back(get_int_from_json(srcPath, "raw", i));
}
//build_dialog(out, srcPath);
} else {
build_textbox(out, srcPath);
}
while(out.size() % 8 != 0) {
out.push_back(0); // Make sure the data is 8-byte aligned.
}
write_binary_file(out, dstPath);
}
BuildGameText::~BuildGameText() {
}
/*
void BuildGameText::build_dialog(std::vector<uint8_t> &out, std::string &srcPath) {
int numberOfLines = GET_ARRAY_LENGTH("lines");
for(int i = 0; i < numberOfLines; i++) {
if(inputJSON["lines"][i].JSONType() == json::JSON::Class::String) {
out.push_back(CONTINUE);
continue;
}
if(HAS_KEY("unknown-data", "lines", i)) { // Check if the key "unknown-data" exists.
for(int j = 0; j < GET_ARRAY_LENGTH("lines", i, "unknown-data"); j++) {
out.push_back(get_int_from_json(srcPath, "lines", i, "unknown-data", j));
}
break;
}
out.push_back(ACTIVE_LINE);
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "red"));
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "green"));
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "blue"));
out.push_back(get_int_from_json(srcPath, "lines", i, "color", "alpha"));
out.push_back(get_int_from_json(srcPath, "lines", i, "font"));
out.push_back(get_int_from_json(srcPath, "lines", i, "alignment"));
out.push_back((uint8_t)(GET_FLOAT("lines", i, "time") * 5));
write_ascii(out, get_string_from_json(srcPath, "lines", i, "text"));
//if(i < numberOfLines - 1 && !HAS_KEY("unknown-data", "lines", i + 1)) {
// out.push_back(CONTINUE);
//}
}
}
*/
void write_basic_command(std::vector<uint8_t> &out, uint8_t cmdId, uint8_t value) {
out.push_back(cmdId);
out.push_back(value);
}
void write_basic_command_4_args(std::vector<uint8_t> &out, uint8_t cmdId, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
out.push_back(cmdId);
out.push_back(a);
out.push_back(b);
out.push_back(c);
out.push_back(d);
}
void BuildGameText::build_textbox(std::vector<uint8_t> &out, std::string &srcPath) {
int numberOfPages = get_array_length_from_json(srcPath, "pages");
for(int page = 0; page < numberOfPages; page++) {
int numberOfCommandsInPage = get_array_length_from_json(srcPath, "pages", page);
for(int cmd = 0; cmd < numberOfCommandsInPage; cmd++) {
std::string cmdType = get_string_from_json(srcPath, "pages", page, cmd, "command");
if(cmdType == "Text") {
write_ascii(out, get_string_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "SetFont") {
std::string fontId = get_string_from_json(srcPath, "pages", page, cmd, "value");
int fontIndex = get_index_of_string_array_value_from_section("ASSET_FONTS", fontId, "fonts-order");
if(fontIndex == -1) {
display_error_and_abort("Could not find the font \"", fontId, "\" in the \"fonts-order\" array in asset_fonts.json.");
}
write_basic_command(out, 3, fontIndex);
} else if(cmdType == "SetBorder") {
write_basic_command_4_args(out, 4,
get_int_from_json(srcPath, "pages", page, cmd, "value", "left"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "top"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "right"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "bottom")
);
} else if(cmdType == "SetColour") {
write_basic_command_4_args(out, 5,
get_int_from_json(srcPath, "pages", page, cmd, "value", "red"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "green"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "blue"),
get_int_from_json(srcPath, "pages", page, cmd, "value", "alpha")
);
} else if(cmdType == "SetAlignment") {
write_basic_command(out, 6, get_string_from_json(srcPath, "pages", page, cmd, "value") == "center" ? 0 : 4);
} else if(cmdType == "Unknown") {
write_basic_command(out, 7, get_int_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "AddVerticalSpacing") {
write_basic_command(out, 8, get_int_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "SetLineHeight") {
write_basic_command(out, 9, get_int_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "SetTimer") {
write_basic_command(out, 10, get_int_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "AllowUserInput") {
write_basic_command(out, 11, get_bool_from_json(srcPath, "pages", page, cmd, "value") ? 1 : 0);
}
}
if(page < numberOfPages - 1) {
out.push_back(NEXT_PAGE);
}
}
}
@@ -0,0 +1,14 @@
#pragma once
#include "../../common/util.h"
class BuildGameText {
public:
BuildGameText(std::string srcPath, std::string dstPath);
~BuildGameText();
private:
/*
void build_dialog(std::vector<uint8_t> &out, std::string &srcPath);
*/
void build_textbox(std::vector<uint8_t> &out, std::string &srcPath);
};
@@ -0,0 +1,116 @@
#include "build_levelheader.h"
#define GET_UNKNOWN_VALUE(name, index) get_int_from_json(srcPath, "unknown-data", name, index)
#define GET_UNKNOWN_VALUES(out, start, end, name) \
for(int i = start; i < end; i++) { \
out[i] = GET_UNKNOWN_VALUE(name, i - start); \
}
int get_bitfield_from_enum_values(std::string &srcPath, std::string propertyName, std::string enumName) {
int numEntries = get_array_length_from_json(srcPath, propertyName);
int out = 0;
for(int i = 0; i < numEntries; i++) {
out |= 1 << get_enum_value_from_string(enumName, get_string_from_json(srcPath, propertyName, i));
}
return out;
}
BuildLevelHeader::BuildLevelHeader(std::string srcPath, std::string dstPath) {
std::vector<uint8_t> out(SIZEOF_LEVEL_HEADER);
// World ID
out[0] = get_enum_value_from_string("World", get_string_from_json(srcPath, "world"));
out[1] = get_int_from_json(srcPath, "unknown-data", "unk1");
out[2] = get_int_from_json(srcPath, "unknown-data", "unk2");
out[3] = get_int_from_json(srcPath, "unknown-data", "unk3");
GET_UNKNOWN_VALUES(out, 4, 8, "unk4");
// Ceiling height for planes
write_big_endian_float(out, 8, get_float_from_json(srcPath, "ceiling-height"));
GET_UNKNOWN_VALUES(out, 0xC, 0x34, "unkC");
// Track ID to use
write_big_endian_halfword(out, 0x34, get_index_from_build_id("ASSET_LEVEL_MODELS", get_string_from_json(srcPath, "model")));
// Collectables bitflags (bananas, balloons, etc)
write_big_endian_halfword(out, 0x36, get_int_from_json(srcPath, "collectables"));
// Skydome object model ID
write_big_endian_halfword(out, 0x38, get_int_from_json(srcPath, "skybox"));
// Fog
write_big_endian_halfword(out, 0x3A, get_int_from_json(srcPath, "fog", "range", "min"));
write_big_endian_halfword(out, 0x3C, get_int_from_json(srcPath, "fog", "range", "max"));
write_big_endian_halfword(out, 0x3E, get_int_from_json(srcPath, "fog", "colour", "red"));
write_big_endian_halfword(out, 0x40, get_int_from_json(srcPath, "fog", "colour", "green"));
write_big_endian_halfword(out, 0x42, get_int_from_json(srcPath, "fog", "colour", "blue"));
GET_UNKNOWN_VALUES(out, 0x44, 0x4B, "unk44");
// Number of laps to complete the race.
out[0x4B] = get_int_from_json(srcPath, "number-laps");
// Type of race (standard, boss race, hub world, etc.
out[0x4C] = get_enum_value_from_string("RaceType", get_string_from_json(srcPath, "race-type"));
// Default vehicle used for this track. (Either Car, Hovercraft, or Plane)
out[0x4D] = get_enum_value_from_string("Vehicle", get_string_from_json(srcPath, "default-vehicle"));
// Which vehicles can be used in this track (Either Car, Hovercraft, or Plane)
out[0x4E] = get_bitfield_from_enum_values(srcPath, "available-vehicles", "Vehicle");
GET_UNKNOWN_VALUES(out, 0x4F, 0x52, "unk4F");
// Music ID to use for this track
out[0x52] = get_int_from_json(srcPath, "music");
// Unknown, but *probably* related to audio.
out[0x53] = get_int_from_json(srcPath, "unknown-data", "unk53");
// Instruments bitflags. Most levels have 0xFFFF, except for the central hub which is 0xB
write_big_endian_halfword(out, 0x54, get_int_from_json(srcPath, "instruments"));
GET_UNKNOWN_VALUES(out, 0x56, 0x74, "unk56");
for(int i = 0; i < 7; i++) {
write_big_endian_word(out, 0x74 + (i * 4), get_int_from_json(srcPath, "unknown-data", "unk74", i));
}
// Weather values currently unknown.
write_big_endian_halfword(out, 0x90, get_int_from_json(srcPath, "unknown-data", "weather", "unk90"));
write_big_endian_halfword(out, 0x92, get_int_from_json(srcPath, "unknown-data", "weather", "unk92"));
out[0x94] = get_int_from_json(srcPath, "unknown-data", "weather", "unk94");
out[0x95] = get_int_from_json(srcPath, "unknown-data", "weather", "unk95");
write_big_endian_halfword(out, 0x96, get_int_from_json(srcPath, "unknown-data", "weather", "unk96"));
write_big_endian_halfword(out, 0x98, get_int_from_json(srcPath, "unknown-data", "weather", "unk98"));
write_big_endian_halfword(out, 0x9A, get_int_from_json(srcPath, "unknown-data", "weather", "unk9A"));
// Field of view
out[0x9C] = get_int_from_json(srcPath, "fov");
// Background clear color
out[0x9D] = get_int_from_json(srcPath, "background-colour", "red");
out[0x9E] = get_int_from_json(srcPath, "background-colour", "green");
out[0x9F] = get_int_from_json(srcPath, "background-colour", "blue");
GET_UNKNOWN_VALUES(out, 0xA0, 0xA4, "unkA0");
write_big_endian_word(out, 0xA4, get_int_from_json(srcPath, "unknown-data", "unkA4"));
write_big_endian_halfword(out, 0xA8, get_int_from_json(srcPath, "unknown-data", "unkA8"));
write_big_endian_halfword(out, 0xAA, get_int_from_json(srcPath, "unknown-data", "unkAA"));
// Pulsating lights are only used in spaceport alpha
int pulsatingLights = -1;
if(json_has_key(srcPath, "pulsating-lights")) {
pulsatingLights = get_index_from_build_id("ASSET_MISC", get_string_from_json(srcPath, "pulsating-lights"));
}
write_big_endian_word(out, 0xAC, pulsatingLights);
GET_UNKNOWN_VALUES(out, 0xB0, 0xC4, "unkB0");
write_big_endian_word(out, 0xC4, get_int_from_json(srcPath, "unknown-data", "unkC4"));
write_binary_file(out, dstPath);
}
BuildLevelHeader::~BuildLevelHeader() {
}
@@ -0,0 +1,11 @@
#pragma once
#include "../../common/util.h"
#define SIZEOF_LEVEL_HEADER 0xC8
class BuildLevelHeader {
public:
BuildLevelHeader(std::string srcPath, std::string dstPath);
~BuildLevelHeader();
};
@@ -0,0 +1,32 @@
#include "build_levelname.h"
BuildLevelName::BuildLevelName(std::string srcPath, std::string dstPath) {
std::vector<uint8_t> out;
std::vector<std::string> languages = get_enum_keys("Language");
int numLangWritten = 0;
// Search through and add all the avaliable languages.
// Note: If a language is not defined in the enum, then it won't be added to the output!
for(auto &langName : languages) {
if(json_has_key(srcPath, "languages", langName)) { // Check if the level name json has the language.
write_ascii(out, get_string_from_json(srcPath, "languages", langName));
numLangWritten++;
} else {
// Language not found. For now, this means the text will be empty.
// TODO: Maybe have an option to default to english?
out.push_back('\0'); // Push back a null terminator
}
}
if(numLangWritten == 0) {
std::cout << "Warning: No languages were found." << std::endl;
}
write_binary_file(out, dstPath);
}
BuildLevelName::~BuildLevelName() {
}
@@ -0,0 +1,9 @@
#pragma once
#include "../../common/util.h"
class BuildLevelName {
public:
BuildLevelName(std::string srcPath, std::string dstPath);
~BuildLevelName();
};
@@ -0,0 +1,46 @@
#include "build_menutext.h"
BuildMenuText::BuildMenuText(std::string srcPath, std::string dstPath) {
//int numberOfEntries = get_array_length_from_json(srcPath, "order");
std::vector<std::string> ids = get_array_from_section("ASSET_MENU_TEXT", "menu-text-build-ids");
int numberOfEntries = ids.size();
std::vector<uint8_t> table(numberOfEntries * 4);
std::vector<uint8_t> text;
int textOffset = numberOfEntries * 4;
for(int i = 0; i < numberOfEntries; i++) {
// Get the build id for this index.
std::string buildId = ids[i];
// If the build ID is not in the sections, then just write -1 to the table.
if(!json_has_key(srcPath, "sections", buildId)) {
write_big_endian_word(table, i * 4, -1);
continue;
}
// Get the text string from the inputJSON.
std::string entryText = get_string_from_json(srcPath, "sections", buildId);
// Write ascii text to vector
write_ascii(text, entryText);
// Write the offset to the text
write_big_endian_word(table, i * 4, textOffset);
// Increment the current offset by the length of the string (+1 for null terminator)
textOffset += entryText.length() + 1;
}
// Append the text data to the table data.
table.insert(table.end(), text.begin(), text.end());
while(table.size() % 8 != 0) {
table.push_back(0); // Make sure the data is 8-byte aligned.
}
write_binary_file(table, dstPath);
}
BuildMenuText::~BuildMenuText(){
}
@@ -0,0 +1,9 @@
#pragma once
#include "../../common/util.h"
class BuildMenuText {
public:
BuildMenuText(std::string srcPath, std::string dstPath);
~BuildMenuText();
};

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