diff --git a/Dockerfile b/Dockerfile index b3200018c..eddd89b91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ FROM ubuntu:18.04 as build -RUN apt-get update && \ - apt-get install -y \ +RUN apt update && \ + apt upgrade -y && \ + apt install -y --install-recommends --install-suggests \ binutils-mips-linux-gnu \ bsdmainutils \ build-essential \ diff --git a/Makefile b/Makefile index 621aedd9a..f004e1d4b 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,10 @@ TARGET_BITS ?= 0 BETTERCAMERA ?= 0 # Disable no drawing distance by default NODRAWINGDISTANCE ?= 0 -# Disable texture fixes by default (helps with them purists) -TEXTURE_FIX ?= 0 +# Disable QoL fixes by default (helps with them purists) +QOL_FIXES ?= 0 +# Disable unused play state tweak by default +USE_UNUSED_PLAY_STATE ?= 0 # Enable extended options menu by default EXT_OPTIONS_MENU ?= 1 # Disable text-based save-files by default @@ -103,7 +105,7 @@ ifeq ($(WINDOWS_BUILD),1) TARGET_BITS = 32 NO_BZERO_BCOPY := 1 else ifeq ($(CROSS),x86_64-w64-mingw32.static-) - TARGET_ARCH = i386pe + TARGET_ARCH = i386pep TARGET_BITS = 64 NO_BZERO_BCOPY := 1 endif @@ -117,24 +119,18 @@ endif ifeq ($(VERSION),jp) VERSION_DEF := VERSION_JP -else -ifeq ($(VERSION),us) +else ifeq ($(VERSION),us) VERSION_DEF := VERSION_US -else -ifeq ($(VERSION),eu) +else ifeq ($(VERSION),eu) VERSION_DEF := VERSION_EU -else -ifeq ($(VERSION),sh) +else ifeq ($(VERSION),sh) $(warning Building SH is experimental and is prone to breaking. Try at your own risk.) VERSION_DEF := VERSION_SH -# TODO: GET RID OF THIS!!! We should mandate assets for Shindou like EU but we dont have the addresses extracted yet so we'll just pretend you have everything extracted for now. +# TODO: GET RID OF THIS!!! We should mandate assets for Shindou like EU, but we don't have the addresses extracted yet, so we'll just pretend you have everything extracted for now. NOEXTRACT := 1 else $(error unknown version "$(VERSION)") endif -endif -endif -endif TARGET := sm64.$(VERSION) VERSION_CFLAGS := -D$(VERSION_DEF) -D_LANGUAGE_C @@ -155,38 +151,38 @@ ifeq ($(GRUCODE),f3dex) # Fast3DEX GRUCODE_ASFLAGS := --defsym F3DEX_GBI_SHARED=1 TARGET := $(TARGET).f3dex COMPARE := 0 -else -ifeq ($(GRUCODE),f3dex2) # Fast3DEX2 +else ifeq ($(GRUCODE),f3dex2) # Fast3DEX2 GRUCODE_DEF := F3DEX_GBI_2 GRUCODE_ASFLAGS := --defsym F3DEX_GBI_SHARED=1 TARGET := $(TARGET).f3dex2 COMPARE := 0 -else -ifeq ($(GRUCODE),f3dex2e) # Fast3DEX2 Extended (PC default) +else ifeq ($(GRUCODE),f3dex2e) # Fast3DEX2 Extended (PC default) GRUCODE_DEF := F3DEX_GBI_2E TARGET := $(TARGET).f3dex2e COMPARE := 0 -else -ifeq ($(GRUCODE),f3d_new) # Fast3D 2.0H (Shindou) +else ifeq ($(GRUCODE),f3d_old) # Fast3D 2.0D (US, EU, JP) + GRUCODE_DEF := F3D_OLD + TARGET := $(TARGET).f3d_old + COMPARE := 0 +else ifeq ($(GRUCODE),f3d_new) # Fast3D 2.0H (Shindou) GRUCODE_DEF := F3D_NEW TARGET := $(TARGET).f3d_new COMPARE := 0 -else -ifeq ($(GRUCODE),f3dzex) # Fast3DZEX (2.0J / Animal Forest - Dōbutsu no Mori) +else ifeq ($(GRUCODE),f3dzex) # Fast3DZEX (2.0J / Animal Forest - Dōbutsu no Mori) $(warning Fast3DZEX is experimental. Try at your own risk.) GRUCODE_DEF := F3DEX_GBI_2 GRUCODE_ASFLAGS := --defsym F3DEX_GBI_SHARED=1 TARGET := $(TARGET).f3dzex COMPARE := 0 endif -endif -endif -endif -endif GRUCODE_CFLAGS := -D$(GRUCODE_DEF) GRUCODE_ASFLAGS := $(GRUCODE_ASFLAGS) --defsym $(GRUCODE_DEF)=1 +ifeq ($(USE_UNUSED_PLAY_STATE),1) + TARGET := $(TARGET).unused_play_state_enabled +endif + # Default build is for PC now VERSION_CFLAGS := $(VERSION_CFLAGS) -DNON_MATCHING -DAVOID_UB @@ -195,7 +191,7 @@ ifeq ($(TARGET_RPI),1) # Define RPi to change SDL2 title & GLES2 hints endif ifeq ($(OSX_BUILD),1) # Modify GFX & SDL2 for OSX GL - VERSION_CFLAGS += -DOSX_BUILD + VERSION_CFLAGS += -DOSX_BUILD endif VERSION_ASFLAGS := --defsym AVOID_UB=1 @@ -227,8 +223,7 @@ endif # on tools and assets, and we use directory globs further down # in the makefile that we want should cover assets.) -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(MAKECMDGOALS),distclean) +ifeq (,$(findstring clean,$(MAKECMDGOALS))) # Make sure assets exist NOEXTRACT ?= 0 @@ -245,7 +240,6 @@ ifeq ($(DUMMY),FAIL) $(error Failed to build tools) endif -endif endif ################ Target Executable and Sources ############### @@ -262,18 +256,13 @@ endif LIBULTRA := $(BUILD_DIR)/libultra.a ifeq ($(TARGET_WEB),1) -EXE := $(BUILD_DIR)/$(TARGET).html - else - ifeq ($(WINDOWS_BUILD),1) - EXE := $(BUILD_DIR)/$(TARGET).exe - - else # Linux builds/binary namer - ifeq ($(TARGET_RPI),1) - EXE := $(BUILD_DIR)/$(TARGET).arm - else - EXE := $(BUILD_DIR)/$(TARGET) - endif - endif + EXE := $(BUILD_DIR)/$(TARGET).html +else ifeq ($(WINDOWS_BUILD),1) + EXE := $(BUILD_DIR)/$(TARGET).exe +else ifeq ($(TARGET_RPI),1) # Linux builds/binary namer + EXE := $(BUILD_DIR)/$(TARGET).arm +else + EXE := $(BUILD_DIR)/$(TARGET) endif ELF := $(BUILD_DIR)/$(TARGET).elf @@ -322,31 +311,29 @@ ifeq ($(TARGET_RPI),1) machine = $(shell sh -c 'uname -m 2>/dev/null || echo unknown') # Raspberry Pi B+, Zero, etc ifneq (,$(findstring armv6l,$(machine))) - OPT_FLAGS := -march=armv6zk+fp -mfpu=vfp -Ofast - endif + OPT_FLAGS := -march=armv6zk+fp -mfpu=vfp -Ofast + endif # Raspberry Pi 2 and 3 in ARM 32bit mode - ifneq (,$(findstring armv7l,$(machine))) - model = $(shell sh -c 'cat /sys/firmware/devicetree/base/model 2>/dev/null || echo unknown') - - ifneq (,$(findstring 3,$(model))) - OPT_FLAGS := -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -O3 - else - OPT_FLAGS := -march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -O3 - endif - endif + ifneq (,$(findstring armv7l,$(machine))) + model = $(shell sh -c 'cat /sys/firmware/devicetree/base/model 2>/dev/null || echo unknown') + ifneq (,$(findstring 3,$(model))) + OPT_FLAGS := -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -O3 + else + OPT_FLAGS := -march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -O3 + endif + endif # RPi3 or RPi4, in ARM64 (aarch64) mode. NEEDS TESTING 32BIT. -# DO NOT pass -mfpu stuff here, thats for 32bit ARM only and will fail for 64bit ARM. - ifneq (,$(findstring aarch64,$(machine))) - model = $(shell sh -c 'cat /sys/firmware/devicetree/base/model 2>/dev/null || echo unknown') - ifneq (,$(findstring 3,$(model))) - OPT_FLAGS := -march=armv8-a+crc -mtune=cortex-a53 -O3 - else ifneq (,$(findstring 4,$(model))) - OPT_FLAGS := -march=armv8-a+crc+simd -mtune=cortex-a72 -O3 - endif - - endif +# DO NOT pass -mfpu stuff here, that's for 32bit ARM only and will fail for 64bit ARM. + ifneq (,$(findstring aarch64,$(machine))) + model = $(shell sh -c 'cat /sys/firmware/devicetree/base/model 2>/dev/null || echo unknown') + ifneq (,$(findstring 3,$(model))) + OPT_FLAGS := -march=armv8-a+crc -mtune=cortex-a53 -O3 + else ifneq (,$(findstring 4,$(model))) + OPT_FLAGS := -march=armv8-a+crc+simd -mtune=cortex-a72 -O3 + endif + endif endif # File dependencies and variables for specific files @@ -468,8 +455,8 @@ ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL OBJDUMP := $(CROSS)objdump else ifeq ($(OSX_BUILD),1) CPP := cpp-9 -P - OBJDUMP := i686-w64-mingw32-objdump OBJCOPY := i686-w64-mingw32-objcopy + OBJDUMP := i686-w64-mingw32-objdump else # Linux & other builds CPP := $(CROSS)cpp -P OBJCOPY := $(CROSS)objcopy @@ -484,7 +471,7 @@ SDLCONFIG := $(CROSS)sdl2-config BACKEND_CFLAGS := -DRAPI_$(RENDER_API)=1 -DWAPI_$(WINDOW_API)=1 -DAAPI_$(AUDIO_API)=1 # can have multiple controller APIs BACKEND_CFLAGS += $(foreach capi,$(CONTROLLER_API),-DCAPI_$(capi)=1) -BACKEND_LDFLAG0S := +BACKEND_LDFLAGS := SDL1_USED := 0 SDL2_USED := 0 @@ -541,16 +528,15 @@ ifneq ($(SDL1_USED)$(SDL2_USED),00) endif ifeq ($(WINDOWS_BUILD),1) - CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) + CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv else ifeq ($(TARGET_WEB),1) - CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2 + CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -s USE_SDL=2 CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv -s USE_SDL=2 -# Linux / Other builds below -else - CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra -Wno-format-security $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) +else # Linux / Other builds below + CC_CHECK := $(CC) -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(INCLUDE_CFLAGS) -Wall -Wextra $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) CFLAGS := $(OPT_FLAGS) $(INCLUDE_CFLAGS) $(BACKEND_CFLAGS) $(VERSION_CFLAGS) $(GRUCODE_CFLAGS) -fno-strict-aliasing -fwrapv endif @@ -564,6 +550,7 @@ ifeq ($(BETTERCAMERA),1) EXT_OPTIONS_MENU := 1 endif +# Check for text saves option ifeq ($(TEXTSAVES),1) CC_CHECK += -DTEXTSAVES CFLAGS += -DTEXTSAVES @@ -581,10 +568,16 @@ ifeq ($(DISCORDRPC),1) CFLAGS += -DDISCORDRPC endif -# Check for texture fix option -ifeq ($(TEXTURE_FIX),1) - CC_CHECK += -DTEXTURE_FIX - CFLAGS += -DTEXTURE_FIX +# Check for QoL fix option +ifeq ($(QOL_FIXES),1) + CC_CHECK += -DQOL_FIXES + CFLAGS += -DQOL_FIXES +endif + +# Check for unused play state option +ifeq ($(USE_UNUSED_PLAY_STATE),1) + CC_CHECK += -DUSE_UNUSED_PLAY_STATE + CFLAGS += -DUSE_UNUSED_PLAY_STATE endif # Check for extended options menu option @@ -642,7 +635,7 @@ else ifeq ($(OSX_BUILD),1) else LDFLAGS := $(BITS) -march=$(TARGET_ARCH) -lm $(BACKEND_LDFLAGS) -lpthread -ldl - ifeq ($(NO_PIE), 1) + ifeq ($(NO_PIE),1) LDFLAGS += -no-pie endif @@ -724,7 +717,7 @@ clean: $(RM) -r $(BUILD_DIR_BASE) cleantools: - $(MAKE) -s -C tools clean + $(MAKE) -C tools clean distclean: $(RM) -r $(BUILD_DIR_BASE) @@ -770,8 +763,7 @@ $(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/us/define_courses.inc.c $(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/de/define_courses.inc.c $(BUILD_DIR)/levels/menu/leveldata.o: $(BUILD_DIR)/text/fr/define_courses.inc.c -else -ifeq ($(VERSION),sh) +else ifeq ($(VERSION),sh) TEXT_DIRS := text/jp $(BUILD_DIR)/bin/segment2.o: $(BUILD_DIR)/text/jp/define_text.inc.c @@ -781,13 +773,12 @@ TEXT_DIRS := text/$(VERSION) # non-EU encoded text inserted into segment 0x02 $(BUILD_DIR)/bin/segment2.o: $(BUILD_DIR)/text/$(VERSION)/define_text.inc.c endif -endif $(BUILD_DIR)/text/%/define_courses.inc.c: text/define_courses.inc.c text/%/courses.h $(CPP) $(VERSION_CFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) charmap.txt - $@ $(BUILD_DIR)/text/%/define_text.inc.c: text/define_text.inc.c text/%/courses.h text/%/dialogs.h - $(CPP) $(VERSION_CFLAGS) $< -o - -I text/$*/ | $(TEXTCONV) charmap.txt - $@ + $(CPP) $(VERSION_CFLAGS) -Wno-trigraphs $< -o - -I text/$*/ | $(TEXTCONV) charmap.txt - $@ RSP_DIRS := $(BUILD_DIR)/rsp ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(TEXT_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS) @@ -918,8 +909,13 @@ $(BUILD_DIR)/include/level_headers.h: levels/level_headers.h.in $(BUILD_DIR)/assets/mario_anim_data.c: $(wildcard assets/anims/*.inc.c) $(PYTHON) tools/mario_anims_converter.py > $@ +ifneq ($(QOL_FIXES),1) $(BUILD_DIR)/assets/demo_data.c: assets/demo_data.json $(wildcard assets/demos/*.bin) $(PYTHON) tools/demo_data_converter.py assets/demo_data.json $(VERSION_CFLAGS) > $@ +else +$(BUILD_DIR)/assets/demo_data.c: assets/qol_demo_data.json $(wildcard assets/demos/*.bin) + $(PYTHON) tools/demo_data_converter.py assets/qol_demo_data.json $(VERSION_CFLAGS) > $@ +endif # Source code $(BUILD_DIR)/levels/%/leveldata.o: OPT_FLAGS := -g @@ -996,7 +992,7 @@ $(BUILD_DIR)/%.o: %.s $(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS) $(LD) -L $(BUILD_DIR) -o $@ $(O_FILES) $(SOUND_OBJ_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS) -.PHONY: all clean distclean default diff test load libultra res +.PHONY: all clean distclean cleantools default diff test load libultra res .PRECIOUS: $(BUILD_DIR)/bin/%.elf $(SOUND_BIN_DIR)/%.ctl $(SOUND_BIN_DIR)/%.tbl $(SOUND_SAMPLE_TABLES) $(SOUND_BIN_DIR)/%.s $(BUILD_DIR)/% .DELETE_ON_ERROR: diff --git a/Makefile.split b/Makefile.split index 609222f0c..d67c6cbb3 100644 --- a/Makefile.split +++ b/Makefile.split @@ -145,13 +145,11 @@ define level_rules = $$(BUILD_DIR)/levels/$(1)/leveldata.elf: TEXTURE_BIN := $(2) endef -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(MAKECMDGOALS),distclean) +ifeq (,$(findstring clean,$(MAKECMDGOALS))) $(BUILD_DIR)/level_rules.mk: levels/level_rules.mk levels/level_defines.h $(CPP) $(VERSION_CFLAGS) -I . -o $@ $< include $(BUILD_DIR)/level_rules.mk endif -endif # -------------------------------------- # Extra Level Rules diff --git a/README.md b/README.md index 1a99617fd..45fee8d1b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # sm64ex -Fork of [sm64-port/sm64-port](https://github.com/sm64-port/sm64-port) with additional features. -Feel free to report bugs and contribute, but remember, there must be **no upload of any copyrighted asset**. +Fork of [sm64-port/sm64-port](https://github.com/sm64-port/sm64-port) with additional features. + +Feel free to report bugs and contribute, but remember, there must be **no upload of any copyrighted asset**. Run `./extract_assets.py --clean && make clean` or `make distclean` to remove ROM-originated content. Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm64ex/tree/nightly/). New functionality will be merged to master once they're considered to be well-tested. @@ -10,21 +11,22 @@ Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm ## New features - * Options menu with various settings, including button remapping. - * Optional external data loading (so far only textures and assembled soundbanks), providing support for custom texture packs. - * Optional analog camera and mouse look (using [Puppycam](https://github.com/FazanaJ/puppycam)). - * Optional OpenGL1.3-based renderer for older machines, as well as the original GL2.1, D3D11 and D3D12 renderers from Emill's [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/). - * Option to disable drawing distances. - * Optional model and texture fixes (e.g. the smoke texture). - * Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option - * Cheats menu in Options (activate with `--cheats` or by pressing L thrice in the pause menu). - * Support for both little-endian and big-endian save files (meaning you can use save files from both sm64-port and most emulators), as well as an optional text-based save format. +* Options menu with various settings, including button remapping. +* Optional external data loading (so far only textures and assembled soundbanks), providing support for custom texture packs. +* Optional analog camera and mouse look (using [Puppycam](https://github.com/FazanaJ/puppycam)). +* Optional OpenGL1.3-based renderer for older machines, as well as the original GL2.1, D3D11 and D3D12 renderers from Emill's [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/). +* Option to disable drawing distances. +* Optional QoL fixes (e.g. the smoke texture and the BitDW trapdoor sound). +* Skip introductory Peach & Lakitu cutscenes with the `--skip-intro` CLI option +* Cheats menu in Options (activate with `--cheats` or by pressing L thrice in the pause menu). +* Support for both little-endian and big-endian save files (meaning you can use save files from both sm64-port and most emulators), as well as an optional text-based save format. Recent changes in Nightly have moved the save and configuration file path to `%HOMEPATH%\AppData\Roaming\sm64ex` on Windows and `$HOME/.local/share/sm64ex` on Linux. This behaviour can be changed with the `--savepath` CLI option. For example `--savepath .` will read saves from the current directory (which not always matches the exe directory, but most of the time it does); `--savepath '!'` will read saves from the executable directory. ## Building + For building instructions, please refer to the [wiki](https://github.com/sm64pc/sm64ex/wiki). -**Make sure you have MXE first before attempting to compile for Windows on Linux and WSL. Follow the guide on the wiki.** +**Make sure you have [MXE](https://mxe.cc) or mingw-w64 first before attempting to compile for Windows on Linux and WSL. Follow the guide on the wiki.** diff --git a/README_es_ES.md b/README_es_ES.md index 44a34a1c5..7e8b39920 100644 --- a/README_es_ES.md +++ b/README_es_ES.md @@ -1,205 +1,258 @@ # sm64pc -Adaptación a OpenGL de [n64decomp/sm64](https://github.com/n64decomp/sm64). -No dudes en contribuir o reportar bugs, pero recuerda: **no se debe subir nada con copyright**. -Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borrar todo el contenido proveniente de la ROM. Este port es posible gracias a [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/) creado por [Emill](https://github.com/Emill). +Adaptación a OpenGL de [n64decomp/sm64](https://github.com/n64decomp/sm64). + +No dudes en contribuir o reportar bugs, pero recuerda: **no se debe subir nada con copyright**. +Ejecuta `./extract_assets.py --clean && make clean` o `make distclean` para borrar todo el contenido proveniente de la ROM. Este port es posible gracias a [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/) creado por [Emill](https://github.com/Emill). ## Funcionalidades - * Renderizado nativo. Podrás jugar a Super Mario 64 sin necesidad de un emulador. - * Resolución y relación de aspecto variables. Puedes jugar a Super Mario 64 a básicamente cualquier resolución o tamaño de ventana. - * Soporte nativo para mandos XInput. En Linux, se ha confirmado que el DualShock 4 funciona sin más. - * Cámara analógica y cámara controlada con el ratón. (Se activa con `make BETTERCAMERA=1`.) - * Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.) - * Configurar los controles desde el juego. - * Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro` - * Menú de trucos (_cheats_) en _options_. (Se activa con la opción de línea de comandos `--cheats`) Ten en cuenta que si un cheat te pide pulsar el botón "L", se refiere al botón de N64, el cual tendrá que estar asignado a un botón de tu mando. Ve a los ajustes de control y asegúrate de que tienes "L" mapeado a un botón de tu mando. +* Renderizado nativo. Podrás jugar a Super Mario 64 sin necesidad de un emulador. +* Resolución y relación de aspecto variables. Puedes jugar a Super Mario 64 a básicamente cualquier resolución o tamaño de ventana. +* Soporte nativo para mandos XInput. En Linux, se ha confirmado que el DualShock 4 funciona sin más. +* Cámara analógica y cámara controlada con el ratón. (Se activa con `make BETTERCAMERA=1`.) +* Opción para desactivar el límite de distancia de renderizado. (Se activa con `make NODRAWINGDISTANCE=1`.) +* Configurar los controles desde el juego. +* Posibilidad de saltarte la intro con la opción de línea de comandos `--skip-intro` +* Menú de trucos (_cheats_) en _options_. (Se activa con la opción de línea de comandos `--cheats`) Ten en cuenta que si un cheat te pide pulsar el botón "L", se refiere al botón de N64, el cual tendrá que estar asignado a un botón de tu mando. Ve a los ajustes de control y asegúrate de que tienes "L" mapeado a un botón de tu mando. ## Compilar en Windows + **No intentes compilar ejecutables para Windows bajo Linux usando `WINDOWS_BUILD=1`. No va a funcionar. Sigue la guía.** -#### 1. Instalación y configuración de MSYS2. + +### 1. Instalación y configuración de MSYS2 1. Descarga [msys2-x86_64-latest.exe](http://repo.msys2.org/distrib/msys2-x86_64-latest.exe) y ejecútalo. Si tu sistema operativo es de 32 bits (¿por qué?) descarga [msys2-i686-latest.exe](http://repo.msys2.org/distrib/msys2-i686-latest.exe) en su lugar. Asegúrate de que lo instalas en `C:\dev\msys64` (o `C:\dev\msys32` para 32 bits...). Ejecuta MSYS2. 2. En la ventana de comandos de MSYS2, ejecuta el siguiente comando: - ``` + + ```bash pacman -Syuu ``` + 3. Abre "MSYS2 MinGW 64-Bit". Ejecuta este comando __repetidamente__ hasta que MSYS diga que ya no hay más actualizaciones. Es posible que tengas que volver a cerrar y abrir MSYS2. - ``` + ```bash pacman -Syuu ``` -5. Ejecuta este comando y cuando te pida confirmación pulsa intro: +4. Ejecuta este comando y cuando te pida confirmación pulsa intro: - ``` + ```bash pacman -S --needed base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain \ git subversion mercurial \ mingw-w64-i686-cmake mingw-w64-x86_64-cmake ``` -6. Listo. + +5. Listo. + #### Instala las dependencias -``` + +```bash pacman -S mingw-w64-i686-glew mingw-w64-x86_64-glew mingw-w64-i686-SDL2 mingw-w64-x86_64-SDL2 python3 ``` + ### Crea el directorio en el que preparar todo + Desde el explorador de Windows, navega a `C:\msys64\home\(nombre de usuario)\` y crea una carpeta con el nombre que te apetezca. Aquí es donde vamos a preparar todo. + ### Clona el repositorio + En MSYS2, introduce el siguiente comando: -``` + +```bash git clone https://github.com/sm64pc/sm64pc/ ``` + (Si no funciona, prueba a escribirlo manualmente, en lugar de copiar y pegar) + #### Copia la ROM base al directorio correspondiente + El paso anterior tiene que haber creado una carpeta llamada sm64pc. Dentro de esa carpeta, y para cada version de la ROM (jp/us/eu) de la cual quieras compilar un ejecutable, coloca la ROM con el nombre `baserom..z64` para extraer sus assets. Por ejemplo, `baserom.us.z64` para la versión americana, o `baserom.eu.z64` para la versión europea. -#### En MSYS2, vamos a navegar a la carpeta `./tools/audiofile-0.3.6/` y ejecutar el `autoreconf-i`. Introduce los siguientes comandos, en orden, uno a uno: -``` +#### En MSYS2, vamos a navegar a la carpeta `./tools/audiofile-0.3.6/` y ejecutar el `autoreconf-i`. Introduce los siguientes comandos, en orden, uno a uno + +```bash cd sm64pc/tools/audiofile-0.3.6/ autoreconf -i ``` + No te vayas de este directorio hasta el paso 9. #### Ejecuta el script `configure` -``` + +```bash PATH=/mingw64/bin:/mingw32/bin:$PATH LIBS=-lstdc++ ./configure --disable-docs ``` + #### Ejecuta el script `make` -``` + +```bash PATH=/mingw64/bin:/mingw32/bin:$PATH make ``` + #### Crea un directorio `lib` en `tools/` -``` + +```bash mkdir ../lib ``` #### Acabas de compilar `libaudiofile`. Ahora cópialo a `tools/lib/` -``` + +```bash cp libaudiofile/.libs/libaudiofile.a ../lib/ cp libaudiofile/.libs/libaudiofile.la ../lib/ ``` -#### Ahora toca hacer algo desde Windows. + +#### Ahora toca hacer algo desde Windows + En el explorador de Windows, ve a sm64pc\tools y edita el archivo Makefile desde un editor de texto (es recomendable usar un editor decente como Notepad++ o Sublime Text, en lugar del bloc de notas, para asegurarte de que no rompes el formato del texto) Busca la línea que contiene esto: ```tabledesign_CFLAGS := -Wno-uninitialized -laudiofile``` -Y añade ` -lstdc++` al final, de manera que quede así (¡no olvides el espacio!) +Y añade `-lstdc++` al final, de manera que quede así (¡no olvides el espacio!) ```tabledesign_CFLAGS := -Wno-uninitialized -laudiofile -lstdc++``` Guarda el archivo. -#### Vuelve a la carpeta tools y ejecuta `make` con los siguientes comandos. -``` + +#### Vuelve a la carpeta tools y ejecuta `make` con los siguientes comandos + +```bash cd .. PATH=/mingw64/bin:/mingw32/bin:$PATH make ``` + #### Vuelve al directorio sm64pc -``` + +```bash cd .. ``` -#### Finalmente, ejecuta ```make``` de nuevo. + +#### Finalmente, ejecuta ```make``` de nuevo (Ten en cuenta que mingw32 y mingw64 han sido intercambiados. Esto es para que puedas compilar la versión de 32 bits si quieres.) Aquí pones las opciones que quieras según la versión que quieras compilar. Por ejemplo, si quieres activar la cámara analógica, añade al final BETTERCAMERA=1. Si quieres la opción de distancia de renderizado ilimitada, añade NODRAWINGDISTANCE=1. Por ejemplo: -``` + +```bash PATH=/mingw32/bin:/mingw64/bin:$PATH make BETTERCAMERA=1 NODRAWINGDISTANCE=1 ``` + Listo. El .exe estará en sm64pc\build\. Disfruta. + ## Compilar en Linux ### Nota para usuarios de Windows + No intentes compilar un ejecutable para Windows desde Linux o WSL. No funciona. Sigue la guía para Windows. -#### Copia la(s) ROM(s) base para la extracción de assets. +#### Copia la(s) ROM(s) base para la extracción de assets Por cada versión de la cual quieras compilar un ejecutable, copia la ROM en `./baserom..z64` para extraer los assets. -#### Instala las dependencias. +#### Instala las siguientes dependencias -Para compilar necesitas las sigueintes dependencias. - * python3 >= 3.6 - * libsdl2-dev - * [audiofile](https://audiofile.68k.org/) - * libglew-dev - * git +Para compilar necesitas las siguientes dependencias. + +* python3 >= 3.6 +* libsdl2-dev +* [audiofile](https://audiofile.68k.org/) +* libglew-dev +* git Puedes instalarlas con este comando: ##### Debian / Ubuntu - (compilando para 32 bits) -``` + +```bash sudo apt install build-essential git python3 libaudiofile-dev libglew-dev:i386 libsdl2-dev:i386 ``` + ##### Debian / Ubuntu - (compilando para 64 bits) -``` + +```bash sudo apt install build-essential git python3 libaudiofile-dev libglew-dev libsdl2-dev ``` + ##### Arch Linux + Hay un paquete AUR (cortesía de @narukeh) disponible bajo el nombre [sm64pc-git](https://aur.archlinux.org/packages/sm64pc-git/). Instálalo con tu gestor de AURs preferido. Si quieres compilarlo por tu cuenta: -``` + +```bash sudo pacman -S base-devel python audiofile sdl2 glew ``` ##### Void Linux - (compilando para 64 bits) -``` + +```bash sudo xbps-install -S base-devel python3 audiofile-devel SDL2-devel glew-devel ``` ##### Void Linux - (compilando para 32 bits) -``` + +```bash sudo xbps-install -S base-devel python3 audiofile-devel-32bit SDL2-devel-32bit glew-devel-32bit ``` -#### Compila el ejecutable. +#### Compila el ejecutable Ejecuta `make` para compilar (por defecto `VERSION=us`) -``` +```bash make VERSION=jp -j6 # Compila la versión (J) usando 6 hilos make VERSION=us MARCH=i686 TARGET_BITS=32 # Compila un ejecutable de la versión (U) de 32 bits make TARGET_RPI=1 # Compila un ejecutable para Raspberry Pi ``` + ## Compilar para la web + Puedes compilar el juego para navegadores que admitan WebGL usando [Emscripten](https://github.com/emscripten-core). Para hacerlo, instala [emsdk](https://github.com/emscripten-core/emsdk) y ejecuta `make TARGET_WEB=1`. ## Script para compilar para Raspberry Pi [Hyenadae](https://github.com/Hyenadae/) ha creado un script que ayuda a compilar el juego para Raspberry Pi. Estos son los pasos que hace el script: - * Instala las dependencias; - * Cambia VC4_DRM en la RPi de 0 a 3; - * Cambia ajustes en la memoria de las RPis 0 y 1 para que se pueda completar la compilación; - * Permite la instalación de un SDL2 con KMS, lo que elimina la necesidad de usar X11 y garantiza el máximo rendimiento de cualquier RPi que ejecute VC4; - * Clona sm64pc si no encuentra los archivos necesarios; - * Comprueba si existen los assets y la ROM base necesaria (baserom.*.z64); - * Compila sm64pc. +* Instala las dependencias; +* Cambia VC4_DRM en la RPi de 0 a 3; +* Cambia ajustes en la memoria de las RPis 0 y 1 para que se pueda completar la compilación; +* Permite la instalación de un SDL2 con KMS, lo que elimina la necesidad de usar X11 y garantiza el máximo rendimiento de cualquier RPi que ejecute VC4; +* Clona sm64pc si no encuentra los archivos necesarios; +* Comprueba si existen los assets y la ROM base necesaria (baserom.*.z64); +* Compila sm64pc. El script está incluído en la rama master, pero también puede descargarse [aquí](https://raw.githubusercontent.com/sm64pc/sm64pc/master/pisetup.sh). -# Problemas conocidos -### Problemas ya conocidos: - * La versión EU tiene bugs en los textos y no tiene audio. - * El movimiento analógico horizontal de la cámara vuelve al estilo antiguo en el nivel Bowser in the Dark World (#72) - * La cámara con el ratón falla cuando disparas a Mario hacia un árbol o un tubo. (#71) - * "make: Nothing to be done for 'default'" al compilar para web. (#67) - -### Estos problemas están marcados como solucionados. Por favor, contacta si sigues teniendo estos problemas. - * El juego se llena de flags aleatorias en las builds de 64 bits para Windows - * Hazy Maze Cave se cuelga en pantalla completa (#57) - * La pantalla de título no tiene el cursor para manipular a Mario en pantalla completa. (#28) + +## Problemas conocidos + +### Problemas ya conocidos + +* La versión EU tiene bugs en los textos y no tiene audio. +* El movimiento analógico horizontal de la cámara vuelve al estilo antiguo en el nivel Bowser in the Dark World (#72) +* La cámara con el ratón falla cuando disparas a Mario hacia un árbol o un tubo. (#71) +* "make: Nothing to be done for 'default'" al compilar para web. (#67) + +### Estos problemas están marcados como solucionados. Por favor, contacta si sigues teniendo estos problemas + +* El juego se llena de flags aleatorias en las builds de 64 bits para Windows +* Hazy Maze Cave se cuelga en pantalla completa (#57) +* La pantalla de título no tiene el cursor para manipular a Mario en pantalla completa. (#28) ## Parches + En la carpeta `./enhancements` hay varios archivos `patch`, que pueden aplicarse de la siguiente manera: -``` +```bash git apply fps.patch --ignore-whitespace --reject ``` + Si ocurre un rechazo, puedes buscarlo con el comando `find | grep .rej`. Intenta resolver los rechazos a través de [wiggle](https://github.com/neilbrown/wiggle). -``` + +```bash wiggle rejection.rej --replace ``` diff --git a/README_pt_BR.md b/README_pt_BR.md index 758733d10..89def7682 100644 --- a/README_pt_BR.md +++ b/README_pt_BR.md @@ -1,5 +1,6 @@ # sm64pc -Adaptação em OpenGL de [n64decomp/sm64](https://github.com/n64decomp/sm64). + +Adaptação em OpenGL de [n64decomp/sm64](https://github.com/n64decomp/sm64). Sinta-se livre para reportar bugs [aqui](https://github.com/sm64pc/sm64pc/issues) e contribuir, mas tenha em mente que não aceitamos compartilhamento de conteúdo protegido com direitos autorais. @@ -15,19 +16,20 @@ Novas funcionalidades serão adicionadas à branch master quando forem considera ## Recursos - * Renderização nativa. Você agora pode jogar SM64 no PC sem precisar de emulador. - * Proporção de tela e resolução variáveis. O jogo renderiza corretamente em basicamente qualquer tamanho de janela. - * Suporte a entradas de controle através de `xinput`. Tal como usando DualShock 4 em distribuições Linux. - * Controle de câmera com analógico ou mouse. (Ative com `make BETTERCAMERA=1`.) - * Uma opção para desativar distância de renderização. (Ative com `make NODRAWINGDISTANCE=1`.) - * Remapeamento de controles _in-game_. - * Pule as cenas introdutórias da Peach e Lakitu com usando a opção `--skip-intro` ao executar o jogo na linha de comando. - * Menu de cheats nas opções. (Ative com `--cheats`) - ** Note que se algum cheat pedir pelo botão "L", o botão em questão é o "L" do N64. Certifique-se de que este está mapeado, caso necessário. +* Renderização nativa. Você agora pode jogar SM64 no PC sem precisar de emulador. +* Proporção de tela e resolução variáveis. O jogo renderiza corretamente em basicamente qualquer tamanho de janela. +* Suporte a entradas de controle através de `xinput`. Tal como usando DualShock 4 em distribuições Linux. +* Controle de câmera com analógico ou mouse. (Ative com `make BETTERCAMERA=1`.) +* Uma opção para desativar distância de renderização. (Ative com `make NODRAWINGDISTANCE=1`.) +* Remapeamento de controles _in-game_. +* Pule as cenas introdutórias da Peach e Lakitu com usando a opção `--skip-intro` ao executar o jogo na linha de comando. +* Menu de cheats nas opções. (Ative com `--cheats`) +** Note que se algum cheat pedir pelo botão "L", o botão em questão é o "L" do N64. Certifique-se de que este está mapeado, caso necessário. ## Compilação + Para instruções de compilaçao, consulte a [wiki](https://github.com/sm64pc/sm64pc/wiki). ## Para usuários de Windows -**Certifique-se de que você tem o [MXE](mxe.cc) antes de tentar compilar em Windows. Siga o guia na Wiki.** +**Certifique-se de que você tem o [MXE](https://mxe.cc) antes de tentar compilar em Windows. Siga o guia na Wiki.** diff --git a/README_zh_CN.md b/README_zh_CN.md index b3e90f928..aec236109 100644 --- a/README_zh_CN.md +++ b/README_zh_CN.md @@ -1,4 +1,5 @@ # sm64pc + 本项目是 [n64decomp/sm64](https://github.com/n64decomp/sm64) 的 OpenGL 移植版本。 我们欢迎贡献代码与 bug 报告,但请切记,**不得上传任何被版权保护(来自 ROM 文件)的资源**。 @@ -7,15 +8,16 @@ ## 主要功能 - * 原生渲染。现在不用任何模拟器就可以运行 马力欧64 了。 - * 长宽比和分辨率可以自由改变。本游戏目前可以在几乎任何窗口尺寸下正确渲染。 - * 原生 xinput 手柄支持。在 Linux 下,已经确认 PS4 手柄可以即插即用。 - * 支持模拟量视点控制、鼠标控制视点。(请使用 `make BETTERCAMERA=1` 编译) - * 可取消可视距离限制。(请使用 `make NODRAWINGDISTANCE=1` 编译) - * 游戏内操作设定功能,目前在 `testing` 分支下可用。 - * 使用 `--skip-intro` 命令行选项跳过碧奇公主与 Lakitu 的片头剧情。目前在 `testing` 及 `skip-intro` 分支下可用。 +* 原生渲染。现在不用任何模拟器就可以运行 马力欧64 了。 +* 长宽比和分辨率可以自由改变。本游戏目前可以在几乎任何窗口尺寸下正确渲染。 +* 原生 xinput 手柄支持。在 Linux 下,已经确认 PS4 手柄可以即插即用。 +* 支持模拟量视点控制、鼠标控制视点。(请使用 `make BETTERCAMERA=1` 编译) +* 可取消可视距离限制。(请使用 `make NODRAWINGDISTANCE=1` 编译) +* 游戏内操作设定功能,目前在 `testing` 分支下可用。 +* 使用 `--skip-intro` 命令行选项跳过碧奇公主与 Lakitu 的片头剧情。目前在 `testing` 及 `skip-intro` 分支下可用。 ## 编译方法 + 关于如何编译,请参考 [wiki](https://github.com/sm64pc/sm64pc/wiki)。 **请勿在 Linux 或者 WSL 下使用 `WINDOWS_BUILD=1` 参数尝试编译 Windows 版本,这样无法编译成功。请参考 Wiki。 diff --git a/SAVE_FORMAT.MD b/SAVE_FORMAT.MD index 5f44a0116..79268e40b 100644 --- a/SAVE_FORMAT.MD +++ b/SAVE_FORMAT.MD @@ -1,4 +1,5 @@ # Text-based savefile format + This small document describes a new, TOML-like text format for game saves. This format allows the user to use a simple text editor to change the data necessary for the game (for example, special saves for speedrun training). All data is stored in pairs (*key = value*). Pairs can be placed arbitrarily within a single section. The format of values may differ for each section. @@ -7,11 +8,14 @@ Each savefile (4 total) must be named `save_file_X.sav`, where X - save slot (0, > **Note**: The game creates the savefile only when you are saved in the game after completing a course! ___ + ## Header + The header is automatically generated by the game when saving progress. It mainly contains information about the value of the 0 and 1 flags, the character that the comment starts with, and the time when the file content changed. Example: -``` + +```python # Super Mario 64 save file # Comment starts with # # True = 1, False = 0 @@ -19,18 +23,23 @@ Example: ``` ___ + ## Commenting + All comment lines starts with `#` character. Comments can be located on a separate line or as part of another line. When the game reads the save, comments are ignored. Example: -``` + +```python # This is a comment coin_score_age = ?? # This is a comment too! ``` ___ + ## Menu Section - [menu] -This section contains two flags for menu. + +This section contains two flags for menu. | Flag | Value | Description | |---|---|---| @@ -38,37 +47,42 @@ This section contains two flags for menu. | sound_mode | stereo, mono, headset | Sound mode for the game Example: -``` + +```python [menu] coin_score_age = 0 sound_mode = stereo ``` + ___ + ## Flags Section - [flags] -This section contains all main game flags (walkthought milestones). + +This section contains all main game flags (walkthrough milestones). > **Note**: The value can be only 0 (False) or 1 (True). | Flag | Description | |---|---| -| wing_cap | **Red Switch** is pressed +| wing_cap | **Red Switch** is pressed | metal_cap | **Green Switch** is pressed -| vanish_cap | **Blue Switch** is pressed. +| vanish_cap | **Blue Switch** is pressed | key_1 | Key is found in **Bowser in the Dark World** | key_2 | Key is found in **Bowser in the Fire Sea** | basement_door | Mario unlocked castle's basement door | upstairs_door | Mario unlocked castle's upper floors -| ddd_moved_back | **Dire Dire Docks** painting is moved back +| ddd_moved_back | **Dire Dire Docks** painting is moved back | moat_drained | Water is drained in the moat of the castle | pps_door | **Princess's Secret Slide** window is unlocked | wf_door | **Whomp's Fortress door** is unlocked | ccm_door | **Cool, Cool Mountain door** is unlocked | jrb_door | **Jolly Roger Bay door** is unlocked | bitdw_door | **Bowser in the Dark World door** door is unlocked -| bitfs_door | **Bowser in the Fire Sea** door is unlocked +| bitfs_door | **Bowser in the Fire Sea** door is unlocked | 50star_door | **Endless Staircase** is not endless anymore Example: -``` + +```python [flags] wing_cap = 1 metal_cap = 1 @@ -76,14 +90,17 @@ vanish_cap = 0 key_1 = 1 key_2 = 1 ``` + ___ + ## Main Courses Section - [courses] + This section contains all stars and coins that Mario collected in each main course. The first value stores the number of coins collected. -> **Warning!**: Make sure that coins count will not exceed 255! +> **Warning!**: Make sure that the coin count does not exceed 255! -The second value stores the stars (or completed missions). Each mission (6 main + 1 bonus) is must be marked `0` (not completed) and `1` (completed). +The second value stores the stars (or completed missions). Each mission (6 main + 1 bonus) is must be marked `0` (not completed) and `1` (completed). > **Warning!**: The sequence of stars' missions goes from **RIGHT** to **LEFT**! > **Note**: Last star flag is **100 coins star** @@ -106,23 +123,27 @@ The second value stores the stars (or completed missions). Each mission (6 main | rr | Rainbow Ride Example: -``` + +```python [courses] bob = "3, 0000011" wf = "3, 0000101" jrb = "0, 1000000" ccm = "1, 1111111" ``` + ___ + ## Bonus Section - [bonus] + This section contains all bonus stars that Mario collected in the castle and all bonus courses. > **Note**: The game takes into account only the number of bonus stars collected, the order of stars flags can be arbitrary | Flag | Stars | Description | |---|---|---| | hub | 5 | MIPS' stars and Toads' stars -| bitdw | 1 | Bowser in the Dark World -| bitfs | 1 | Bowser in the Fire Sea +| bitdw | 1 | Bowser in the Dark World +| bitfs | 1 | Bowser in the Fire Sea | bits | 1 | Bowser in the Sky | pss | 2 | The Princess's Secret Slide | cotmc | 1 | Cavern of the Metal Cap @@ -132,7 +153,8 @@ This section contains all bonus stars that Mario collected in the castle and all | sa | 1 | The Secret Aquarium Example: -``` + +```python [bonus] hub = 11101 bitdw = 1 @@ -140,19 +162,23 @@ bitfs = 0 bits = 1 pss = 10 ``` + ___ + ## Cap Section - [cap] -This section contains information about where Mario lost his cap and who take it. + +This section contains information about where Mario lost his cap and who, or what, took it. | Flag | Value | Description | |---|---|---| -| type | ground, klepto, ukiki, mrblizzard | The one who or what took the cap from Mario. Default flag is **"ground"** +| type | ground, klepto, ukiki, mrblizzard | The one that took the cap from Mario. Default flag is **"ground"** | level | ssl, sl, ttm, none | Specifies the course where the cap is located. Default flag is **"none"**. | area | 1, 2 | Specifies the area in the course. Example: -``` + +```python [cap] type = ground level = ssl area = 1 -``` \ No newline at end of file +``` diff --git a/actors/boo/geo.inc.c b/actors/boo/geo.inc.c index 4fa9721bc..d0c7e29d6 100644 --- a/actors/boo/geo.inc.c +++ b/actors/boo/geo.inc.c @@ -12,6 +12,8 @@ const GeoLayout boo_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/boo_castle/geo.inc.c b/actors/boo_castle/geo.inc.c index 1b3ee4f3a..f20d4b06c 100644 --- a/actors/boo_castle/geo.inc.c +++ b/actors/boo_castle/geo.inc.c @@ -12,6 +12,8 @@ const GeoLayout boo_castle_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/bookend/geo.inc.c b/actors/bookend/geo.inc.c index b5629c8d5..157ab697a 100644 --- a/actors/bookend/geo.inc.c +++ b/actors/bookend/geo.inc.c @@ -24,6 +24,8 @@ const GeoLayout bookend_part_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/bowser_key/geo.inc.c b/actors/bowser_key/geo.inc.c index d7e2a85f6..d1e967c59 100644 --- a/actors/bowser_key/geo.inc.c +++ b/actors/bowser_key/geo.inc.c @@ -26,6 +26,8 @@ const GeoLayout bowser_key_cutscene_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/burn_smoke/model.inc.c b/actors/burn_smoke/model.inc.c index bcf4fd6f4..d62aee3ad 100644 --- a/actors/burn_smoke/model.inc.c +++ b/actors/burn_smoke/model.inc.c @@ -10,9 +10,9 @@ static const Vtx burn_smoke_seg4_vertex_040217C0[] = { // //! Wrong texture format. Called as rgba16, which makes the burn smoke appear // as a transparent black burn smoke. Probably meant to show up as white-ish -// burn smoke, but mistakened for being intended as black smoke. +// burn smoke, but mistaken for being intended as black smoke. // Due to debate in the Koopa shorts PR surrounding the fix to a similar bug, -// said fix is on a compile-time variable. Use TEXTURE_FIX=1 at compile time +// said fix is on a compile-time variable. Use QOL_FIXES=1 at compile time // to fix this. // 0x04021800 ALIGNED8 static const u8 burn_smoke_seg4_texture_04021800[] = { @@ -47,7 +47,7 @@ const Gfx burn_smoke_seg4_dl_04022048[] = { // 0x04022070 - 0x040220C8 const Gfx burn_smoke_seg4_dl_04022070[] = { gsSPDisplayList(burn_smoke_seg4_dl_04022000), - #ifdef TEXTURE_FIX + #ifdef QOL_FIXES gsDPLoadTextureBlock(burn_smoke_seg4_texture_04021800, G_IM_FMT_IA, G_IM_SIZ_16b, 32, 32, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD), #else gsDPLoadTextureBlock(burn_smoke_seg4_texture_04021800, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD), diff --git a/actors/chain_chomp/geo.inc.c b/actors/chain_chomp/geo.inc.c index ad3367733..d54d73eea 100644 --- a/actors/chain_chomp/geo.inc.c +++ b/actors/chain_chomp/geo.inc.c @@ -17,6 +17,8 @@ const GeoLayout chain_chomp_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/chair/geo.inc.c b/actors/chair/geo.inc.c index eb963a7e5..10ed51658 100644 --- a/actors/chair/geo.inc.c +++ b/actors/chair/geo.inc.c @@ -24,6 +24,8 @@ const GeoLayout haunted_chair_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/door/geo.inc.c b/actors/door/geo.inc.c index 81c017d12..726f9fc25 100644 --- a/actors/door/geo.inc.c +++ b/actors/door/geo.inc.c @@ -21,7 +21,9 @@ const GeoLayout castle_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -48,7 +50,9 @@ const GeoLayout cabin_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -75,7 +79,9 @@ const GeoLayout wooden_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -102,7 +108,9 @@ const GeoLayout wooden_door2_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -129,7 +137,9 @@ const GeoLayout metal_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -156,7 +166,9 @@ const GeoLayout hazy_maze_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -183,7 +195,9 @@ const GeoLayout haunted_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -216,7 +230,9 @@ const GeoLayout castle_door_0_star_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -249,7 +265,9 @@ const GeoLayout castle_door_1_star_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -282,7 +300,9 @@ const GeoLayout castle_door_3_stars_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; @@ -315,6 +335,8 @@ const GeoLayout key_door_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/dorrie/geo.inc.c b/actors/dorrie/geo.inc.c index 23fd462c0..b22d7e907 100644 --- a/actors/dorrie/geo.inc.c +++ b/actors/dorrie/geo.inc.c @@ -49,6 +49,8 @@ const GeoLayout dorrie_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/group3.h b/actors/group3.h index e6154e111..26b9ac73b 100644 --- a/actors/group3.h +++ b/actors/group3.h @@ -24,8 +24,13 @@ extern const Gfx king_bobomb_seg5_dl_0500B068[]; extern const Gfx king_bobomb_seg5_dl_0500B118[]; extern const Gfx king_bobomb_seg5_dl_0500B150[]; extern const Gfx king_bobomb_seg5_dl_0500B188[]; +#ifdef QOL_FIXES +extern const Gfx king_bobomb_dl_eyes[]; +extern const Gfx king_bobomb_dl_eyes_blink[]; +#else extern const Gfx king_bobomb_seg5_dl_0500B278[]; extern const Gfx king_bobomb_seg5_dl_0500B2D0[]; +#endif extern const Gfx king_bobomb_seg5_dl_0500B3C8[]; extern const Gfx king_bobomb_seg5_dl_0500B418[]; extern const Gfx king_bobomb_seg5_dl_0500B5F0[]; diff --git a/actors/hoot/geo.inc.c b/actors/hoot/geo.inc.c index e415a4920..c76e3e44c 100644 --- a/actors/hoot/geo.inc.c +++ b/actors/hoot/geo.inc.c @@ -57,6 +57,8 @@ const GeoLayout hoot_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/king_bobomb/geo.inc.c b/actors/king_bobomb/geo.inc.c index 5b7ced61b..4b00befe7 100644 --- a/actors/king_bobomb/geo.inc.c +++ b/actors/king_bobomb/geo.inc.c @@ -35,7 +35,15 @@ const GeoLayout king_bobomb_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifdef QOL_FIXES + GEO_SWITCH_CASE(2, geo_switch_anim_state), + GEO_OPEN_NODE(), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, king_bobomb_dl_eyes), + GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, king_bobomb_dl_eyes_blink), + GEO_CLOSE_NODE(), +#else GEO_ANIMATED_PART(LAYER_ALPHA, 0, 0, 0, king_bobomb_seg5_dl_0500B2D0), +#endif GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, king_bobomb_seg5_dl_0500B418), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 0, 0, king_bobomb_seg5_dl_0500B6C0), GEO_ANIMATED_PART(LAYER_OPAQUE, 0, 243, 0, NULL), @@ -115,6 +123,8 @@ const GeoLayout king_bobomb_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/king_bobomb/model.inc.c b/actors/king_bobomb/model.inc.c index dc1171a84..40ab93555 100644 --- a/actors/king_bobomb/model.inc.c +++ b/actors/king_bobomb/model.inc.c @@ -55,6 +55,11 @@ ALIGNED8 static const u8 king_bobomb_seg5_texture_05004878[] = { #include "actors/king_bobomb/king_bob-omb_eyes.rgba16.inc.c" }; +// 0x05005078 - Unused +ALIGNED8 static const u8 king_bobomb_seg5_texture_05005078[] = { +#include "actors/king_bobomb/king_bob-omb_eyes_blink.rgba16.inc.c" +}; + // 0x05005878 ALIGNED8 static const u8 king_bobomb_seg5_texture_05005878[] = { #include "actors/king_bobomb/king_bob-omb_hand.rgba16.inc.c" @@ -527,6 +532,50 @@ static const Vtx king_bobomb_seg5_vertex_0500B218[] = { {{{ 124, -158, 493}, 0, { 990, 0}, {0x00, 0xe8, 0x7c, 0xff}}}, }; +#ifdef QOL_FIXES +const Gfx king_bobomb_dl_eyes_start_block[] = { + gsDPPipeSync(), + gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), + gsSPClearGeometryMode(G_LIGHTING), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOLOD), + gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), + gsDPTileSync(), + gsDPSetTile(G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 5, G_TX_NOLOD), + gsDPSetTileSize(0, 0, 0, (32 - 1) << G_TEXTURE_IMAGE_FRAC, (32 - 1) << G_TEXTURE_IMAGE_FRAC), + gsSPEndDisplayList(), +}; + +const Gfx king_bobomb_dl_eyes_end_block[] = { + gsSPLight(&king_bobomb_seg5_lights_0500B200.l, 1), + gsSPLight(&king_bobomb_seg5_lights_0500B200.a, 2), + gsSPVertex(king_bobomb_seg5_vertex_0500B218, 6, 0), + gsSP2Triangles( 0, 1, 2, 0x0, 3, 2, 4, 0x0), + gsSP2Triangles( 2, 3, 0, 0x0, 4, 5, 3, 0x0), + gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF), + gsDPPipeSync(), + gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), + gsSPSetGeometryMode(G_LIGHTING), + gsSPEndDisplayList(), +}; + +const Gfx king_bobomb_dl_eyes[] = { + gsSPDisplayList(king_bobomb_dl_eyes_start_block), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, king_bobomb_seg5_texture_05004878), + gsDPLoadSync(), + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), + gsSPDisplayList(king_bobomb_dl_eyes_end_block), + gsSPEndDisplayList(), +}; + +const Gfx king_bobomb_dl_eyes_blink[] = { + gsSPDisplayList(king_bobomb_dl_eyes_start_block), + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, king_bobomb_seg5_texture_05005078), + gsDPLoadSync(), + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 32 * 32 - 1, CALC_DXT(32, G_IM_SIZ_16b_BYTES)), + gsSPDisplayList(king_bobomb_dl_eyes_end_block), + gsSPEndDisplayList(), +}; +#else // 0x0500B278 - 0x0500B2D0 const Gfx king_bobomb_seg5_dl_0500B278[] = { gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, king_bobomb_seg5_texture_05004878), @@ -555,6 +604,7 @@ const Gfx king_bobomb_seg5_dl_0500B2D0[] = { gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE), gsSPEndDisplayList(), }; +#endif // 0x0500B330 static const Lights1 king_bobomb_seg5_lights_0500B330 = gdSPDefLights1( diff --git a/actors/klepto/geo.inc.c b/actors/klepto/geo.inc.c index 0d0bbe304..4cd9e2b26 100644 --- a/actors/klepto/geo.inc.c +++ b/actors/klepto/geo.inc.c @@ -50,7 +50,11 @@ const GeoLayout klepto_geo[] = { GEO_SCALE(0x00, 16384), GEO_OPEN_NODE(), GEO_ASM(0, geo_offset_klepto_held_object), + #ifdef QOL_FIXES + GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_TRANSPARENT, 0, 100, 0, 180, 270, 0, transparent_star_seg3_dl_0302C620), + #else GEO_TRANSLATE_ROTATE_WITH_DL(LAYER_OPAQUE, 0, 100, 0, 180, 270, 0, transparent_star_seg3_dl_0302C620), + #endif GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), diff --git a/actors/koopa/model.inc.c b/actors/koopa/model.inc.c index 6bf241876..12f535daf 100644 --- a/actors/koopa/model.inc.c +++ b/actors/koopa/model.inc.c @@ -55,7 +55,7 @@ static const Lights1 koopa_seg6_lights_06002630 = gdSPDefLights1( // the rest of its body. This is evident because once the mistake is corrected // it turns back to being white like the other polygons. // Due to debate in the PR surrounding the fix to this, said fix is on -// a compile-time variable. Use TEXTURE_FIX=1 at compile time to fix this. +// a compile-time variable. Use QOL_FIXES=1 at compile time to fix this. // 0x06002648 ALIGNED8 static const u8 koopa_seg6_texture_06002648[] = { #include "actors/koopa/koopa_shell_front.rgba16.inc.c" @@ -2079,7 +2079,7 @@ const Gfx koopa_seg6_dl_0600C498[] = { gsSPVertex(koopa_seg6_vertex_0600B560, 9, 0), gsSP2Triangles( 0, 1, 2, 0x0, 3, 4, 5, 0x0), gsSP1Triangle( 6, 7, 8, 0x0), - #ifdef TEXTURE_FIX + #ifdef QOL_FIXES gsSPLight(&koopa_seg6_lights_06002630.l, 1), gsSPLight(&koopa_seg6_lights_06002630.a, 2), #else diff --git a/actors/mad_piano/geo.inc.c b/actors/mad_piano/geo.inc.c index 70dea53ed..6a6520e7b 100644 --- a/actors/mad_piano/geo.inc.c +++ b/actors/mad_piano/geo.inc.c @@ -16,6 +16,8 @@ const GeoLayout mad_piano_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/mips/geo.inc.c b/actors/mips/geo.inc.c index 58948b5b1..c434113f4 100644 --- a/actors/mips/geo.inc.c +++ b/actors/mips/geo.inc.c @@ -49,7 +49,9 @@ const GeoLayout mips_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/moneybag/geo.inc.c b/actors/moneybag/geo.inc.c index 2d1db035b..287cb9ec2 100644 --- a/actors/moneybag/geo.inc.c +++ b/actors/moneybag/geo.inc.c @@ -52,7 +52,9 @@ const GeoLayout moneybag_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/actors/snufit/geo.inc.c b/actors/snufit/geo.inc.c index a8aabeccf..fddb7aca3 100644 --- a/actors/snufit/geo.inc.c +++ b/actors/snufit/geo.inc.c @@ -22,6 +22,8 @@ const GeoLayout snufit_geo[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/assets.json b/assets.json index 422858ee5..2eab275f7 100644 --- a/assets.json +++ b/assets.json @@ -270,8 +270,9 @@ "actors/king_bobomb/king_bob-omb_arm.rgba16.png": [32,32,2048,{"jp":[1257760,8312],"us":[1264928,8312],"eu":[1136896,8312],"sh":[1113408,8312]}], "actors/king_bobomb/king_bob-omb_body_unused.rgba16.png": [64,64,8192,{"jp":[1257760,10360],"us":[1264928,10360],"eu":[1136896,10360],"sh":[1113408,10360]}], "actors/king_bobomb/king_bob-omb_crown_rim.rgba16.png": [32,16,1024,{"jp":[1257760,24696],"us":[1264928,24696],"eu":[1136896,24696],"sh":[1113408,24696]}], -"actors/king_bobomb/king_bob-omb_eyes.rgba16.png": [32,64,4096,{"jp":[1257760,18552],"us":[1264928,18552],"eu":[1136896,18552],"sh":[1113408,18552]}], -"actors/king_bobomb/king_bob-omb_hand.rgba16.png": [32,32,2048,{"jp":[1215456,64],"us":[1222624,64],"eu":[1094592,64],"sh":[1071104,64]}], +"actors/king_bobomb/king_bob-omb_eyes.rgba16.png": [32,32,2048,{"jp":[1257760,18552],"us":[1264928,18552],"eu":[1136896,18552],"sh":[1113408,18552]}], +"actors/king_bobomb/king_bob-omb_eyes_blink.rgba16.png": [32,32,2048,{"jp":[1257760,20600],"us":[1264928,20600],"eu":[1136896,20600],"sh":[1113408,20600]}], +"actors/king_bobomb/king_bob-omb_hand.rgba16.png": [32,32,2048,{"jp":[1257760,22648],"us":[1264928,22648],"eu":[1136896,22648],"sh":[1113408,22648]}], "actors/king_bobomb/king_bob-omb_left_side.rgba16.png": [32,64,4096,{"jp":[1257760,33912],"us":[1264928,33912],"eu":[1136896,33912],"sh":[1113408,33912]}], "actors/king_bobomb/king_bob-omb_right_side.rgba16.png": [32,64,4096,{"jp":[1257760,38008],"us":[1264928,38008],"eu":[1136896,38008],"sh":[1113408,38008]}], "actors/klepto/klepto_beak.rgba16.png": [32,64,4096,{"jp":[1327760,4104],"us":[1334928,4104],"eu":[1206896,4104],"sh":[1183408,4104]}], diff --git a/assets/demo_data.json b/assets/demo_data.json index 5993222b5..f5a60220a 100644 --- a/assets/demo_data.json +++ b/assets/demo_data.json @@ -7,7 +7,7 @@ * in the "demofiles" array. * "ifdef" is an optional array property which can be used to specify * requirement of SM64 version. - * "extraSize" is an optional property which will be added the size of the + * "extraSize" is an optional property which will be added to the size of the * demofile. * * The "demofiles" array declares the inclusion order of the demofiles. diff --git a/assets/qol_demo_data.json b/assets/qol_demo_data.json new file mode 100644 index 000000000..534933973 --- /dev/null +++ b/assets/qol_demo_data.json @@ -0,0 +1,45 @@ +/* + * This file defines the demo data. It's parsed by tools/demo_data_converter.py. + * + * The "table" array declares the order of the demos and will be generated + * as pairs of (offset, size). + * Each item has a "demofile" property, which must reference a demofile + * in the "demofiles" array. + * "ifdef" is an optional array property which can be used to specify + * requirement of SM64 version. + * "extraSize" is an optional property which will be added to the size of the + * demofile. + * + * The "demofiles" array declares the inclusion order of the demofiles. + * A file with the ".bin" extension with the "name" property as basename + * should exist in the assets/demos/ directory. + * "ifdef" is an optional array property which can be used to specify + * requirement of SM64 version. + */ + +{ + "table": [ + {"demofile":"bitdw", "ifdef":["VERSION_US"]}, + {"demofile":"wf"}, + {"demofile":"ccm"}, + {"demofile":"bbh"}, + {"demofile":"jrb"}, + {"demofile":"hmc"}, + {"demofile":"pss"} + ], + "demofiles": [ + {"name":"bbh"}, + {"name":"ccm"}, + {"name":"hmc"}, + {"name":"jrb"}, + {"name":"wf"}, + {"name":"pss"}, + + /* Might be an unused demo, but it doesn't define a header, + so it can't be normally called. Speculation: "blooper" take for CCM. + Mario runs into the sign and aligns himself as if it were a mistake. */ + {"name":"unused"}, + + {"name":"bitdw", "ifdef":["VERSION_US"]} + ] +} diff --git a/bin/segment2.c b/bin/segment2.c index a6756e952..622f69c0f 100644 --- a/bin/segment2.c +++ b/bin/segment2.c @@ -2492,10 +2492,17 @@ ALIGNED8 const u8 texture_waterbox_lava[] = { }; // Unreferenced light group +#ifndef TARGET_WEB static const Lights1 segment2_lights_unused = gdSPDefLights1( 0x40, 0x40, 0x40, 0xff, 0xff, 0xff, 0x28, 0x28, 0x28 ); +#else +UNUSED static const Lights1 segment2_lights_unused = gdSPDefLights1( + 0x40, 0x40, 0x40, + 0xff, 0xff, 0xff, 0x28, 0x28, 0x28 +); +#endif // 0x02014470 - 0x020144B0 static const Mtx matrix_identity = { diff --git a/data/behavior_data.c b/data/behavior_data.c index d27cf09fe..ad3b27f01 100644 --- a/data/behavior_data.c +++ b/data/behavior_data.c @@ -3144,7 +3144,11 @@ const BehaviorScript bhvUnusedFakeStar[] = { }; // What is this? +#ifndef TARGET_WEB static const BehaviorScript unused_1[] = { +#else +UNUSED static const BehaviorScript unused_1[] = { +#endif BREAK(), BREAK(), BREAK(), diff --git a/extract_assets.py b/extract_assets.py index bb5293484..873f3d4c3 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -20,6 +20,8 @@ def read_local_asset_list(f): def asset_needs_update(asset, version): + if version <= 6 and asset in ["actors/king_bobomb/king_bob-omb_eyes.rgba16.png", "actors/king_bobomb/king_bob-omb_hand.rgba16.png"]: + return True if version <= 5 and asset == "textures/spooky/bbh_textures.00800.rgba16.png": return True if version <= 4 and asset in ["textures/mountain/ttm_textures.01800.rgba16.png", "textures/mountain/ttm_textures.05800.rgba16.png"]: @@ -59,7 +61,7 @@ def clean_assets(local_asset_file): def main(): # In case we ever need to change formats of generated files, we keep a # revision ID in the local asset file. - new_version = 6 + new_version = 7 try: local_asset_file = open(".assets-local.txt") diff --git a/include/PR/os_libc.h b/include/PR/os_libc.h index 9eb872e79..039b18589 100644 --- a/include/PR/os_libc.h +++ b/include/PR/os_libc.h @@ -12,12 +12,12 @@ #elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) || defined(NO_BZERO_BCOPY) -// there's no way that shit's defined, use memcpy/memset +// there's no way that shit's defined, use memmove/memset #include #undef bzero #undef bcopy -#define bzero(buf, len) memset((buf), 0, (len)) -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bzero(buf, len) memset(buf, 0, len) +#define bcopy(src, dst, len) memmove(dst, src, len) #else diff --git a/include/config.h b/include/config.h index 4512546eb..2249b0470 100644 --- a/include/config.h +++ b/include/config.h @@ -9,20 +9,38 @@ */ // Bug Fixes -// --| US Version Nintendo Bug Fixes +// --| Post-JP Version Nintendo Bug Fixes /// Fixes bug where obtaining over 999 coins sets the number of lives to 999 (or -25) -#define BUGFIX_MAX_LIVES (0 || VERSION_US || VERSION_EU || VERSION_SH) +#define BUGFIX_MAX_LIVES (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) /// Fixes bug where the Boss music won't fade out after defeating King Bob-omb -#define BUGFIX_KING_BOB_OMB_FADE_MUSIC (0 || VERSION_US || VERSION_EU) +#define BUGFIX_KING_BOB_OMB_FADE_MUSIC (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) /// Fixes bug in Bob-Omb Battlefield where entering a warp stops the Koopa race music -#define BUGFIX_KOOPA_RACE_MUSIC (0 || VERSION_US || VERSION_EU || VERSION_SH) +#define BUGFIX_KOOPA_RACE_MUSIC (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) /// Fixes bug where Piranha Plants do not reset their action state when the /// player exits their activation radius. -#define BUGFIX_PIRANHA_PLANT_STATE_RESET (0 || VERSION_US || VERSION_EU || VERSION_SH) +#define BUGFIX_PIRANHA_PLANT_STATE_RESET (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) /// Fixes bug where sleeping Piranha Plants damage players that bump into them -#define BUGFIX_PIRANHA_PLANT_SLEEP_DAMAGE (0 || VERSION_US || VERSION_SH) +#define BUGFIX_PIRANHA_PLANT_SLEEP_DAMAGE (0 || VERSION_US || VERSION_SH || QOL_FIXES) /// Fixes bug where it shows a star when you grab a key in bowser battle stages -#define BUGFIX_STAR_BOWSER_KEY (0 || VERSION_US || VERSION_EU) +#define BUGFIX_STAR_BOWSER_KEY (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) +/// Fixes bug in KTQ win dialog which makes it sound like a penguin instead of a Koopa +#define BUGFIX_DIALOG_SOUND_KTQ_WIN (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) +/// Fixes bug that causes Wiggler to read a garbage health value when it gets loaded +#define BUGFIX_WIGGLER_HEALTH (0 || VERSION_EU || AVOID_UB || QOL_FIXES) +/// Fixes bug that can cause spawning displacement (e.g. after exiting a level) +#define BUGFIX_SPAWNING_DISPLACEMENT (0 || VERSION_US || VERSION_EU || VERSION_SH || QOL_FIXES) +// --| Shindou Version Nintendo Bug Fixes +/// Fixes bug where bully could still be interacted with while he dies +#define BUGFIX_BULLY_NO_INTERACT_DEATH (0 || VERSION_SH || QOL_FIXES) +/// Fixes bug where standing on a controllable platform in HMC makes Mario invisible while it blinks +#define BUGFIX_HMC_VISIBLE_CONTROL_PLATFORM (0 || VERSION_SH || QOL_FIXES) +/// Fixes bug where the angle speed isn't preserved while in a pole +#define BUGFIX_PRESERVE_VEL_POLE (0 || VERSION_SH || QOL_FIXES) +/// Fixes bug where backwards long jumps have uncapped speed +#define BUGFIX_BLJ (0 || VERSION_SH || QOL_FIXES) +// --| Misc QoL Fixes (these aren't really covered by QOL_FIXES) +/// Reenables the unused play state +#define TWEAK_USE_UNUSED_PLAY_STATE (0 || USE_UNUSED_PLAY_STATE) // Screen Size Defines #define SCREEN_WIDTH 320 diff --git a/include/dxsdk/d3dx12.h b/include/dxsdk/d3dx12.h index 3aafbd252..59e28948c 100644 --- a/include/dxsdk/d3dx12.h +++ b/include/dxsdk/d3dx12.h @@ -2171,8 +2171,6 @@ struct CD3DX12_RT_FORMAT_ARRAY : public D3D12_RT_FORMAT_ARRAY struct DefaultSampleMask { operator UINT() { return UINT_MAX; } }; struct DefaultSampleDesc { operator DXGI_SAMPLE_DESC() { return DXGI_SAMPLE_DESC{1, 0}; } }; -#pragma warning(push) -#pragma warning(disable : 4324) template class alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT { @@ -2188,7 +2186,6 @@ class alignas(void*) CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT InnerStructType* operator&() { return &_Inner; } InnerStructType const* operator&() const { return &_Inner; } }; -#pragma warning(pop) typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< D3D12_PIPELINE_STATE_FLAGS, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS> CD3DX12_PIPELINE_STATE_STREAM_FLAGS; typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK> CD3DX12_PIPELINE_STATE_STREAM_NODE_MASK; typedef CD3DX12_PIPELINE_STATE_STREAM_SUBOBJECT< ID3D12RootSignature*, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> CD3DX12_PIPELINE_STATE_STREAM_ROOT_SIGNATURE; diff --git a/include/libc/math.h b/include/libc/math.h index 8cea459bf..dc1e229df 100644 --- a/include/libc/math.h +++ b/include/libc/math.h @@ -2,6 +2,9 @@ #define MATH_H #define M_PI 3.14159265358979323846 +#ifdef QOL_FIXES +#define M__PI 3.14159265358979323846264338327950288 +#endif float sinf(float); double sin(double); diff --git a/include/object_constants.h b/include/object_constants.h index 82a167697..7fb87dc07 100644 --- a/include/object_constants.h +++ b/include/object_constants.h @@ -879,6 +879,9 @@ #define KLEPTO_ANIM_STATE_HOLDING_NOTHING 0 #define KLEPTO_ANIM_STATE_HOLDING_CAP 1 #define KLEPTO_ANIM_STATE_HOLDING_STAR 2 + #ifdef QOL_FIXES + #define KLEPTO_ANIM_STATE_HOLDING_BLUE_STAR 3 + #endif /* Bird */ /* oAction */ diff --git a/include/object_fields.h b/include/object_fields.h index 9f2661ce0..9bc861f19 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -195,6 +195,11 @@ #define /*0x0FC*/ oBackAndForthPlatformUnkFC OBJECT_FIELD_F32(0x1D) #define /*0x100*/ oBackAndForthPlatformUnk100 OBJECT_FIELD_F32(0x1E) +/* Beta Trampoline */ +#ifdef QOL_FIXES +#define /*0x098*/ oBetaTrampolineAdditiveYVel OBJECT_FIELD_F32(0x04) +#endif + /* Bird */ #define /*0x0F4*/ oBirdSpeed OBJECT_FIELD_F32(0x1B) #define /*0x0F8*/ oBirdTargetPitch OBJECT_FIELD_S32(0x1C) @@ -593,6 +598,9 @@ #define /*0x100*/ oKingBobombUnk100 OBJECT_FIELD_S32(0x1E) #define /*0x104*/ oKingBobombUnk104 OBJECT_FIELD_S32(0x1F) #define /*0x108*/ oKingBobombUnk108 OBJECT_FIELD_S32(0x20) +#ifdef QOL_FIXES +#define /*0x108*/ oKingBobombBlinkTimer OBJECT_FIELD_S32(0x21) +#endif /* Klepto */ #define /*0x0F4*/ oKleptoDistanceToTarget OBJECT_FIELD_F32(0x1B) diff --git a/include/stb/stb_image.h b/include/stb/stb_image.h index d9c21bc81..c2f115426 100644 --- a/include/stb/stb_image.h +++ b/include/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.19 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,13 @@ LICENSE RECENT REVISION HISTORY: + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings @@ -84,23 +91,33 @@ RECENT REVISION HISTORY: Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine John-Mark Allen + Carmelo J Fdez-Aguera Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko [reserved] + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -161,6 +178,16 @@ RECENT REVISION HISTORY: // // =========================================================================== // +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// // Philosophy // // stb libraries are designed with the following priorities: @@ -171,12 +198,12 @@ RECENT REVISION HISTORY: // // Sometimes I let "good performance" creep up in priority over "easy to maintain", // and for best performance I may provide less-easy-to-use APIs that give higher -// performance, in addition to the easy to use ones. Nevertheless, it's important +// performance, in addition to the easy-to-use ones. Nevertheless, it's important // to keep in mind that from the standpoint of you, a client of this library, // all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which -// make more explicit reasons why performance can't be emphasized. +// provide more explicit reasons why performance can't be emphasized. // // - Portable ("ease of use") // - Small source code footprint ("easy to maintain") @@ -219,11 +246,10 @@ RECENT REVISION HISTORY: // // HDR image support (disable by defining STBI_NO_HDR) // -// stb_image now supports loading HDR images in general, and currently -// the Radiance .HDR file format, although the support is provided -// generically. You can still load any file through the existing interface; -// if you attempt to load an HDR file, it will be automatically remapped to -// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; // both of these constants can be reconfigured through this interface: // // stbi_hdr_to_ldr_gamma(2.2f); @@ -257,7 +283,7 @@ RECENT REVISION HISTORY: // // By default we convert iphone-formatted PNGs back to RGB, even though // they are internally encoded differently. You can disable this conversion -// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// by calling stbi_convert_iphone_png_to_rgb(0), in which case // you will always just get the native iphone "format" through (which // is BGR stored in RGB). // @@ -301,7 +327,14 @@ RECENT REVISION HISTORY: // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. #ifndef STBI_NO_STDIO #include @@ -319,6 +352,7 @@ enum STBI_rgb_alpha = 4 }; +#include typedef unsigned char stbi_uc; typedef unsigned short stbi_us; @@ -326,11 +360,13 @@ typedef unsigned short stbi_us; extern "C" { #endif +#ifndef STBIDEF #ifdef STB_IMAGE_STATIC #define STBIDEF static #else #define STBIDEF extern #endif +#endif ////////////////////////////////////////////////////////////////////////////// // @@ -355,10 +391,6 @@ typedef struct STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); -#ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -#endif - #ifndef STBI_NO_STDIO STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); @@ -366,6 +398,14 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in // for stbi_load_from_file, file pointer is left pointing immediately after image #endif +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + //////////////////////////////////// // // 16-bits-per-channel interface @@ -413,7 +453,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure -// NOT THREADSAFE +// on most compilers (and ALL modern mainstream compilers) this is threadsafe STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() @@ -446,6 +486,11 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); @@ -525,6 +570,12 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_ASSERT(x) assert(x) #endif +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + #ifndef _MSC_VER #ifdef __cplusplus @@ -536,6 +587,23 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define stbi_inline __forceinline #endif +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif #ifdef _MSC_VER typedef unsigned short stbi__uint16; @@ -649,14 +717,18 @@ static int stbi__cpuid3(void) #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; } +#endif + #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { // If we're even attempting to compile this on GCC/Clang, that means @@ -664,6 +736,8 @@ static int stbi__sse2_available(void) // instructions at will, and so are we. return 1; } +#endif + #endif #endif @@ -682,6 +756,10 @@ static int stbi__sse2_available(void) #define STBI_SIMD_ALIGN(type, name) type name #endif +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + /////////////////////////////////////////////// // // stbi__context struct and start_xxx functions @@ -699,6 +777,7 @@ typedef struct int read_from_callbacks; int buflen; stbi_uc buffer_start[128]; + int callback_already_read; stbi_uc *img_buffer, *img_buffer_end; stbi_uc *img_buffer_original, *img_buffer_original_end; @@ -712,6 +791,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; + s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } @@ -723,7 +803,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; stbi__refill_buffer(s); s->img_buffer_original_end = s->img_buffer_end; } @@ -737,12 +818,17 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { + int ch; fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } } static int stbi__stdio_eof(void *user) { - return feof((FILE*) user); + return feof((FILE*) user) || ferror((FILE *) user); } static stbi_io_callbacks stbi__stdio_callbacks = @@ -840,19 +926,24 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif -// this is not threadsafe -static const char *stbi__g_failure_reason; +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } +#ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } +#endif static void *stbi__malloc(size_t size) { @@ -891,11 +982,13 @@ static int stbi__mul2sizes_valid(int a, int b) return a <= INT_MAX/b; } +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow static int stbi__mad2sizes_valid(int a, int b, int add) { return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); } +#endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow static int stbi__mad3sizes_valid(int a, int b, int c, int add) @@ -913,12 +1006,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) } #endif +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) { if (!stbi__mad2sizes_valid(a, b, add)) return NULL; return stbi__malloc(a*b + add); } +#endif static void *stbi__malloc_mad3(int a, int b, int c, int add) { @@ -962,13 +1057,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif -static int stbi__vertically_flip_on_load = 0; +static int stbi__vertically_flip_on_load_global = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { - stbi__vertically_flip_on_load = flag_true_if_should_flip; + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields @@ -990,6 +1101,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); #endif #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); @@ -1070,6 +1183,7 @@ static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) } } +#ifndef STBI_NO_GIF static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) { int slice; @@ -1077,10 +1191,11 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; } } +#endif static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { @@ -1090,8 +1205,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 8; } @@ -1114,8 +1231,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 16; } @@ -1131,7 +1250,7 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, return (stbi__uint16 *) result; } -#if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { @@ -1143,10 +1262,38 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else @@ -1237,15 +1384,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - + stbi__context s; + stbi__start_mem(&s,buffer,len); + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } - return result; + return result; } #endif @@ -1390,6 +1537,7 @@ enum static void stbi__refill_buffer(stbi__context *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); if (n == 0) { // at end of file, treat same as if from memory, but need to handle case // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file @@ -1414,6 +1562,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s) return 0; } +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { @@ -1425,9 +1576,14 @@ stbi_inline static int stbi__at_eof(stbi__context *s) return s->img_buffer >= s->img_buffer_end; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else static void stbi__skip(stbi__context *s, int n) { + if (n == 0) return; // already there! if (n < 0) { s->img_buffer = s->img_buffer_end; return; @@ -1442,7 +1598,11 @@ static void stbi__skip(stbi__context *s, int n) } s->img_buffer += n; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { @@ -1466,18 +1626,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) } else return 0; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } +#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1499,7 +1668,9 @@ static stbi__uint32 stbi__get32le(stbi__context *s) #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp @@ -1515,7 +1686,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1539,19 +1714,19 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; STBI__CASE(2,1) { dest[0]=src[0]; } break; STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1559,12 +1734,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI_FREE(data); return good; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1588,19 +1771,19 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; STBI__CASE(2,1) { dest[0]=src[0]; } break; STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1608,6 +1791,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI_FREE(data); return good; } +#endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) @@ -1623,7 +1807,11 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) for (k=0; k < n; ++k) { output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } } STBI_FREE(data); return output; @@ -1904,7 +2092,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; @@ -2015,6 +2203,7 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); + if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; @@ -3005,6 +3194,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); c = stbi__get8(s); if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; @@ -3596,7 +3787,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp int k; unsigned int i,j; stbi_uc *output; - stbi_uc *coutput[4]; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; stbi__resample res_comp[4]; @@ -3717,7 +3908,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (n == 1) for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } } } } @@ -3885,16 +4076,23 @@ typedef struct stbi__zhuffman z_length, z_distance; } stbi__zbuf; +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; + return stbi__zeof(z) ? 0 : *z->zbuffer++; } static void stbi__fill_bits(stbi__zbuf *z) { do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); @@ -3919,10 +4117,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; - if (s == 16) return -1; // invalid code! + if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); + if ((unsigned int)b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; @@ -3931,7 +4130,12 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -3945,13 +4149,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; - int cur, limit, old_limit; + unsigned int cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); limit *= 2; + } q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); @@ -4049,11 +4256,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) c = stbi__zreceive(a,2)+3; if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; - } else if (c == 17) + } else if (c == 17) { c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); + } else if (c == 18) { c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); } if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); @@ -4079,7 +4287,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a) a->code_buffer >>= 8; a->num_bits -= 8; } - STBI_ASSERT(a->num_bits == 0); + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); @@ -4101,6 +4309,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png @@ -4362,7 +4571,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return stbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place filter_bytes = 1; width = img_width_bytes; @@ -4731,7 +4940,7 @@ static void stbi__de_iphone(stbi__png *z) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; + stbi_uc has_trans=0, tc[3]={0}; stbi__uint16 tc16[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; int first=1,k,interlace=0, color=0, is_iphone=0; @@ -4757,8 +4966,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); @@ -4875,6 +5086,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); return 1; } @@ -4905,10 +5118,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) + if (p->depth <= 8) ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; else - ri->bits_per_channel = p->depth; + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { @@ -5009,11 +5224,11 @@ static int stbi__high_bit(unsigned int z) { int n=0; if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } return n; } @@ -5030,7 +5245,7 @@ static int stbi__bitcount(unsigned int a) // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(int v, int shift, int bits) +static int stbi__shiftsigned(unsigned int v, int shift, int bits) { static unsigned int mul_table[9] = { 0, @@ -5044,7 +5259,7 @@ static int stbi__shiftsigned(int v, int shift, int bits) v <<= -shift; else v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); + STBI_ASSERT(v < 256); v >>= (8-bits); STBI_ASSERT(bits >= 0 && bits <= 8); return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; @@ -5054,6 +5269,7 @@ typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; + int extra_read; } stbi__bmp_data; static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) @@ -5066,6 +5282,9 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { @@ -5109,6 +5328,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); + info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? @@ -5157,6 +5377,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; mg = info.mg; mb = info.mb; @@ -5165,13 +5388,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz == 12) { if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; + psize = (info.offset - info.extra_read - 24) / 3; } else { if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); + if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } } - s->img_n = ma ? 4 : 3; + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 target = req_comp; else @@ -5193,7 +5425,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); if (info.bpp == 1) width = (s->img_x + 7) >> 3; else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; @@ -5207,6 +5439,8 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req out[z++] = pal[color][0]; out[z++] = pal[color][1]; out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; if((--bit_offset) < 0) { bit_offset = 7; v = stbi__get8(s); @@ -5240,7 +5474,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); + stbi__skip(s, info.offset - info.extra_read - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; @@ -5258,6 +5492,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } } for (j=0; j < (int) s->img_y; ++j) { if (easy) { @@ -5299,7 +5534,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *p1 = out + j *s->img_x*target; stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; + t = p1[i]; p1[i] = p2[i]; p2[i] = t; } } } @@ -5479,6 +5714,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req int RLE_repeating = 0; int read_next_pixel = 1; STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); // do a tiny bit of precessing if ( tga_image_type >= 8 ) @@ -5519,6 +5759,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // do I need to load a palette? if ( tga_indexed) { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette @@ -5642,6 +5887,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Microsoft's C compilers happy... [8^( tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); // OK, done return tga_data; } @@ -5726,6 +5972,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req h = stbi__get32be(s); w = stbi__get32be(s); + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // Make sure the depth is 8 bits. bitdepth = stbi__get16be(s); if (bitdepth != 8 && bitdepth != 16) @@ -5789,7 +6038,7 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // Else if n is 128, noop. // Endloop - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, // which we're going to just skip. stbi__skip(s, h * channelCount * 2 ); @@ -6080,6 +6329,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c x = stbi__get16be(s); y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); @@ -6127,7 +6380,7 @@ typedef struct int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; + stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; @@ -6188,6 +6441,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in g->ratio = stbi__get8(s); g->transparent = -1; + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; @@ -6215,7 +6471,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6224,12 +6480,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; + idx = g->cur_x + g->cur_y; p = &g->out[idx]; - g->history[idx / 4] = 1; + g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6338,31 +6594,36 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int dispose; - int first_frame; - int pi; - int pcount; + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; + first_frame = 0; if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->history = (stbi_uc *) stbi__malloc(g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - - // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to teh color that was there the previous frame. - memset( g->out, 0x00, 4 * g->w * g->h ); - memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - first_frame = 1; + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background @@ -6371,32 +6632,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { - // This is a non-disposal case eithe way, so just + // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } - // clear my history; + // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { - int tag = stbi__get8(s); + int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { @@ -6418,6 +6679,13 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i g->cur_x = g->start_x; g->cur_y = g->start_y; + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + g->lflags = stbi__get8(s); if (g->lflags & 0x40) { @@ -6434,19 +6702,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - + return stbi__errpuc("missing color table", "Corrupt GIF"); + o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; + if (!o) return NULL; - // if this was the first frame, - pcount = g->w * g->h; + // if this was the first frame, + pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } @@ -6457,7 +6725,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); + int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { @@ -6466,23 +6734,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // unset old transparent if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } + g->pal[g->transparent][3] = 255; + } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; + g->pal[g->transparent][3] = 0; } } else { // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; + stbi__skip(s, 1); + g->transparent = -1; } } else { stbi__skip(s, len); break; } - } + } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } @@ -6501,15 +6769,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { - int layers = 0; + int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; - stbi_uc *two_back = 0; + stbi_uc *two_back = 0; stbi__gif g; - int stride; + int stride; + int out_size = 0; + int delays_size = 0; + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); memset(&g, 0, sizeof(g)); if (delays) { - *delays = 0; + *delays = 0; } do { @@ -6519,44 +6791,58 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (u) { *x = g.w; *y = g.h; - ++layers; - stride = g.w * g.h * 4; - + ++layers; + stride = g.w * g.h * 4; + if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + *delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + delays_size = layers * sizeof(int); } } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); + out = (stbi_uc*)stbi__malloc( layers * stride ); + out_size = layers * stride; if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + delays_size = layers * sizeof(int); } } - memcpy( out + ((layers - 1) * stride), u, stride ); + memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out - 2 * stride; } if (delays) { - (*delays)[layers - 1U] = g.delay; + (*delays)[layers - 1U] = g.delay; } } - } while (u != 0); + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; + // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; + *z = layers; return out; } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); + return stbi__errpuc("not GIF", "Image was not as a gif type."); } } @@ -6565,6 +6851,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *u = 0; stbi__gif g; memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); u = stbi__gif_load_next(s, &g, comp, req_comp, 0); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker @@ -6573,14 +6860,17 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req *y = g.h; // moved conversion to after successful load so that the same - // can be done for multiple frames. + // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); } - // free buffers needed for multiple frame loading; + // free buffers needed for multiple frame loading; STBI_FREE(g.history); - STBI_FREE(g.background); + STBI_FREE(g.background); return u; } @@ -6705,6 +6995,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re token += 3; width = (int) strtol(token, NULL, 10); + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + *x = width; *y = height; @@ -6852,7 +7145,12 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) return 0; if (x) *x = s->img_x; if (y) *y = s->img_y; - if (comp) *comp = info.ma ? 4 : 3; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } return 1; } #endif @@ -7014,6 +7312,9 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) return 0; + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; @@ -7238,6 +7539,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user /* revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug diff --git a/include/stb/stb_image_write.h b/include/stb/stb_image_write.h index c05e95812..a685b9e7b 100644 --- a/include/stb/stb_image_write.h +++ b/include/stb/stb_image_write.h @@ -1,4 +1,4 @@ -/* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h +/* stb_image_write - v1.15 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk @@ -10,15 +10,9 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, also before #including, - - #define STBI_MSC_SECURE_CRT - ABOUT: - This header file is a library for writing images to C stdio. It could be - adapted to write to memory or a general streaming interface; let me know. + This header file is a library for writing images to C stdio or a callback. The PNG output is not optimal; it is 20-50% larger than the file written by a decent optimizing implementation; though providing a custom @@ -38,6 +32,14 @@ The returned data will be freed with STBIW_FREE() (free() by default), so it must be heap allocated with STBIW_MALLOC() (malloc() by default), +UNICODE: + + If compiling for Windows and you wish to use Unicode filenames, compile + with + #define STBIW_WINDOWS_UTF8 + and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert + Windows wchar_t filenames to utf8. + USAGE: There are five functions, one for each image file format: @@ -103,7 +105,7 @@ TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. - + JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). @@ -111,7 +113,7 @@ CREDITS: - Sean Barrett - PNG/BMP/TGA + Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements @@ -148,6 +150,8 @@ LICENSE #ifndef INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H +#include + // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC @@ -173,6 +177,10 @@ STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); + +#ifdef STBI_WINDOWS_UTF8 +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif #endif typedef void stbi_write_func(void *context, void *data, int size); @@ -239,17 +247,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #ifdef STB_IMAGE_WRITE_STATIC -static int stbi__flip_vertically_on_write=0; static int stbi_write_png_compression_level = 8; static int stbi_write_tga_with_rle = 1; static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; -int stbi__flip_vertically_on_write=0; int stbi_write_tga_with_rle = 1; int stbi_write_force_png_filter = -1; #endif +static int stbi__flip_vertically_on_write = 0; + STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; @@ -259,6 +267,8 @@ typedef struct { stbi_write_func *func; void *context; + unsigned char buffer[64]; + int buf_used; } stbi__write_context; // initialize a callback-based context @@ -275,15 +285,52 @@ static void stbi__stdio_write(void *context, void *data, int size) fwrite(data,1,size,(FILE*) context); } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#ifdef __cplusplus +#define STBIW_EXTERN extern "C" +#else +#define STBIW_EXTERN extern +#endif +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); + +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = fopen(filename, "wb"); + f = _wfopen(wFilename, wMode); #endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + +static int stbi__start_write_file(stbi__write_context *s, const char *filename) +{ + FILE *f = stbiw__fopen(filename, "wb"); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } @@ -335,16 +382,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) va_end(v); } +static void stbiw__write_flush(stbi__write_context *s) +{ + if (s->buf_used) { + s->func(s->context, &s->buffer, s->buf_used); + s->buf_used = 0; + } +} + static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } +static void stbiw__write1(stbi__write_context *s, unsigned char a) +{ + if ((unsigned int)s->buf_used + 1 > sizeof(s->buffer)) + stbiw__write_flush(s); + s->buffer[s->buf_used++] = a; +} + static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { - unsigned char arr[3]; - arr[0] = a, arr[1] = b, arr[2] = c; - s->func(s->context, arr, 3); + int n; + if ((unsigned int)s->buf_used + 3 > sizeof(s->buffer)) + stbiw__write_flush(s); + n = s->buf_used; + s->buf_used = n+3; + s->buffer[n+0] = a; + s->buffer[n+1] = b; + s->buffer[n+2] = c; } static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) @@ -353,7 +420,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in int k; if (write_alpha < 0) - s->func(s->context, &d[comp - 1], 1); + stbiw__write1(s, d[comp - 1]); switch (comp) { case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case @@ -361,7 +428,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp else - s->func(s->context, d, 1); // monochrome TGA + stbiw__write1(s, d[0]); // monochrome TGA break; case 4: if (!write_alpha) { @@ -377,7 +444,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in break; } if (write_alpha > 0) - s->func(s->context, &d[comp - 1], 1); + stbiw__write1(s, d[comp - 1]); } static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) @@ -391,16 +458,18 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i if (stbi__flip_vertically_on_write) vdir *= -1; - if (vdir < 0) - j_end = -1, j = y-1; - else - j_end = y, j = 0; + if (vdir < 0) { + j_end = -1; j = y-1; + } else { + j_end = y; j = 0; + } for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { unsigned char *d = (unsigned char *) data + (j*x+i)*comp; stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); } + stbiw__write_flush(s); s->func(s->context, &zero, scanline_pad); } } @@ -430,7 +499,7 @@ static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, c STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_bmp_core(&s, x, y, comp, data); } @@ -438,7 +507,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_bmp_core(&s, x, y, comp, data); stbi__end_write_file(&s); @@ -511,24 +580,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v if (diff) { unsigned char header = STBIW_UCHAR(len - 1); - s->func(s->context, &header, 1); + stbiw__write1(s, header); for (k = 0; k < len; ++k) { stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); } } else { unsigned char header = STBIW_UCHAR(len - 129); - s->func(s->context, &header, 1); + stbiw__write1(s, header); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); } } } + stbiw__write_flush(s); } return 1; } STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_tga_core(&s, x, y, comp, (void *) data); } @@ -536,7 +606,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); stbi__end_write_file(&s); @@ -552,7 +622,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); @@ -569,7 +639,7 @@ void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) } } -void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { unsigned char lengthbyte = STBIW_UCHAR(length+128); STBIW_ASSERT(length+128 <= 255); @@ -577,7 +647,7 @@ void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char dat s->func(s->context, &databyte, 1); } -void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { unsigned char lengthbyte = STBIW_UCHAR(length); STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code @@ -585,7 +655,7 @@ void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *d s->func(s->context, data, length); } -void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) { unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; unsigned char rgbe[4]; @@ -686,15 +756,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); -#ifdef STBI_MSC_SECURE_CRT - len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); +#ifdef __STDC_WANT_SECURE_LIB__ + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x); + stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); STBIW_FREE(scratch); return 1; } @@ -702,7 +772,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_hdr_core(&s, x, y, comp, (float *) data); } @@ -710,7 +780,7 @@ STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); stbi__end_write_file(&s); @@ -728,7 +798,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (a) - 2) +#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) #define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbn(a) stbiw__sbraw(a)[1] @@ -809,7 +879,7 @@ static unsigned int stbiw__zhash(unsigned char *data) #endif // STBIW_ZLIB_COMPRESS -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS // user provided a zlib compress implementation, use that @@ -822,7 +892,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); if (hash_table == NULL) return NULL; if (quality < 5) quality = 5; @@ -845,7 +915,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { // if entry lies within window int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) best=d,bestloc=hlist[j]; + if (d >= best) { best=d; bestloc=hlist[j]; } } } // when hash table entry is too long, delete half the entries @@ -904,8 +974,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l int blocklen = (int) (data_len % 5552); j=0; while (j < data_len) { - for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; - s1 %= 65521, s2 %= 65521; + for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } + s1 %= 65521; s2 %= 65521; j += blocklen; blocklen = 5552; } @@ -923,6 +993,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l static unsigned int stbiw__crc32(unsigned char *buffer, int len) { +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else static unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, @@ -964,6 +1037,7 @@ static unsigned int stbiw__crc32(unsigned char *buffer, int len) for (i=0; i < len; ++i) crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; return ~crc; +#endif } #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) @@ -994,9 +1068,15 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int int type = mymap[filter_type]; unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel for (i = 0; i < n; ++i) { switch (type) { - case 0: line_buffer[i] = z[i]; break; case 1: line_buffer[i] = z[i]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; @@ -1005,20 +1085,17 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int case 6: line_buffer[i] = z[i]; break; } } - for (i=n; i < width*n; ++i) { - switch (type) { - case 0: line_buffer[i] = z[i]; break; - case 1: line_buffer[i] = z[i] - z[i-n]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } -unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { int force_filter = stbi_write_force_png_filter; int ctype[5] = { -1, 0, 4, 2, 6 }; @@ -1040,11 +1117,11 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in int filter_type; if (force_filter > -1) { filter_type = force_filter; - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); } else { // Estimate the best filter by running through all of them: int best_filter = 0, best_filter_val = 0x7fffffff, est, i; for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); // Estimate the entropy of the line using this filter; the less, the better. est = 0; @@ -1057,7 +1134,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in } } if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer); + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); filter_type = best_filter; } } @@ -1109,14 +1186,10 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const { FILE *f; int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; -#ifdef STBI_MSC_SECURE_CRT - if (fopen_s(&f, filename, "wb")) - f = NULL; -#else - f = fopen(filename, "wb"); -#endif + + f = stbiw__fopen(filename, "wb"); if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); @@ -1128,7 +1201,7 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) { int len; - unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; func(context, png, len); STBIW_FREE(png); @@ -1222,26 +1295,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { bits[0] = val & ((1< 100 ? 100 : quality; quality = quality < 50 ? 5000 / quality : 200 - quality * 2; @@ -1390,7 +1469,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; s->func(s->context, (void*)head0, sizeof(head0)); s->func(s->context, (void*)YTable, sizeof(YTable)); stbiw__putc(s, 1); @@ -1413,38 +1492,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in // Encode 8x8 macroblocks { static const unsigned short fillBits[] = {0x7F, 7}; - const unsigned char *imageData = (const unsigned char *)data; int DCY=0, DCU=0, DCV=0; int bitBuf=0, bitCnt=0; // comp == 2 is grey+alpha (alpha is ignored) int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; int x, y, pos; - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float YDU[64], UDU[64], VDU[64]; - for(row = y, pos = 0; row < y+8; ++row) { - for(col = x; col < x+8; ++col, ++pos) { - int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp; - float r, g, b; - if(row >= height) { - p -= width*comp*(row+1 - height); + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } - if(col >= width) { - p -= comp*(col+1 - width); + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } } - - r = imageData[p+0]; - g = imageData[p+ofsG]; - b = imageData[p+ofsB]; - YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; - UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; - VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } } } @@ -1461,7 +1576,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) { - stbi__write_context s; + stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); } @@ -1470,7 +1585,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { - stbi__write_context s; + stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); stbi__end_write_file(&s); @@ -1483,6 +1598,13 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) @@ -1531,38 +1653,38 @@ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */ diff --git a/include/text_strings.h.in b/include/text_strings.h.in index e5065c570..f37d75e95 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -337,6 +337,10 @@ // English, "R" text is different #define TEXT_CAMERA_ANGLE_R _("SET CAMERA ANGLE WITH [R]") // French +#ifdef QOL_FIXES +#define TEXT_CATCH_FR _("CAPTURE") +#define TEXT_CLEAR_FR _("DÉGAGER") +#endif #define TEXT_COURSE_FR _("NIVEAU") #define TEXT_MY_SCORE_FR _("MON SCORE") #define TEXT_CONTINUE_FR _("CONTINUER") @@ -344,6 +348,10 @@ #define TEXT_EXIT_GAME_FR _("QUITTER JEU") #define TEXT_CAMERA_ANGLE_R_FR _("RÉGLAGE CAMÉRA AVEC [R]") // German +#ifdef QOL_FIXES +#define TEXT_CATCH_DE _("FANG") +#define TEXT_CLEAR_DE _("KLAR") +#endif #define TEXT_COURSE_DE _("KURS") #define TEXT_MY_SCORE_DE _("LEISTUNG") #define TEXT_CONTINUE_DE _("WEITER") diff --git a/include/types.h b/include/types.h index b3dc27e27..c76298ada 100644 --- a/include/types.h +++ b/include/types.h @@ -291,7 +291,11 @@ struct MarioState /*0x0C*/ u32 action; /*0x10*/ u32 prevAction; /*0x14*/ u32 terrainSoundAddend; + #ifndef QOL_FIXES /*0x18*/ u16 actionState; + #else + /*0x18*/ u32 actionState; + #endif /*0x1A*/ u16 actionTimer; /*0x1C*/ u32 actionArg; /*0x20*/ f32 intendedMag; diff --git a/levels/bits/areas/1/macro.inc.c b/levels/bits/areas/1/macro.inc.c index 663871c0f..6e88dc5c8 100644 --- a/levels/bits/areas/1/macro.inc.c +++ b/levels/bits/areas/1/macro.inc.c @@ -28,7 +28,11 @@ const MacroObject bits_seg7_macro_objs[] = { MACRO_OBJECT(/*preset*/ macro_hidden_1up_trigger, /*yaw*/ 0, /*pos*/ -7200, 2080, -890), MACRO_OBJECT(/*preset*/ macro_hidden_1up_trigger, /*yaw*/ 0, /*pos*/ -6600, 2080, -1550), MACRO_OBJECT_WITH_BEH_PARAM(/*preset*/ macro_hidden_1up, /*yaw*/ 0, /*pos*/ -6640, 2280, -890, /*behParam*/ 3), + #ifdef QOL_FIXES + MACRO_OBJECT(/*preset*/ macro_goomba_triplet_spawner, /*yaw*/ 45, /*pos*/ -5476, 3839, -930), + #else MACRO_OBJECT(/*preset*/ macro_goomba_triplet_spawner, /*yaw*/ 0, /*pos*/ -5239, 3839, -999), + #endif MACRO_OBJECT(/*preset*/ macro_bobomb, /*yaw*/ 0, /*pos*/ -1559, 3800, -1079), MACRO_OBJECT(/*preset*/ macro_bobomb, /*yaw*/ 0, /*pos*/ -1079, 3800, -1039), MACRO_OBJECT(/*preset*/ macro_coin_line_horizontal, /*yaw*/ 0, /*pos*/ 1879, 4639, -1559), diff --git a/levels/castle_grounds/areas/1/11/geo.inc.c b/levels/castle_grounds/areas/1/11/geo.inc.c index e5127f1d0..50467408f 100644 --- a/levels/castle_grounds/areas/1/11/geo.inc.c +++ b/levels/castle_grounds/areas/1/11/geo.inc.c @@ -22,6 +22,8 @@ const GeoLayout castle_grounds_geo_000660[] = { GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES GEO_CLOSE_NODE(), //! more close than open nodes +#endif GEO_END(), }; diff --git a/levels/ccm/areas/2/trajectory.inc.c b/levels/ccm/areas/2/trajectory.inc.c index 1bff30478..38e940dcb 100644 --- a/levels/ccm/areas/2/trajectory.inc.c +++ b/levels/ccm/areas/2/trajectory.inc.c @@ -27,7 +27,12 @@ const Trajectory ccm_seg7_trajectory_penguin_race[] = { TRAJECTORY_POS(24, /*pos*/ 1333, 761, -1733), TRAJECTORY_POS(25, /*pos*/ 2488, 562, -2944), TRAJECTORY_POS(26, /*pos*/ 2977, 361, -4988), + #ifndef QOL_FIXES //! missing ID + #else + // TODO: Find suitable coordinates for this + //TRAJECTORY_POS(27, /*pos*/ 0, 0, 0), + #endif TRAJECTORY_POS(28, /*pos*/ 3754, 329, -5689), TRAJECTORY_POS(29, /*pos*/ 5805, 86, -5980), TRAJECTORY_POS(30, /*pos*/ 6566, -449, -4133), diff --git a/levels/menu/script.c b/levels/menu/script.c index 4e955c120..f36f4cf9f 100644 --- a/levels/menu/script.c +++ b/levels/menu/script.c @@ -88,7 +88,11 @@ const LevelScript level_main_menu_entry_2[] = { /*37*/ TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF), /*39*/ SLEEP(/*frames*/ 16), /*40*/ CLEAR_LEVEL(), + #ifndef QOL_FIXES /*41*/ SLEEP_BEFORE_EXIT(/*frames*/ 1), + #else + /*41*/ SLEEP_BEFORE_EXIT(/*frames*/ 5), + #endif // L1: /*42*/ EXIT(), }; diff --git a/levels/sl/areas/1/macro.inc.c b/levels/sl/areas/1/macro.inc.c index d75dac182..2ac5d997e 100644 --- a/levels/sl/areas/1/macro.inc.c +++ b/levels/sl/areas/1/macro.inc.c @@ -3,7 +3,11 @@ const MacroObject sl_seg7_area_1_macro_objs[] = { MACRO_OBJECT_WITH_BEH_PARAM(/*preset*/ macro_wooden_signpost, /*yaw*/ 90, /*pos*/ 4086, 1024, 400, /*behParam*/ DIALOG_086), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 1285, 2210, 385), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 1728, 2560, -671), + #ifdef QOL_FIXES + MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 1371, 3072, -500), + #else MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 1371, 2188, -500), + #endif MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 1814, 3174, 114), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 28, 3328, 1885), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -228, 3482, 1742), diff --git a/levels/sl/script.c b/levels/sl/script.c index 47e1338cf..d521592ce 100644 --- a/levels/sl/script.c +++ b/levels/sl/script.c @@ -24,6 +24,9 @@ static const LevelScript script_func_local_1[] = { }; static const LevelScript script_func_local_2[] = { +#ifdef QOL_FIXES + OBJECT(/*model*/ MODEL_SL_CRACKED_ICE, /*pos*/ 4377, 1843, 4361, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvUnusedPoundablePlatform), +#endif OBJECT(/*model*/ MODEL_NONE, /*pos*/ 977, 1024, 2075, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvSnowMoundSpawn), RETURN(), }; diff --git a/levels/thi/areas/1/macro.inc.c b/levels/thi/areas/1/macro.inc.c index e622e4db6..7833449c3 100644 --- a/levels/thi/areas/1/macro.inc.c +++ b/levels/thi/areas/1/macro.inc.c @@ -16,7 +16,11 @@ const MacroObject thi_seg7_area_1_macro_objs[] = { MACRO_OBJECT(/*preset*/ macro_huge_goomba, /*yaw*/ 0, /*pos*/ 4600, -1544, 3455), MACRO_OBJECT(/*preset*/ macro_huge_goomba, /*yaw*/ 0, /*pos*/ 3444, -522, 3011), MACRO_OBJECT(/*preset*/ macro_huge_goomba, /*yaw*/ 0, /*pos*/ -3622, -511, 3100), + #ifdef QOL_FIXES + MACRO_OBJECT(/*preset*/ macro_coin_line_horizontal, /*yaw*/ 0, /*pos*/ -4911, -165, -1433), + #else MACRO_OBJECT(/*preset*/ macro_coin_line_horizontal, /*yaw*/ 0, /*pos*/ -4911, -395, -1433), + #endif MACRO_OBJECT(/*preset*/ macro_coin_line_horizontal, /*yaw*/ 90, /*pos*/ 199, 2233, 433), MACRO_OBJECT(/*preset*/ macro_huge_goomba, /*yaw*/ 0, /*pos*/ -3177, 1255, -2366), MACRO_OBJECT(/*preset*/ macro_chuckya, /*yaw*/ 0, /*pos*/ -1800, 2233, -322), diff --git a/levels/thi/areas/2/macro.inc.c b/levels/thi/areas/2/macro.inc.c index a825abe49..2fb9ed8bf 100644 --- a/levels/thi/areas/2/macro.inc.c +++ b/levels/thi/areas/2/macro.inc.c @@ -38,9 +38,15 @@ const MacroObject thi_seg7_area_2_macro_objs[] = { MACRO_OBJECT(/*preset*/ macro_tiny_goomba, /*yaw*/ 0, /*pos*/ 1822, -460, -1511), MACRO_OBJECT(/*preset*/ macro_tiny_goomba, /*yaw*/ 0, /*pos*/ 2148, -460, -918), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -133, -491, -1481), + #ifdef QOL_FIXES + MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, 26, -814), + MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, -16, -518), + MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, -149, -162), + #else MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, -70, -814), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, -107, -518), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -1466, -151, -162), + #endif MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ 133, -491, -1496), MACRO_OBJECT(/*preset*/ macro_box_1up, /*yaw*/ 0, /*pos*/ -1866, -400, 311), MACRO_OBJECT(/*preset*/ macro_yellow_coin_2, /*yaw*/ 0, /*pos*/ -380, -480, 370), diff --git a/levels/ttm/areas/1/14/geo.inc.c b/levels/ttm/areas/1/14/geo.inc.c index 98ee9baae..1745e2394 100644 --- a/levels/ttm/areas/1/14/geo.inc.c +++ b/levels/ttm/areas/1/14/geo.inc.c @@ -7,6 +7,12 @@ const GeoLayout ttm_geo_000920[] = { GEO_DISPLAY_LIST(LAYER_OPAQUE, ttm_seg7_dl_0700DF78), GEO_OPEN_NODE(), GEO_CLOSE_NODE(), +#ifndef QOL_FIXES //! Too many open nodes. Unfortunately not exploitable GEO_END(), +#else + GEO_CLOSE_NODE(), + GEO_CLOSE_NODE(), + GEO_END(), +#endif }; diff --git a/levels/vcutm/script.c b/levels/vcutm/script.c index fb52c9569..9e26c641b 100644 --- a/levels/vcutm/script.c +++ b/levels/vcutm/script.c @@ -49,8 +49,11 @@ const LevelScript level_vcutm_entry[] = { MARIO(/*model*/ MODEL_MARIO, /*behParam*/ 0x00000001, /*beh*/ bhvMario), JUMP_LINK(script_func_global_1), JUMP_LINK(script_func_global_9), - LOAD_MODEL_FROM_GEO(MODEL_VCUTM_SEESAW_PLATFORM, vcutm_geo_0001F0), - LOAD_MODEL_FROM_GEO(MODEL_VCUTM_WARP_PIPE, warp_pipe_geo), + LOAD_MODEL_FROM_GEO(MODEL_VCUTM_SEESAW_PLATFORM, vcutm_geo_0001F0), + #ifdef QOL_FIXES + LOAD_MODEL_FROM_GEO(MODEL_VCUTM_CHECKERBOARD_PLATFORM_SPAWNER, NULL), + #endif + LOAD_MODEL_FROM_GEO(MODEL_VCUTM_WARP_PIPE, warp_pipe_geo), AREA(/*index*/ 1, vcutm_geo_000208), OBJECT(/*model*/ MODEL_NONE, /*pos*/ -6143, 6734, -6143, /*angle*/ 0, 0, 0, /*behParam*/ 0x000A0000, /*beh*/ bhvAirborneWarp), diff --git a/levels/wf/script.c b/levels/wf/script.c index 6697b4973..027d09d90 100644 --- a/levels/wf/script.c +++ b/levels/wf/script.c @@ -40,7 +40,11 @@ static const LevelScript script_func_local_2[] = { OBJECT(/*model*/ MODEL_WF_SLIDING_PLATFORM, /*pos*/ 3328, 1075, -767, /*angle*/ 0, 90, 0, /*behParam*/ 0x00010000, /*beh*/ bhvWfSlidingPlatform), OBJECT(/*model*/ MODEL_WF_SLIDING_PLATFORM, /*pos*/ 3328, 1075, -2815, /*angle*/ 0, 90, 0, /*behParam*/ 0x00030000, /*beh*/ bhvWfSlidingPlatform), OBJECT(/*model*/ MODEL_WF_TUMBLING_BRIDGE, /*pos*/ 1792, 2496, 1600, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvWfTumblingBridge), + #ifndef QOL_FIXES OBJECT(/*model*/ MODEL_WF_BREAKABLE_WALL_RIGHT, /*pos*/ 512, 2176, 2944, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvWfBreakableWallRight), + #else + OBJECT(/*model*/ MODEL_WF_BREAKABLE_WALL_RIGHT, /*pos*/ 512, 2176, 2944, /*angle*/ 0, 0, 0, /*behParam*/ 0x05000000, /*beh*/ bhvWfBreakableWallRight), + #endif OBJECT(/*model*/ MODEL_WF_BREAKABLE_WALL_LEFT, /*pos*/ -1023, 2176, 2944, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhvWfBreakableWallLeft), OBJECT_WITH_ACTS(/*model*/ MODEL_WF_KICKABLE_BOARD, /*pos*/ 13, 3584, -1407, /*angle*/ 0, 315, 0, /*behParam*/ 0x00000000, /*beh*/ bhvKickableBoard, /*acts*/ ACT_2 | ACT_3 | ACT_4 | ACT_5 | ACT_6), OBJECT_WITH_ACTS(/*model*/ MODEL_1UP, /*pos*/ -384, 3584, 6, /*angle*/ 0, 0, 0, /*behParam*/ 0x00000000, /*beh*/ bhv1Up, /*acts*/ ACT_2 | ACT_3 | ACT_4 | ACT_5 | ACT_6), @@ -87,7 +91,9 @@ static const LevelScript script_func_local_4[] = { OBJECT_WITH_ACTS(/*model*/ MODEL_STAR, /*pos*/ -2500, 1500, -750, /*angle*/ 0, 0, 0, /*behParam*/ 0x02000000, /*beh*/ bhvStar, /*acts*/ ALL_ACTS), OBJECT_WITH_ACTS(/*model*/ MODEL_NONE, /*pos*/ 4600, 550, 2500, /*angle*/ 0, 0, 0, /*behParam*/ 0x03000000, /*beh*/ bhvHiddenRedCoinStar, /*acts*/ ALL_ACTS), OBJECT_WITH_ACTS(/*model*/ MODEL_STAR, /*pos*/ 2880, 4300, 190, /*angle*/ 0, 0, 0, /*behParam*/ 0x04000000, /*beh*/ bhvStar, /*acts*/ ALL_ACTS), + #ifndef QOL_FIXES OBJECT_WITH_ACTS(/*model*/ MODEL_STAR, /*pos*/ 590, 2450, 2650, /*angle*/ 0, 0, 0, /*behParam*/ 0x05000000, /*beh*/ bhvStar, /*acts*/ ALL_ACTS), + #endif RETURN(), }; diff --git a/src/audio/data.c b/src/audio/data.c index 47b02c4d8..34dba042c 100644 --- a/src/audio/data.c +++ b/src/audio/data.c @@ -173,11 +173,19 @@ u8 gDefaultShortNoteDurationTable[16] = { s8 gVibratoCurve[16] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120 }; #endif +#ifndef TARGET_WEB struct AdsrEnvelope gDefaultEnvelope[] = { { BE_TO_HOST16(4), BE_TO_HOST16(32000) }, // go from 0 to 32000 over the course of 16ms { BE_TO_HOST16(1000), BE_TO_HOST16(32000) }, // stay there for 4.16 seconds { BE_TO_HOST16(ADSR_HANG), 0 } // then continue staying there }; +#else +struct AdsrEnvelope gDefaultEnvelope[] = { + { (s16)BE_TO_HOST16(4), (s16)BE_TO_HOST16(32000) }, // go from 0 to 32000 over the course of 16ms + { (s16)BE_TO_HOST16(1000), (s16)BE_TO_HOST16(32000) }, // stay there for 4.16 seconds + { (s16)BE_TO_HOST16(ADSR_HANG), 0 } // then continue staying there +}; +#endif #ifdef VERSION_EU struct NoteSubEu gZeroNoteSub = { 0 }; diff --git a/src/audio/external.c b/src/audio/external.c index d8a26b35d..2293a8e35 100644 --- a/src/audio/external.c +++ b/src/audio/external.c @@ -227,7 +227,7 @@ s32 sGameLoopTicked = 0; #define YOSHI 10 #define _ 0xFF -#ifdef VERSION_JP +#if BUGFIX_DIALOG_SOUND_KTQ_WIN #define DIFF KOOPA #else #define DIFF TUXIE @@ -621,8 +621,11 @@ const char unusedErrorStr2[] = "specchg error\n"; /** * Fade out a sequence player */ -#if defined(VERSION_EU) +#ifdef VERSION_EU +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" void audio_reset_session_eu(s32 presetId) { OSMesg mesg; @@ -633,6 +636,7 @@ void audio_reset_session_eu(s32 presetId) { osRecvMesg(OSMesgQueues[3], &mesg, OS_MESG_BLOCK); } } +#pragma GCC diagnostic pop #else diff --git a/src/audio/heap.c b/src/audio/heap.c index a183a7074..26b210161 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -302,7 +302,11 @@ void temporary_pools_init(struct PoolSplit *a) { } #ifndef VERSION_EU +#ifndef TARGET_WEB static void unused_803163D4(void) { +#else +UNUSED static void unused_803163D4(void) { +#endif } #endif @@ -558,8 +562,13 @@ void func_eu_802e27e4_unused(f32 arg0, f32 arg1, u16 *arg2) { for (i = 2; i < 8; i++) { //! @bug they probably meant to store the value to tmp[i] and tmp[8 + i] + #ifndef QOL_FIXES arg2[i] = arg1 * tmp[i - 2] + arg0 * tmp[i - 1]; arg2[8 + i] = arg1 * tmp[6 + i] + arg0 * tmp[7 + i]; + #else + tmp[i] = arg1 * tmp[i - 2] + arg0 * tmp[i - 1]; + tmp[8 + i] = arg1 * tmp[6 + i] + arg0 * tmp[7 + i]; + #endif } for (i = 0; i < 16; i++) { diff --git a/src/audio/heap.h b/src/audio/heap.h index 7f99b9a71..beca026ed 100644 --- a/src/audio/heap.h +++ b/src/audio/heap.h @@ -65,9 +65,14 @@ void sound_init_main_pools(s32 sizeForAudioInitPool); void *alloc_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 size, s32 arg3, s32 id); void *get_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 arg2); #ifdef VERSION_EU +#ifdef TARGET_WEB s32 audio_shut_down_and_reset_step(void); void audio_reset_session(void); #else +s32 audio_shut_down_and_reset_step(void); +void audio_reset_session(void); +#endif +#else void audio_reset_session(struct AudioSessionSettings *preset); #endif diff --git a/src/audio/load.c b/src/audio/load.c index d4c27b746..6215253fc 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -27,7 +27,11 @@ void port_eu_init(void); struct Note *gNotes; #ifdef VERSION_EU +#ifndef TARGET_WEB static u8 pad[4]; +#else +UNUSED static u8 pad[4]; +#endif #endif struct SequencePlayer gSequencePlayers[SEQUENCE_PLAYERS]; @@ -390,7 +394,11 @@ void init_sample_dma_buffers(UNUSED s32 arg0) { static #endif +#ifndef TARGET_WEB void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED u8 *offsetBase) { +#else +UNUSED void patch_sound(UNUSED struct AudioBankSound *sound, UNUSED u8 *memBase, UNUSED u8 *offsetBase) { +#endif struct AudioBankSample *sample; void *patched; UNUSED u8 *mem; // unused on US @@ -486,10 +494,16 @@ void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 mem->drums[i] = drum; if (drum->loaded == 0) { #ifndef VERSION_EU +#ifndef QOL_FIXES //! copt replaces drum with 'patched' for these two lines PATCH_SOUND(&(*(struct Drum *)patched).sound, mem, offset); patched = (*(struct Drum *)patched).envelope; drum->envelope = (void *)((uintptr_t) mem + (uintptr_t) patched); +#else + patch_sound(&drum->sound, (u8 *) mem, offset); + patched = drum->envelope; + drum->envelope = (void *)((uintptr_t) patched + (uintptr_t) mem); +#endif #else patch_sound(&drum->sound, (u8 *) mem, offset); patched = drum->envelope; @@ -789,7 +803,11 @@ void preload_sequence(u32 seqId, u8 preloadMask) { if (preloadMask & PRELOAD_SEQUENCE) { // @bug should be IS_SEQ_LOAD_COMPLETE + #ifndef QOL_FIXES if (IS_BANK_LOAD_COMPLETE(seqId) == TRUE) { + #else + if (IS_SEQ_LOAD_COMPLETE(seqId) == TRUE) { + #endif sequenceData = get_bank_or_seq(&gSeqLoadedPool, 2, seqId); } else { sequenceData = NULL; @@ -894,7 +912,11 @@ void audio_init() { UNUSED s8 pad[32]; u8 buf[0x10]; #endif +#ifndef TARGET_WEB s32 i, j, UNUSED k; +#else + s32 i, j, UNUSED k = 0; +#endif UNUSED s32 lim1; // lim1 unused in EU #ifdef VERSION_EU u8 buf[0x10]; diff --git a/src/audio/port_eu.c b/src/audio/port_eu.c index 4fbc74dbd..b2ab679fa 100644 --- a/src/audio/port_eu.c +++ b/src/audio/port_eu.c @@ -4,6 +4,7 @@ #include "data.h" #include "seqplayer.h" #include "synthesis.h" +#include "heap.h" #ifdef VERSION_EU @@ -37,6 +38,9 @@ void func_802ad7ec(u32); struct SPTask *create_next_audio_frame_task(void) { return NULL; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" void create_next_audio_buffer(s16 *samples, u32 num_samples) { s32 writtenCmds; OSMesg msg; @@ -58,6 +62,7 @@ void create_next_audio_buffer(s16 *samples, u32 num_samples) { gAudioRandom = ((gAudioRandom + gAudioFrameCount) * gAudioFrameCount); gAudioRandom = gAudioRandom + writtenCmds / 8; } +#pragma GCC diagnostic pop void eu_process_audio_cmd(struct EuAudioCmd *cmd) { s32 i; @@ -164,12 +169,15 @@ void func_802ad770(u32 arg0, s8 arg1) { func_802ad6f0(arg0, &sp1C); } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" void func_802ad7a0(void) { osSendMesg(OSMesgQueues[1], (OSMesg)(u32)((D_EU_80302014 & 0xff) << 8 | (D_EU_80302010 & 0xff)), OS_MESG_NOBLOCK); D_EU_80302014 = D_EU_80302010; } +#pragma GCC diagnostic pop void func_802ad7ec(u32 arg0) { struct EuAudioCmd *cmd; diff --git a/src/audio/synthesis.c b/src/audio/synthesis.c index 1fdd85108..991070d0a 100644 --- a/src/audio/synthesis.c +++ b/src/audio/synthesis.c @@ -273,7 +273,18 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) { for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) { if (i == 1) { // self-assignment has no affect when added here, could possibly simplify a macro definition + #ifndef TARGET_WEB + #ifndef QOL_FIXES + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wself-assign" chunkLen = bufLen; nextVolRampTable = nextVolRampTable; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF]; + #pragma GCC diagnostic pop + #else + chunkLen = bufLen; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF]; + #endif + #else + chunkLen = bufLen; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF]; + #endif } else { if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) { chunkLen = gAudioBufferParameters.samplesPerUpdateMax; nextVolRampTable = 2; leftVolRamp = gLeftVolRampings[2]; rightVolRamp = gRightVolRampings[2]; diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index f61f2bf4b..7af958dcc 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -31,7 +31,11 @@ static u16 gRandomSeed16; // Unused function that directly jumps to a behavior command and resets the object's stack index. +#ifndef TARGET_WEB static void goto_behavior_unused(const BehaviorScript *bhvAddr) { +#else +UNUSED static void goto_behavior_unused(const BehaviorScript *bhvAddr) { +#endif gCurBhvCommand = segmented_to_virtual(bhvAddr); gCurrentObject->bhvStackIndex = 0; } @@ -107,7 +111,11 @@ static uintptr_t cur_obj_bhv_stack_pop(void) { return bhvAddr; } +#ifndef TARGET_WEB static void stub_behavior_script_1(void) { +#else +UNUSED static void stub_behavior_script_1(void) { +#endif for (;;) { ; } @@ -691,11 +699,16 @@ static s32 bhv_cmd_begin(void) { return BHV_PROC_CONTINUE; } +#ifndef QOL_FIXES // An unused, incomplete behavior command that does not have an entry in the lookup table, and so no command number. // It cannot be simply re-added to the table, as unlike all other bhv commands it takes a parameter. // Theoretically this command would have been of variable size. // Included below is a modified/repaired version of this function that would work properly. +#ifndef TARGET_WEB static void bhv_cmd_set_int_random_from_table(s32 tableSize) { +#else +UNUSED static void bhv_cmd_set_int_random_from_table(s32 tableSize) { +#endif u8 field = BHV_CMD_GET_2ND_U8(0); s32 table[16]; s32 i; @@ -710,11 +723,15 @@ static void bhv_cmd_set_int_random_from_table(s32 tableSize) { // Does not increment gCurBhvCommand or return a bhv status } -/** +#else // Command 0x??: Sets the specified field to a random entry in the given table, up to size 16. // Bytes: ?? FF SS SS V1 V1 V2 V2 V3 V3 V4 V4... ...V15 V15 V16 V16 (no macro exists) // F -> field, S -> table size, V1, V2, etc. -> table entries (up to 16) +#ifndef TARGET_WEB static s32 bhv_cmd_set_int_random_from_table(void) { +#else +UNUSED static s32 bhv_cmd_set_int_random_from_table(void) { +#endif u8 field = BHV_CMD_GET_2ND_U8(0); // Retrieve tableSize from the bhv command instead of as a parameter. s16 tableSize = BHV_CMD_GET_2ND_S16(0); // tableSize should not be greater than 16 @@ -733,7 +750,7 @@ static s32 bhv_cmd_set_int_random_from_table(void) { gCurBhvCommand += (tableSize / 2) + 1; return BHV_PROC_CONTINUE; } -**/ +#endif // Command 0x2A: Loads collision data for the object. // Usage: LOAD_COLLISION_DATA(collisionData) @@ -908,7 +925,12 @@ static BhvCommandProc BehaviorCmdTable[] = { bhv_cmd_disable_rendering, //35 bhv_cmd_set_int_unused, //36 bhv_cmd_spawn_water_droplet, //37 + #ifndef QOL_FIXES bhv_cmd_cylboard //38 + #else + bhv_cmd_cylboard, //38 + bhv_cmd_set_int_random_from_table //39 + #endif }; // Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects. diff --git a/src/engine/math_util.c b/src/engine/math_util.c index ca2a74571..47531305e 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -4,6 +4,7 @@ #include "engine/graph_node.h" #include "math_util.h" #include "surface_collision.h" +#include "include/libc/math.h" #include "trig_tables.inc.c" @@ -14,15 +15,24 @@ int gSplineState; // These functions have bogus return values. // Disable the compiler warning. +#ifndef TARGET_WEB #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wreturn-local-addr" +#endif /// Copy vector 'src' to 'dest' void *vec3f_copy(Vec3f dest, Vec3f src) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Set vector 'dest' to (x, y, z) @@ -30,7 +40,14 @@ void *vec3f_set(Vec3f dest, f32 x, f32 y, f32 z) { dest[0] = x; dest[1] = y; dest[2] = z; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Add vector 'a' to 'dest' @@ -38,7 +55,14 @@ void *vec3f_add(Vec3f dest, Vec3f a) { dest[0] += a[0]; dest[1] += a[1]; dest[2] += a[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Make 'dest' the sum of vectors a and b. @@ -46,7 +70,14 @@ void *vec3f_sum(Vec3f dest, Vec3f a, Vec3f b) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Multiply vector 'dest' by a @@ -55,7 +86,14 @@ void *vec3f_mul(Vec3f dest, f32 a) dest[0] *= a; dest[1] *= a; dest[2] *= a; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Copy vector src to dest @@ -63,7 +101,14 @@ void *vec3s_copy(Vec3s dest, Vec3s src) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Set vector 'dest' to (x, y, z) @@ -71,7 +116,14 @@ void *vec3s_set(Vec3s dest, s16 x, s16 y, s16 z) { dest[0] = x; dest[1] = y; dest[2] = z; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Add vector a to 'dest' @@ -79,7 +131,14 @@ void *vec3s_add(Vec3s dest, Vec3s a) { dest[0] += a[0]; dest[1] += a[1]; dest[2] += a[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Make 'dest' the sum of vectors a and b. @@ -87,7 +146,14 @@ void *vec3s_sum(Vec3s dest, Vec3s a, Vec3s b) { dest[0] = a[0] + b[0]; dest[1] = a[1] + b[1]; dest[2] = a[2] + b[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Make 'dest' the difference of vectors a and b. @@ -95,7 +161,14 @@ void *vec3f_dif(Vec3f dest, Vec3f a, Vec3f b) { dest[0] = a[0] - b[0]; dest[1] = a[1] - b[1]; dest[2] = a[2] - b[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Convert short vector a to float vector 'dest' @@ -103,7 +176,14 @@ void *vec3s_to_vec3f(Vec3f dest, Vec3s a) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /** @@ -115,7 +195,14 @@ void *vec3f_to_vec3s(Vec3s dest, Vec3f a) { dest[0] = a[0] + ((a[0] > 0) ? 0.5f : -0.5f); dest[1] = a[1] + ((a[1] > 0) ? 0.5f : -0.5f); dest[2] = a[2] + ((a[2] > 0) ? 0.5f : -0.5f); + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /** @@ -127,7 +214,14 @@ void *find_vector_perpendicular_to_plane(Vec3f dest, Vec3f a, Vec3f b, Vec3f c) dest[0] = (b[1] - a[1]) * (c[2] - b[2]) - (c[1] - b[1]) * (b[2] - a[2]); dest[1] = (b[2] - a[2]) * (c[0] - b[0]) - (c[2] - b[2]) * (b[0] - a[0]); dest[2] = (b[0] - a[0]) * (c[1] - b[1]) - (c[0] - b[0]) * (b[1] - a[1]); + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Make vector 'dest' the cross product of vectors a and b. @@ -135,18 +229,41 @@ void *vec3f_cross(Vec3f dest, Vec3f a, Vec3f b) { dest[0] = a[1] * b[2] - b[1] * a[2]; dest[1] = a[2] * b[0] - b[2] * a[0]; dest[2] = a[0] * b[1] - b[0] * a[1]; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Scale vector 'dest' so it has length 1 void *vec3f_normalize(Vec3f dest) { + #ifndef QOL_FIXES //! Possible division by zero f32 invsqrt = 1.0f / sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]); + #else + f32 invsqrt = 1.0f; + if (sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]) != 0) { + invsqrt /= sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]); + } else { + invsqrt *= 0.0f; + } + #endif dest[0] *= invsqrt; dest[1] *= invsqrt; dest[2] *= invsqrt; + #ifndef QOL_FIXES + #ifndef TARGET_WEB return &dest; //! warning: function returns address of local variable + #endif + #endif + #ifdef TARGET_WEB + return 0; + #endif } /// Get length of vector 'a' @@ -161,7 +278,9 @@ f32 vec3f_dot(Vec3f a, Vec3f b) return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } +#ifndef TARGET_WEB #pragma GCC diagnostic pop +#endif /// Copy matrix 'src' to 'dest' void mtxf_copy(Mat4 dest, Mat4 src) { @@ -791,7 +910,11 @@ s16 atan2s(f32 y, f32 x) { * Compute the atan2 in radians by calling atan2s and converting the result. */ f32 atan2f(f32 y, f32 x) { + #ifndef QOL_FIXES return (f32) atan2s(y, x) * M_PI / 0x8000; + #else + return (f32) atan2s(y, x) * M__PI / 0x8000; + #endif } #define CURVE_BEGIN_1 1 diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 1da535b9b..d79b49638 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -310,14 +310,24 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { struct SurfaceNode *surfaceList; f32 height = 20000.0f; f32 dynamicHeight = 20000.0f; + #ifndef QOL_FIXES s16 x, y, z; + #else + s32 x, y, z; + #endif //! (Parallel Universes) Because position is casted to an s16, reaching higher - // float locations can return ceilings despite them not existing there. + // float locations can return ceilings despite them not existing there. //(Dynamic ceilings will unload due to the range.) + #ifndef QOL_FIXES x = (s16) posX; y = (s16) posY; z = (s16) posZ; + #else + x = (s32) posX; + y = (s32) posY; + z = (s32) posZ; + #endif *pceil = NULL; if (x <= -LEVEL_BOUNDARY_MAX || x >= LEVEL_BOUNDARY_MAX) { @@ -370,7 +380,11 @@ f32 unused_obj_find_floor_height(struct Object *obj) { */ struct FloorGeometry sFloorGeo; +#ifndef TARGET_WEB static u8 unused8038BE50[0x40]; +#else +UNUSED static u8 unused8038BE50[0x40]; +#endif /** * Return the floor height underneath (xPos, yPos, zPos) and populate `floorGeo` @@ -490,13 +504,24 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl f32 floorHeight = -11000.0f; // Would normally cause PUs, but dynamic floors unload at that range. + #ifndef QOL_FIXES s16 x = (s16) xPos; s16 y = (s16) yPos; s16 z = (s16) zPos; + #else + s32 x = (s32) xPos; + s32 y = (s32) yPos; + s32 z = (s32) zPos; + #endif // Each level is split into cells to limit load, find the appropriate cell. + #ifndef QOL_FIXES s16 cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & 0x0F; s16 cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & 0x0F; + #else + s32 cellX = ((x + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & 0x0F; + s32 cellZ = ((z + LEVEL_BOUNDARY_MAX) / CELL_SIZE) & 0x0F; + #endif surfaceList = gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next; floor = find_floor_from_list(surfaceList, x, y, z, &floorHeight); @@ -510,7 +535,11 @@ f32 unused_find_dynamic_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfl * Find the highest floor under a given position and return the height. */ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { + #ifndef QOL_FIXES s16 cellZ, cellX; + #else + s32 cellZ, cellX; + #endif struct Surface *floor, *dynamicFloor; struct SurfaceNode *surfaceList; @@ -519,11 +548,17 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { f32 dynamicHeight = -11000.0f; //! (Parallel Universes) Because position is casted to an s16, reaching higher - // float locations can return floors despite them not existing there. + // float locations can return floors despite them not existing there. //(Dynamic floors will unload due to the range.) + #ifndef QOL_FIXES s16 x = (s16) xPos; s16 y = (s16) yPos; s16 z = (s16) zPos; + #else + s32 x = (s32) xPos; + s32 y = (s32) yPos; + s32 z = (s32) zPos; + #endif *pfloor = NULL; @@ -547,16 +582,22 @@ f32 find_floor(f32 xPos, f32 yPos, f32 zPos, struct Surface **pfloor) { floor = find_floor_from_list(surfaceList, x, y, z, &height); // To prevent the Merry-Go-Round room from loading when Mario passes above the hole that leads - // there, SURFACE_INTANGIBLE is used. This prevent the wrong room from loading, but can also allow + // there, SURFACE_INTANGIBLE is used. This prevents the wrong room from loading, but can also allow // Mario to pass through. if (!gFindFloorIncludeSurfaceIntangible) { //! (BBH Crash) Most NULL checking is done by checking the height of the floor returned // instead of checking directly for a NULL floor. If this check returns a NULL floor - // (happens when there is no floor under the SURFACE_INTANGIBLE floor) but returns the height + // (happens when there is no floor under the SURFACE_INTANGIBLE floor), it returns the height // of the SURFACE_INTANGIBLE floor instead of the typical -11000 returned for a NULL floor. if (floor != NULL && floor->type == SURFACE_INTANGIBLE) { floor = find_floor_from_list(surfaceList, x, (s32)(height - 200.0f), z, &height); + #ifndef QOL_FIXES } + #else + } else if (floor == NULL) { + height = -11000.0f; + } + #endif } else { // To prevent accidentally leaving the floor tangible, stop checking for it. gFindFloorIncludeSurfaceIntangible = FALSE; diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index ac2ee50ca..1b98ac8d8 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -291,7 +291,11 @@ static void add_surface(struct Surface *surface, s32 dynamic) { } } +#ifndef TARGET_WEB static void stub_surface_load_1(void) { +#else +UNUSED static void stub_surface_load_1(void) { +#endif } /** @@ -651,7 +655,11 @@ void clear_dynamic_surfaces(void) { } } +#ifndef TARGET_WEB static void unused_80383604(void) { +#else +UNUSED static void unused_80383604(void) { +#endif } /** diff --git a/src/game/area.c b/src/game/area.c index ba7768a4b..45f35bae4 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -108,7 +108,11 @@ void set_warp_transition_rgb(u8 red, u8 green, u8 blue) { gWarpTransBlue = blue; } +#ifndef TARGET_WEB static int scale_x_to_correct_aspect_center(int x) { +#else +UNUSED static int scale_x_to_correct_aspect_center(int x) { +#endif f32 aspect = GFX_DIMENSIONS_ASPECT_RATIO; return x + (SCREEN_HEIGHT * aspect / 2) - (SCREEN_WIDTH / 2); } diff --git a/src/game/behaviors/beta_chest.inc.c b/src/game/behaviors/beta_chest.inc.c index 7a1a786d5..ce6aa4d88 100644 --- a/src/game/behaviors/beta_chest.inc.c +++ b/src/game/behaviors/beta_chest.inc.c @@ -21,7 +21,9 @@ void bhv_beta_chest_bottom_init(void) { // cancelled by setting the yaw to 0, right before this beta // object was discarded? o->oMoveAngleYaw = random_u16(); + #ifndef QOL_FIXES o->oMoveAngleYaw = 0; + #endif // Spawn the chest lid 97 units in the +Y direction and 77 units in the -Z direction. spawn_object_relative(0, 0, 97, -77, o, MODEL_TREASURE_CHEST_LID, bhvBetaChestLid); diff --git a/src/game/behaviors/beta_trampoline.inc.c b/src/game/behaviors/beta_trampoline.inc.c index f9c248f57..d6de71757 100644 --- a/src/game/behaviors/beta_trampoline.inc.c +++ b/src/game/behaviors/beta_trampoline.inc.c @@ -30,7 +30,11 @@ void bhv_beta_trampoline_spring_loop(void) { // must be replaced with 150 (the height of the trampoline). // Note that all of the numbers in this if/else block are doubles. if ((yDisplacement = o->oPosY - o->oHomeY) >= 0) { + #ifndef QOL_FIXES yScale = yDisplacement / 10.0 + 1.0; + #else + yScale = yDisplacement / 150.0f + 1.0; + #endif } else { // Otherwise (if the trampoline is compressed), // scale by 1 - (the displacement)/500. @@ -38,7 +42,12 @@ void bhv_beta_trampoline_spring_loop(void) { // must be replaced with 150 (the height of the trampoline), // as with the above code. yDisplacement = -yDisplacement; + #ifndef QOL_FIXES yScale = 1.0 - yDisplacement / 500.0; + #else + yScale = 1.0 - yDisplacement / 150.0f; + o->oPosY += 75.0f * (1.0f - yScale); + #endif } // Scale the spring @@ -73,9 +82,27 @@ void bhv_beta_trampoline_top_loop(void) { // when Mario's on it in this if statement? if (gMarioObject->platform == o) { o->oBetaTrampolineMarioOnTrampoline = TRUE; + #ifdef QOL_FIXES + o->oPosY = + (o->oPosY > (o->oHomeY - 150.0f + 75.0f)) ? + (o->oPosY - 10) : + (o->oHomeY - 150.0f + 65.0f); + + o->oBetaTrampolineAdditiveYVel = + ((o->oBehParams2ndByte >> 4) / 2.0f) + + ((o->oHomeY - o->oPosY) / ((o->oBehParams2ndByte & 0x0F) / 2.0f)); + #endif } else { o->oBetaTrampolineMarioOnTrampoline = FALSE; o->oPosY = o->oHomeY; + #ifdef QOL_FIXES + o->oPosY = + (o->oPosY < (o->oHomeY - 10.0f)) ? + (o->oPosY + 10.0f) : + o->oHomeY; + + o->oBetaTrampolineAdditiveYVel = 0; + #endif } // This function is from mario_step.c, and is empty. diff --git a/src/game/behaviors/boo.inc.c b/src/game/behaviors/boo.inc.c index abfaba866..3700780d5 100644 --- a/src/game/behaviors/boo.inc.c +++ b/src/game/behaviors/boo.inc.c @@ -193,7 +193,11 @@ static void boo_move_during_hit(s32 roll, f32 fVel) { s32 oscillationVel = o->oTimer * 0x800 + 0x800; o->oForwardVel = fVel; + #ifndef QOL_FIXES o->oVelY = coss(oscillationVel); + #else + o->oVelY = coss(oscillationVel) * 0x400; + #endif o->oMoveAngleYaw = o->oBooMoveYawDuringHit; if (roll != FALSE) { diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index f1e16cb13..d7861a2d4 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -78,12 +78,19 @@ void bowling_ball_set_waypoints(void) { void bhv_bowling_ball_roll_loop(void) { s16 collisionFlags; + #ifndef QOL_FIXES s32 sp18; + #else + s32 sp18 = 0; + #endif + #ifdef TARGET_WEB + sp18 = 0; + #endif bowling_ball_set_waypoints(); collisionFlags = object_step(); - //! Uninitialzed parameter, but the parameter is unused in the called function + //! Uninitialized parameter, but the parameter is unused in the called function sp18 = cur_obj_follow_path(sp18); o->oBowlingBallTargetYaw = o->oPathedTargetYaw; @@ -108,11 +115,18 @@ void bhv_bowling_ball_roll_loop(void) { } void bhv_bowling_ball_initializeLoop(void) { + #ifndef QOL_FIXES s32 sp1c; + #else + s32 sp1c = 0; + #endif + #ifdef TARGET_WEB + sp1c = 0; + #endif bowling_ball_set_waypoints(); - //! Uninitialzed parameter, but the parameter is unused in the called function + //! Uninitialized parameter, but the parameter is unused in the called function sp1c = cur_obj_follow_path(sp1c); o->oMoveAngleYaw = o->oPathedTargetYaw; @@ -260,7 +274,11 @@ void bhv_free_bowling_ball_roll_loop(void) { cur_obj_play_sound_1(SOUND_ENV_UNKNOWN2); } + #ifndef QOL_FIXES if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) && !(collisionFlags & OBJ_COL_FLAGS_LANDED)) + #else + if ((collisionFlags & OBJ_COL_FLAG_GROUNDED) && !(collisionFlags & OBJ_COL_FLAG_NO_Y_VEL)) + #endif cur_obj_play_sound_2(SOUND_GENERAL_QUIET_POUND1_LOWPRIO); if (!is_point_within_radius_of_mario(o->oPosX, o->oPosY, o->oPosZ, 6000)) { diff --git a/src/game/behaviors/bowser.inc.c b/src/game/behaviors/bowser.inc.c index ebc6bf475..a790c252e 100644 --- a/src/game/behaviors/bowser.inc.c +++ b/src/game/behaviors/bowser.inc.c @@ -181,7 +181,11 @@ void bowser_act_intro_walk(void) { } } +#ifndef TARGET_WEB static void bowser_debug_actions(void) // unused +#else +UNUSED static void bowser_debug_actions(void) +#endif { if (gDebugInfo[5][1] != 0) { o->oAction = D_8032F4FC[gDebugInfo[5][2] & 0xf]; diff --git a/src/game/behaviors/breakable_wall.inc.c b/src/game/behaviors/breakable_wall.inc.c index 997d22080..5e205f312 100644 --- a/src/game/behaviors/breakable_wall.inc.c +++ b/src/game/behaviors/breakable_wall.inc.c @@ -4,8 +4,12 @@ void bhv_wf_breakable_wall_loop(void) { if (gMarioStates->action == ACT_SHOT_FROM_CANNON) { cur_obj_become_tangible(); if (obj_check_if_collided_with_object(o, gMarioObject)) { - if (cur_obj_has_behavior(bhvWfBreakableWallRight)) + if (cur_obj_has_behavior(bhvWfBreakableWallRight)) { + #ifdef QOL_FIXES + spawn_default_star(590.0f, 2450.0f, 2650.0f); + #endif play_puzzle_jingle(); + } create_sound_spawner(SOUND_GENERAL_WALL_EXPLOSION); o->oInteractType = 8; o->oDamageOrCoinValue = 1; diff --git a/src/game/behaviors/bully.inc.c b/src/game/behaviors/bully.inc.c index efe0ee180..b9a5a4e8b 100644 --- a/src/game/behaviors/bully.inc.c +++ b/src/game/behaviors/bully.inc.c @@ -52,7 +52,11 @@ void bhv_big_bully_init(void) { } void bully_check_mario_collision(void) { - if (o->oInteractStatus & INT_STATUS_INTERACTED) { + if ( +#if BUGFIX_BULLY_NO_INTERACT_DEATH + o->oAction != BULLY_ACT_LAVA_DEATH && o->oAction != BULLY_ACT_DEATH_PLANE_DEATH && +#endif + o->oInteractStatus & INT_STATUS_INTERACTED) { if (o->oBehParams2ndByte == BULLY_BP_SIZE_SMALL) cur_obj_play_sound_2(SOUND_OBJ2_BULLY_ATTACKED); else @@ -122,7 +126,11 @@ void bully_act_back_up(void) { // conditions are activated. However because its angle is set to its facing angle, // it will walk forward instead of backing up. + #ifndef QOL_FIXES if (o->oTimer == 15) { + #else + if (o->oTimer >= 15) { + #endif o->oMoveAngleYaw = o->oFaceAngleYaw; o->oFlags |= 0x8; /* bit 3 */ o->oAction = BULLY_ACT_PATROL; @@ -219,7 +227,13 @@ void bhv_bully_loop(void) { // death action by colliding with it. Since the bully hitbox is tall enough to collide // with Mario even when it is under a lava floor, this can get the bully stuck OOB // if there is nothing under the lava floor. + #ifndef QOL_FIXES bully_check_mario_collision(); + #else + if (o->oAction != BULLY_ACT_LAVA_DEATH || o->oAction != BULLY_ACT_DEATH_PLANE_DEATH) { + bully_check_mario_collision(); + } + #endif switch (o->oAction) { case BULLY_ACT_PATROL: @@ -341,6 +355,9 @@ void bhv_big_bully_with_minions_loop(void) { if (o->oTimer >= 91) o->oAction = BULLY_ACT_ACTIVATE_AND_FALL; + #ifdef QOL_FIXES + o->oBullyKBTimerAndMinionKOCounter = 0; + #endif } break; diff --git a/src/game/behaviors/camera_lakitu.inc.c b/src/game/behaviors/camera_lakitu.inc.c index 0f70c3398..1c97e1d83 100644 --- a/src/game/behaviors/camera_lakitu.inc.c +++ b/src/game/behaviors/camera_lakitu.inc.c @@ -28,10 +28,17 @@ void bhv_camera_lakitu_init(void) { static void camera_lakitu_intro_act_trigger_cutscene(void) { //! These bounds are slightly smaller than the actual bridge bounds, allowing // the RTA speedrunning method of lakitu skip + #ifndef QOL_FIXES if (gMarioObject->oPosX > -544.0f && gMarioObject->oPosX < 545.0f && gMarioObject->oPosY > 800.0f + #else + // not anymore :) + if (gMarioObject->oPosX > -555.0f && gMarioObject->oPosX < 555.0f && gMarioObject->oPosY > 800.0f + #endif && gMarioObject->oPosZ > -2000.0f && gMarioObject->oPosZ < -177.0f - && gMarioObject->oPosZ < -177.0f) // always double check your conditions - { + #ifndef QOL_FIXES + && gMarioObject->oPosZ < -177.0f // always double check your conditions + #endif + ) { if (set_mario_npc_dialog(2) == 1) { o->oAction = CAMERA_LAKITU_INTRO_ACT_SPAWN_CLOUD; } @@ -61,8 +68,13 @@ static void camera_lakitu_intro_act_spawn_cloud(void) { * Circle down to mario, show the dialog, then fly away. */ static void camera_lakitu_intro_act_show_dialog(void) { + #ifndef TARGET_WEB s16 targetMovePitch; s16 targetMoveYaw; + #else + s16 targetMovePitch = 0; + s16 targetMoveYaw = 0; + #endif cur_obj_play_sound_1(SOUND_AIR_LAKITU_FLY); diff --git a/src/game/behaviors/castle_floor_trap.inc.c b/src/game/behaviors/castle_floor_trap.inc.c index 9eeddbb4c..7b066951c 100644 --- a/src/game/behaviors/castle_floor_trap.inc.c +++ b/src/game/behaviors/castle_floor_trap.inc.c @@ -26,7 +26,11 @@ void bhv_castle_floor_trap_open_detect(void) { void bhv_castle_floor_trap_open(void) { if (o->oTimer == 0) + #ifndef QOL_FIXES cur_obj_play_sound_2(SOUND_GENERAL_CASTLE_TRAP_OPEN); + #else + create_sound_spawner(SOUND_GENERAL_CASTLE_TRAP_OPEN); + #endif o->oAngleVelRoll -= 0x100; o->oFaceAngleRoll += o->oAngleVelRoll; if (o->oFaceAngleRoll < -0x4000) { diff --git a/src/game/behaviors/chuckya.inc.c b/src/game/behaviors/chuckya.inc.c index 99a1b5f1d..864c0ed03 100644 --- a/src/game/behaviors/chuckya.inc.c +++ b/src/game/behaviors/chuckya.inc.c @@ -71,7 +71,14 @@ s32 approach_forward_vel(f32 *arr, f32 spC, f32 sp10) { } void chuckya_act_0(void) { + #ifndef QOL_FIXES s32 sp3C; + #else + s32 sp3C = 0; + #endif + #ifdef TARGET_WEB + sp3C = 0; + #endif UNUSED u8 pad[16]; s32 sp28; if (o->oTimer == 0) diff --git a/src/game/behaviors/controllable_platform.inc.c b/src/game/behaviors/controllable_platform.inc.c index 7634c3ad4..d19b3eba9 100644 --- a/src/game/behaviors/controllable_platform.inc.c +++ b/src/game/behaviors/controllable_platform.inc.c @@ -29,6 +29,9 @@ void bhv_controllable_platform_sub_loop(void) { if (gMarioObject->platform == o) { D_80331694 = o->oBehParams2ndByte; +#if BUGFIX_HMC_VISIBLE_CONTROL_PLATFORM + o->parentObj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; +#endif o->oAction = 1; cur_obj_play_sound_2(SOUND_GENERAL_MOVING_PLATFORM_SWITCH); } diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c index d169ecf78..fd6325667 100644 --- a/src/game/behaviors/fish.inc.c +++ b/src/game/behaviors/fish.inc.c @@ -12,27 +12,31 @@ void fish_act_spawn(void) { s32 i; s32 schoolQuantity; s16 model; + #ifndef NODRAWINGDISTANCE f32 minDistToMario; + #else + UNUSED f32 minDistToMario; + #endif const struct Animation * const*fishAnimation; struct Object *fishObject; switch (o->oBehParams2ndByte) { - // Blue fish with a quanitiy of twenty. + // Blue fish with a quantity of twenty. case 0: model = MODEL_FISH; schoolQuantity = 20; minDistToMario = 1500.0f; fishAnimation = blue_fish_seg3_anims_0301C2B0; break; - // Blue fish with a quanitiy of five. + // Blue fish with a quantity of five. case 1: model = MODEL_FISH; schoolQuantity = 5; minDistToMario = 1500.0f; fishAnimation = blue_fish_seg3_anims_0301C2B0; break; - // Cyan fish with a quanitiy of twenty. + // Cyan fish with a quantity of twenty. case 2: model = MODEL_CYAN_FISH; schoolQuantity = 20; minDistToMario = 1500.0f; fishAnimation = cyan_fish_seg6_anims_0600E264; break; - // Cyan fish with a quanitiy of five. + // Cyan fish with a quantity of five. case 3: model = MODEL_CYAN_FISH; schoolQuantity = 5; minDistToMario = 1500.0f; fishAnimation = cyan_fish_seg6_anims_0600E264; break; diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index 7942b2bb8..6b8d93fe5 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -35,7 +35,11 @@ void king_bobomb_act_0(void) { o->oSubAction++; func_8031FFB4(SEQ_PLAYER_LEVEL, 60, 40); } + #ifndef QOL_FIXES } else if (cur_obj_update_dialog_with_cutscene(2, 1, CUTSCENE_DIALOG, DIALOG_017)) { + #else + } else if (cur_obj_update_dialog_with_cutscene(1, 1, CUTSCENE_DIALOG, DIALOG_017)) { + #endif o->oAction = 2; o->oFlags |= OBJ_FLAG_HOLDABLE; } @@ -151,7 +155,9 @@ void king_bobomb_act_6(void) { o->oKingBobombUnk104++; if (o->oKingBobombUnk104 > 3) { o->oSubAction++; + #ifndef QOL_FIXES ; // Needed to match + #endif } } else { if (o->oSubAction == 1) { @@ -170,7 +176,11 @@ void king_bobomb_act_6(void) { void king_bobomb_act_7(void) { cur_obj_init_animation_with_sound(2); + #ifndef QOL_FIXES if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_116)) { + #else + if (cur_obj_update_dialog_with_cutscene(1, 2, CUTSCENE_DIALOG, DIALOG_116)) { + #endif create_sound_spawner(SOUND_OBJ_KING_WHOMP_DEATH); cur_obj_hide(); cur_obj_become_intangible(); @@ -325,4 +335,8 @@ void bhv_king_bobomb_loop(void) { break; } o->oInteractStatus = 0; + +#ifdef QOL_FIXES + curr_obj_random_blink(&o->oKingBobombBlinkTimer); +#endif } diff --git a/src/game/behaviors/klepto.inc.c b/src/game/behaviors/klepto.inc.c index 22ab3e8fb..a43941663 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -75,7 +75,15 @@ static void klepto_anim_dive(void) { void bhv_klepto_init(void) { if (o->oBehParams2ndByte != 0) { +#ifdef QOL_FIXES + if (save_file_get_star_flags(gCurrSaveFileNum - 1, COURSE_SSL) & 1) { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_BLUE_STAR; + } else { + o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_STAR; + } +#else o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_STAR; +#endif } else { o->oKleptoStartPosX = o->oPosX; o->oKleptoStartPosY = o->oPosY; @@ -362,7 +370,11 @@ void bhv_klepto_update(void) { if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_CAP) { save_file_clear_flags(SAVE_FLAG_CAP_ON_KLEPTO); spawn_object(o, MODEL_MARIOS_CAP, bhvNormalCap); - } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR) { + } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR + #ifdef QOL_FIXES + || o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_BLUE_STAR + #endif + ) { spawn_default_star(-5550.0f, 300.0f, -930.0f); } diff --git a/src/game/behaviors/manta_ray.inc.c b/src/game/behaviors/manta_ray.inc.c index 35e5e2e69..e153b3bd5 100644 --- a/src/game/behaviors/manta_ray.inc.c +++ b/src/game/behaviors/manta_ray.inc.c @@ -34,7 +34,14 @@ void bhv_manta_ray_init(void) { void manta_ray_move(void) { s16 sp1E; + #ifndef QOL_FIXES s32 sp18; + #else + s32 sp18 = 0; + #endif + #ifdef TARGET_WEB + sp18 = 0; + #endif sp1E = o->header.gfx.unk38.animFrame; gCurrentObject->oPathedStartWaypoint = (struct Waypoint *) sMantaRayTraj; diff --git a/src/game/behaviors/mips.inc.c b/src/game/behaviors/mips.inc.c index a24cecd13..59578d8ff 100644 --- a/src/game/behaviors/mips.inc.c +++ b/src/game/behaviors/mips.inc.c @@ -110,7 +110,14 @@ void bhv_mips_act_wait_for_nearby_mario(void) { */ void bhv_mips_act_follow_path(void) { s16 collisionFlags = 0; + #ifndef QOL_FIXES s32 followStatus; + #else + s32 followStatus = 0; + #endif + #ifdef TARGET_WEB + followStatus = 0; + #endif struct Waypoint **pathBase; struct Waypoint *waypoint; diff --git a/src/game/behaviors/monty_mole.inc.c b/src/game/behaviors/monty_mole.inc.c index 685f5aae6..39e36dd78 100644 --- a/src/game/behaviors/monty_mole.inc.c +++ b/src/game/behaviors/monty_mole.inc.c @@ -1,3 +1,7 @@ +#ifdef QOL_FIXES +#include +#include +#endif /** * Behavior for bhvMontyMole, bhvMontyMoleHole, and bhvMontyMoleRock. @@ -377,7 +381,11 @@ void bhv_monty_mole_update(void) { //! The two farthest holes on the bottom level of TTM are more than // 1500 units away from each other, so the counter resets if you // attack moles in these holes consecutively. + #ifndef QOL_FIXES if (distToLastKill < 1500.0f) { + #else + if (distToLastKill <= FLT_MAX) { + #endif if (sMontyMoleKillStreak == 7) { play_puzzle_jingle(); spawn_object(o, MODEL_1UP, bhv1upWalking); @@ -388,7 +396,15 @@ void bhv_monty_mole_update(void) { } //! No overflow check + #ifndef QOL_FIXES sMontyMoleKillStreak += 1; + #else + if (sMontyMoleKillStreak > INT_MAX) { + sMontyMoleKillStreak = INT_MAX; + } else { + sMontyMoleKillStreak += 1; + } + #endif sMontyMoleLastKilledPosX = o->oPosX; sMontyMoleLastKilledPosY = o->oPosY; diff --git a/src/game/behaviors/pokey.inc.c b/src/game/behaviors/pokey.inc.c index cfcc92c26..3267f0e63 100644 --- a/src/game/behaviors/pokey.inc.c +++ b/src/game/behaviors/pokey.inc.c @@ -75,8 +75,13 @@ void bhv_pokey_body_part_update(void) { //! If you kill a body part as it's expanding, the body part that // was above it will instantly shrink and begin expanding in its // place. + #ifndef QOL_FIXES else if (o->parentObj->oPokeyBottomBodyPartSize < 1.0f && o->oBehParams2ndByte + 1 == o->parentObj->oPokeyNumAliveBodyParts) { + #else + if (o->parentObj->oPokeyBottomBodyPartSize < 1.0f + && o->oBehParams2ndByte + 1 == o->parentObj->oPokeyNumAliveBodyParts) { + #endif approach_f32_ptr(&o->parentObj->oPokeyBottomBodyPartSize, 1.0f, 0.1f); cur_obj_scale(o->parentObj->oPokeyBottomBodyPartSize * 3.0f); } diff --git a/src/game/behaviors/pyramid_top.inc.c b/src/game/behaviors/pyramid_top.inc.c index 824d24f2b..df78c0bc3 100644 --- a/src/game/behaviors/pyramid_top.inc.c +++ b/src/game/behaviors/pyramid_top.inc.c @@ -53,6 +53,9 @@ void bhv_pyramid_top_spinning(void) { // with a random velocity and angle. if (o->oTimer < 90) { pyramidFragment = spawn_object(o, MODEL_DIRT_ANIMATION, bhvPyramidTopFragment); +#ifdef QOL_FIXES + pyramidFragment->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; +#endif pyramidFragment->oForwardVel = random_float() * 10.0f + 20.0f; pyramidFragment->oMoveAngleYaw = random_u16(); pyramidFragment->oPyramidTopFragmentsScale = 0.8f; @@ -72,6 +75,9 @@ void bhv_pyramid_top_explode(void) { struct Object *pyramidFragment; s16 i; +#ifdef QOL_FIXES + if (o->oTimer == 0) { +#endif spawn_mist_particles_variable(0, 0, 690); // Generate 30 pyramid fragments with random properties. @@ -79,6 +85,9 @@ void bhv_pyramid_top_explode(void) { pyramidFragment = spawn_object( o, MODEL_DIRT_ANIMATION, bhvPyramidTopFragment ); +#ifdef QOL_FIXES + pyramidFragment->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; +#endif pyramidFragment->oForwardVel = random_float() * 50 + 80; pyramidFragment->oVelY = random_float() * 80 + 20; pyramidFragment->oMoveAngleYaw = random_u16(); @@ -86,8 +95,18 @@ void bhv_pyramid_top_explode(void) { pyramidFragment->oGravity = random_float() * 2 + 5; } +#ifdef QOL_FIXES + cur_obj_disable(); + } + + if (o->oTimer == 30) { + disable_time_stop_including_mario(); +#endif // Deactivate the pyramid top. o->activeFlags = ACTIVE_FLAG_DEACTIVATED; +#ifdef QOL_FIXES + } +#endif } void bhv_pyramid_top_loop(void) { @@ -95,6 +114,10 @@ void bhv_pyramid_top_loop(void) { case PYRAMID_TOP_ACT_CHECK_IF_SOLVED: if (o->oPyramidTopPillarsTouched == 4) { play_puzzle_jingle(); + #ifdef QOL_FIXES + cutscene_object(CUTSCENE_SSL_PYRAMID_EXPLODE, o); + enable_time_stop_including_mario(); + #endif o->oAction = PYRAMID_TOP_ACT_SPINNING; } break; diff --git a/src/game/behaviors/seaweed.inc.c b/src/game/behaviors/seaweed.inc.c index d1dc2b469..f7d992b90 100644 --- a/src/game/behaviors/seaweed.inc.c +++ b/src/game/behaviors/seaweed.inc.c @@ -15,6 +15,9 @@ void bhv_seaweed_bundle_init(void) { seaweed->header.gfx.scale[1] = 1.0; seaweed->header.gfx.scale[2] = 1.0; //! gfx.animFrame uninitialized + #ifdef QOL_FIXES + seaweed->header.gfx.unk38.animFrame = random_float() * 80.0f; + #endif seaweed = spawn_object(o, MODEL_SEAWEED, bhvSeaweed); seaweed->oFaceAngleYaw = 41800; diff --git a/src/game/behaviors/snowman.inc.c b/src/game/behaviors/snowman.inc.c index 174123d18..bde25a8c4 100644 --- a/src/game/behaviors/snowman.inc.c +++ b/src/game/behaviors/snowman.inc.c @@ -52,7 +52,14 @@ void adjust_rolling_face_pitch(f32 f12) { void snowmans_bottom_act_1(void) { UNUSED s16 sp26; + #ifndef QOL_FIXES s32 sp20; + #else + s32 sp20 = 0; + #endif + #ifdef TARGET_WEB + sp20 = 0; + #endif UNUSED s16 sp1E; o->oPathedStartWaypoint = segmented_to_virtual(&ccm_seg7_trajectory_snowman); diff --git a/src/game/behaviors/spawn_star.inc.c b/src/game/behaviors/spawn_star.inc.c index 9a194a5ca..fe8592ce8 100644 --- a/src/game/behaviors/spawn_star.inc.c +++ b/src/game/behaviors/spawn_star.inc.c @@ -122,19 +122,40 @@ struct Object *spawn_star(struct Object *sp30, f32 sp34, f32 sp38, f32 sp3C) { } void spawn_default_star(f32 sp20, f32 sp24, f32 sp28) { + #ifndef QOL_FIXES struct Object *sp1C; + #else + struct Object *sp1C = NULL; + #endif + #ifdef TARGET_WEB + sp1C = NULL; + #endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 0; } void spawn_red_coin_cutscene_star(f32 sp20, f32 sp24, f32 sp28) { + #ifndef QOL_FIXES struct Object *sp1C; + #else + struct Object *sp1C = NULL; + #endif + #ifdef TARGET_WEB + sp1C = NULL; + #endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 1; } void spawn_no_exit_star(f32 sp20, f32 sp24, f32 sp28) { + #ifndef QOL_FIXES struct Object *sp1C; + #else + struct Object *sp1C = NULL; + #endif + #ifdef TARGET_WEB + sp1C = NULL; + #endif sp1C = spawn_star(sp1C, sp20, sp24, sp28); sp1C->oBehParams2ndByte = 1; sp1C->oInteractionSubtype |= INT_SUBTYPE_NO_EXIT; diff --git a/src/game/behaviors/tilting_inverted_pyramid.inc.c b/src/game/behaviors/tilting_inverted_pyramid.inc.c index ebce64fc9..fd95c9723 100644 --- a/src/game/behaviors/tilting_inverted_pyramid.inc.c +++ b/src/game/behaviors/tilting_inverted_pyramid.inc.c @@ -90,7 +90,11 @@ void bhv_tilting_inverted_pyramid_loop(void) { linear_mtxf_mul_vec3f(*transform, posBeforeRotation, dist); dx = gMarioObject->oPosX - o->oPosX; + #ifndef QOL_FIXES dy = 500.0f; + #else + dy = gMarioObject->oPosY - o->oPosY; + #endif dz = gMarioObject->oPosZ - o->oPosZ; d = sqrtf(dx * dx + dy * dy + dz * dz); diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 1dae58501..8cecb8421 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -66,6 +66,9 @@ void tuxies_mother_act_1(void) { break; case 1: if (o->prevObj->oHeldState == HELD_FREE) { +#ifdef QOL_FIXES + o->prevObj->oInteractionSubtype &= ~INT_SUBTYPE_DROP_IMMEDIATELY; +#else //! This line is was almost certainly supposed to be something // like o->prevObj->oInteractionSubtype &= ~INT_SUBTYPE_DROP_IMMEDIATELY; // however, this code uses the value of o->oInteractionSubtype @@ -75,6 +78,7 @@ void tuxies_mother_act_1(void) { // which has no effect as o->prevObj->oUnknownUnk88 is always 0 // or 1, which is not affected by the bitwise AND. o->prevObj->OBJECT_FIELD_S32(o->oInteractionSubtype) &= ~INT_SUBTYPE_DROP_IMMEDIATELY; +#endif obj_set_behavior(o->prevObj, bhvUnused20E0); #ifndef VERSION_JP cur_obj_spawn_star_at_y_offset(3167.0f, -4300.0f, 5108.0f, 200.0f); @@ -86,8 +90,12 @@ void tuxies_mother_act_1(void) { break; case 2: if (o->prevObj->oHeldState == HELD_FREE) { +#ifdef QOL_FIXES + o->prevObj->oInteractionSubtype &= ~INT_SUBTYPE_DROP_IMMEDIATELY; +#else //! Same bug as above o->prevObj->OBJECT_FIELD_S32(o->oInteractionSubtype) &= ~INT_SUBTYPE_DROP_IMMEDIATELY; +#endif obj_set_behavior(o->prevObj, bhvPenguinBaby); o->oAction = 2; } @@ -291,12 +299,29 @@ Gfx *geo_switch_tuxie_mother_eyes(s32 run, struct GraphNode *node, UNUSED Mat4 * if (run == TRUE) { obj = (struct Object *) gCurGraphNodeObject; switchCase = (struct GraphNodeSwitchCase *) node; + #ifdef QOL_FIXES + int babyDelivered = obj->oAction == 2; + if (obj->behavior == segmented_to_virtual(bhvTuxiesMother)) { + switchCase->selectedCase = babyDelivered ? 0 : 4; + } else { + switchCase->selectedCase = 0; + } + #else switchCase->selectedCase = 0; + #endif // timer logic for blinking. uses cases 0-2. timer = gGlobalTimer % 50; if (timer < 43) + #ifdef QOL_FIXES + if (obj->behavior == segmented_to_virtual(bhvTuxiesMother)) { + switchCase->selectedCase = babyDelivered ? 0 : 4; + } else { + switchCase->selectedCase = 0; + } + #else switchCase->selectedCase = 0; + #endif else if (timer < 45) switchCase->selectedCase = 1; else if (timer < 47) diff --git a/src/game/behaviors/ukiki.inc.c b/src/game/behaviors/ukiki.inc.c index e7598253b..82417194e 100644 --- a/src/game/behaviors/ukiki.inc.c +++ b/src/game/behaviors/ukiki.inc.c @@ -501,7 +501,11 @@ void ukiki_free_loop(void) { * * Possibly unused so AnimState could be used for wearing a hat? */ +#ifndef TARGET_WEB static void ukiki_blink_timer(void) { +#else +UNUSED static void ukiki_blink_timer(void) { +#endif if (gGlobalTimer % 50 < 7) { o->oAnimState = UKIKI_ANIM_STATE_EYE_CLOSED; } else { diff --git a/src/game/behaviors/unused_poundable_platform.inc.c b/src/game/behaviors/unused_poundable_platform.inc.c index 238169055..e760ab56a 100644 --- a/src/game/behaviors/unused_poundable_platform.inc.c +++ b/src/game/behaviors/unused_poundable_platform.inc.c @@ -19,6 +19,9 @@ void bhv_unused_poundable_platform(void) { if (cur_obj_is_mario_ground_pounding_platform()) { spawn_mist_particles(); spawn_triangle_break_particles(20, 56, 3.0f, 0); +#ifdef QOL_FIXES + create_sound_spawner(SOUND_GENERAL_BREAK_BOX); +#endif o->oAction++; } } else if (o->oTimer > 7) { diff --git a/src/game/behaviors/water_ring.inc.c b/src/game/behaviors/water_ring.inc.c index 5fa6efb85..45dcd0ad3 100644 --- a/src/game/behaviors/water_ring.inc.c +++ b/src/game/behaviors/water_ring.inc.c @@ -21,17 +21,16 @@ void water_ring_init(void) { // This cause the ring's orientation for the purposes of collision to be // different than the graphical orientation, which means that Mario won't // necessarily collect a ring even if he appears to swim through it. +#ifdef QOL_FIXES + o->oWaterRingNormalX = sins(o->oFaceAngleYaw) * sins(o->oFaceAngleRoll); + o->oWaterRingNormalY = coss(o->oFaceAnglePitch) * coss(o->oFaceAngleRoll); + o->oWaterRingNormalZ = coss(o->oFaceAngleYaw) * sins(o->oFaceAnglePitch); +#else o->oWaterRingNormalX = coss(o->oFaceAnglePitch) * sins(o->oFaceAngleRoll) * -1.0f; o->oWaterRingNormalY = coss(o->oFaceAnglePitch) * coss(o->oFaceAngleRoll); o->oWaterRingNormalZ = sins(o->oFaceAnglePitch); - +#endif o->oWaterRingMarioDistInFront = water_ring_calc_mario_dist(); - - // Adding this code will alter the ring's graphical orientation to align with the faulty - // collision orientation: - // - // o->oFaceAngleYaw = 0; - // o->oFaceAngleRoll *= -1; } void bhv_jet_stream_water_ring_init(void) { @@ -162,8 +161,13 @@ void water_ring_spawner_act_inactive(void) { // come around again. if (o->oTimer == 300) o->oTimer = 0; + #ifndef QOL_FIXES if ((o->oTimer == 0) || (o->oTimer == 50) || (o->oTimer == 150) || (o->oTimer == 200) || (o->oTimer == 250)) { + #else + // This makes it much easier to collect this star + if (o->oTimer % 50 == 0) { + #endif waterRing = spawn_object(o, MODEL_WATER_RING, bhvJetStreamWaterRing); waterRing->oWaterRingIndex = currentObj->oWaterRingMgrNextRingIndex; currentObj->oWaterRingMgrNextRingIndex++; diff --git a/src/game/behaviors/whomp.inc.c b/src/game/behaviors/whomp.inc.c index 1f3bcb7f0..d3d8442f7 100644 --- a/src/game/behaviors/whomp.inc.c +++ b/src/game/behaviors/whomp.inc.c @@ -209,7 +209,11 @@ void whomp_act_6(void) { void whomp_act_8(void) { if (o->oBehParams2ndByte != 0) { + #ifndef QOL_FIXES if (cur_obj_update_dialog_with_cutscene(2, 2, CUTSCENE_DIALOG, DIALOG_115)) { + #else + if (cur_obj_update_dialog_with_cutscene(3, 2, CUTSCENE_DIALOG, DIALOG_115)) { + #endif obj_set_angle(o, 0, 0, 0); cur_obj_hide(); cur_obj_become_intangible(); diff --git a/src/game/behaviors/wiggler.inc.c b/src/game/behaviors/wiggler.inc.c index 4c465f809..c2bbc0131 100644 --- a/src/game/behaviors/wiggler.inc.c +++ b/src/game/behaviors/wiggler.inc.c @@ -153,7 +153,7 @@ void wiggler_init_segments(void) { cur_obj_unhide(); } -#if defined(VERSION_EU) || defined(AVOID_UB) +#if BUGFIX_WIGGLER_HEALTH o->oHealth = 4; // This fixes Wiggler reading UB on his first frame of his acceleration, as his health is not set. #endif } diff --git a/src/game/bettercamera.inc.h b/src/game/bettercamera.inc.h index d73fdaf19..0e4c15b9b 100644 --- a/src/game/bettercamera.inc.h +++ b/src/game/bettercamera.inc.h @@ -256,9 +256,9 @@ static int ivrt(u8 axis) { return 1; } else { if (newcam_invertY == 0) - return 1; - else return -1; + else + return 1; } } diff --git a/src/game/camera.c b/src/game/camera.c index bde066264..e65244a1b 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -664,7 +664,11 @@ void unused_set_camera_pitch_shake_env(s16 shake) { */ f32 calc_y_to_curr_floor(f32 *posOff, f32 posMul, f32 posBound, f32 *focOff, f32 focMul, f32 focBound) { f32 floorHeight = sMarioGeometry.currFloorHeight; + #ifndef QOL_FIXES f32 waterHeight; + #else + f32 waterHeight = sMarioGeometry.waterHeight; + #endif UNUSED s32 filler; if (!(sMarioCamState->action & ACT_FLAG_METAL_WATER)) { @@ -700,6 +704,9 @@ f32 calc_y_to_curr_floor(f32 *posOff, f32 posMul, f32 posBound, f32 *focOff, f32 if (*focOff < -focBound) { *focOff = -focBound; } + #ifdef TARGET_WEB + return 0; + #endif } //Compiler gets mad if I put this any further above. thanks refresh 7 #ifdef BETTERCAMERA @@ -723,12 +730,21 @@ void focus_on_mario(Vec3f focus, Vec3f pos, f32 posYOff, f32 focYOff, f32 dist, static UNUSED void set_pos_to_mario(Vec3f foc, Vec3f pos, f32 yOff, f32 focYOff, f32 dist, s16 pitch, s16 yaw) { Vec3f marioPos; f32 posDist; + #ifndef QOL_FIXES f32 focDist; + #else + UNUSED f32 focDist; + #endif s16 posPitch; s16 posYaw; + #ifndef QOL_FIXES s16 focPitch; s16 focYaw; + #else + UNUSED s16 focPitch; + UNUSED s16 focYaw; + #endif vec3f_copy(marioPos, sMarioCamState->pos); marioPos[1] += yOff; @@ -736,9 +752,11 @@ static UNUSED void set_pos_to_mario(Vec3f foc, Vec3f pos, f32 yOff, f32 focYOff, vec3f_set_dist_and_angle(marioPos, pos, dist, pitch + sLakituPitch, yaw); vec3f_get_dist_and_angle(pos, sMarioCamState->pos, &posDist, &posPitch, &posYaw); + #ifndef QOL_FIXES //! Useless get and set vec3f_get_dist_and_angle(pos, foc, &focDist, &focPitch, &focYaw); vec3f_set_dist_and_angle(pos, foc, focDist, focPitch, focYaw); + #endif foc[1] = sMarioCamState->pos[1] + focYOff; } @@ -1608,10 +1626,15 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { pos[1] = 300.f - (nx * pos[0] + nz * pos[2] + oo) / ny; switch (gCurrLevelArea) { case AREA_BOB: + #ifndef QOL_FIXES pos[1] += 125.f; //! fall through, makes the BoB boss fight camera move up twice as high as it should + #endif case AREA_WF: pos[1] += 125.f; + #ifdef QOL_FIXES + break; + #endif } } @@ -1640,9 +1663,11 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { } //! Unnecessary conditional, focusDistance is already bounded to 800 + #ifndef QOL_FIXES if (focusDistance < 400.f) { focusDistance = 400.f; } + #endif // Set C-Down distance and pitch. // C-Down will essentially double the distance from the center. @@ -1708,9 +1733,16 @@ struct ParallelTrackingPoint sBBHLibraryParTrackPath[] = { }; s32 unused_update_mode_5_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { + #ifdef TARGET_WEB + return 0; + #endif } +#ifndef TARGET_WEB static void stub_camera_1(UNUSED s32 unused) { +#else +UNUSED static void stub_camera_1(UNUSED s32 unused) { +#endif } void mode_boss_fight_camera(struct Camera *c) { @@ -1781,10 +1813,12 @@ s32 update_behind_mario_camera(struct Camera *c, Vec3f focus, Vec3f pos) { // Focus on Mario vec3f_copy(focus, sMarioCamState->pos); c->focus[1] += focYOff; + #ifndef QOL_FIXES //! @bug unnecessary dist = calc_abs_dist(focus, pos); //! @bug unnecessary pitch = calculate_pitch(focus, pos); + #endif vec3f_get_dist_and_angle(focus, pos, &dist, &pitch, &yaw); if (dist > maxDist) { dist = maxDist; @@ -2033,6 +2067,9 @@ void mode_behind_mario_camera(struct Camera *c) { } s32 nop_update_water_camera(UNUSED struct Camera *c, UNUSED Vec3f focus, UNUSED Vec3f pos) { + #ifdef TARGET_WEB + return 0; + #endif } /** @@ -2101,7 +2138,11 @@ s16 update_default_camera(struct Camera *c) { if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { //! In Mario mode, the camera is zoomed out further than in Lakitu mode (1400 vs 1200) if (set_cam_angle(0) == CAM_ANGLE_MARIO) { + #ifndef QOL_FIXES zoomDist = gCameraZoomDist + 1050; + #else + zoomDist = gCameraZoomDist + 850; + #endif } else { zoomDist = gCameraZoomDist + 400; } @@ -2195,12 +2236,16 @@ s16 update_default_camera(struct Camera *c) { unusedFreeRoamWallYaw = avoidYaw; sAvoidYawVel = yaw; sStatusFlags |= CAM_FLAG_COLLIDED_WITH_WALL; + #ifndef QOL_FIXES //! Does nothing vec3f_get_dist_and_angle(sMarioCamState->pos, cPos, &xzDist, &tempPitch, &tempYaw); + #endif // Rotate to avoid the wall approach_s16_asymptotic_bool(&yaw, avoidYaw, 10); + #ifndef QOL_FIXES //! Does nothing vec3f_set_dist_and_angle(sMarioCamState->pos, cPos, xzDist, tempPitch, tempYaw); + #endif sAvoidYawVel = (sAvoidYawVel - yaw) / 0x100; } else { if (gMarioStates[0].forwardVel == 0.f) { @@ -2455,8 +2500,10 @@ s32 update_spiral_stairs_camera(struct Camera *c, Vec3f focus, Vec3f pos) { } focYaw += sSpiralStairsYawOffset; posYaw = focYaw; + #ifndef QOL_FIXES //! @bug unnecessary camera_approach_s16_symmetric_bool(&posYaw, focYaw, 0x1000); + #endif vec3f_set_dist_and_angle(sFixedModeBasePosition, cPos, 300.f, 0, posYaw); @@ -2921,20 +2968,28 @@ void update_lakitu(struct Camera *c) { s16 newYaw; UNUSED u8 unused1[8]; + #ifndef QOL_FIXES if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) { } else { + #else + if (!(gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN)) { + #endif + #ifndef QOL_FIXES if (c->cutscene) { } if (TRUE) { + #endif newYaw = next_lakitu_state(newPos, newFoc, c->pos, c->focus, sOldPosition, sOldFocus, c->nextYaw); set_or_approach_s16_symmetric(&c->yaw, newYaw, sYawSpeed); sStatusFlags &= ~CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; + #ifndef QOL_FIXES } else { //! dead code, moved to next_lakitu_state() vec3f_copy(newPos, c->pos); vec3f_copy(newFoc, c->focus); } + #endif // Update old state vec3f_copy(sOldPosition, newPos); @@ -3170,6 +3225,9 @@ void update_camera(struct Camera *c) { case CAMERA_MODE_FREE_ROAM: mode_lakitu_camera(c); break; + #ifdef QOL_FIXES + + #endif case CAMERA_MODE_BOSS_FIGHT: mode_boss_fight_camera(c); break; @@ -3335,7 +3393,11 @@ void init_camera(struct Camera *c) { gLakituState.posHSpeed = 0.3f; gLakituState.posVSpeed = 0.3f; gLakituState.focHSpeed = 0.8f; + #ifndef QOL_FIXES gLakituState.focHSpeed = 0.3f; // @bug set focHSpeed back-to-back + #else + gLakituState.focVSpeed = 0.3f; + #endif gLakituState.roll = 0; gLakituState.keyDanceRoll = 0; gLakituState.unused = 0; @@ -4820,12 +4882,20 @@ s32 offset_yaw_outward_radial(struct Camera *c, s16 areaYaw) { // When the final yaw is out of [-60,60] degrees, approach yawGoal faster than dYaw will ever be, // making the camera lock in one direction until yawGoal drops below 60 (or Mario presses a C button) if (yaw < -DEGREES(60)) { + #ifndef QOL_FIXES //! Maybe they meant to reverse yawGoal's sign? camera_approach_s16_symmetric_bool(&yaw, -yawGoal, 0x200); + #else + camera_approach_s16_symmetric_bool(&yaw, yawGoal, 0x200); + #endif } if (yaw > DEGREES(60)) { + #ifndef QOL_FIXES //! Maybe they meant to reverse yawGoal's sign? camera_approach_s16_symmetric_bool(&yaw, yawGoal, 0x200); + #else + camera_approach_s16_symmetric_bool(&yaw, -yawGoal, 0x200); + #endif } return yaw; } @@ -4897,7 +4967,14 @@ void play_sound_if_cam_switched_to_lakitu_or_mario(void) { * Handles input for radial, outwards radial, parallel tracking, and 8 direction mode. */ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + #ifndef QOL_FIXES s16 dummy; + #else + s16 dummy = 0; + #endif + #ifdef TARGET_WEB + dummy = 0; + #endif if ((gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) || !(gCameraMovementFlags & CAM_MOVE_ROTATE)) { @@ -5172,8 +5249,12 @@ u8 get_cutscene_from_mario_status(struct Camera *c) { //! doorStatus is never DOOR_ENTER_LOBBY when cameraEvent == 6, because //! doorStatus is only used for the star door in the lobby, which uses //! ACT_ENTERING_STAR_DOOR + #ifndef QOL_FIXES if (c->mode == CAMERA_MODE_SPIRAL_STAIRS || c->mode == CAMERA_MODE_CLOSE || c->doorStatus == DOOR_ENTER_LOBBY) { + #else + if (c->mode == CAMERA_MODE_SPIRAL_STAIRS || c->mode == CAMERA_MODE_CLOSE) { + #endif cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL_MODE, CUTSCENE_DOOR_PUSH_MODE); } else { cutscene = open_door_cutscene(CUTSCENE_DOOR_PULL, CUTSCENE_DOOR_PUSH); @@ -5365,7 +5446,11 @@ void set_focus_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack * @param forwBack offset to Mario's front/back, relative to his faceAngle * @param yawOff offset to Mario's faceAngle, changes the direction of `leftRight` and `forwBack` */ +#ifndef TARGET_WEB static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { +#else +UNUSED static void unused_set_pos_rel_mario(struct Camera *c, f32 leftRight, f32 yOff, f32 forwBack, s16 yawOff) { +#endif u16 yaw = sMarioCamState->faceAngle[1] + yawOff; c->pos[0] = sMarioCamState->pos[0] + forwBack * sins(yaw) + leftRight * coss(yaw); @@ -5414,7 +5499,11 @@ void determine_pushing_or_pulling_door(s16 *rotation) { if (sMarioCamState->action == ACT_PULLING_DOOR) { *rotation = 0; } else { + #ifndef TARGET_WEB *rotation = DEGREES(180); + #else + *rotation = (s16)DEGREES(180); + #endif } } @@ -6310,8 +6399,10 @@ struct CameraTrigger sCamCastle[] = { { 1, cam_castle_close_mode, -2304, -264, -4072, 140, 150, 140, 0 }, { 1, cam_castle_close_mode, -2304, 145, -1344, 140, 150, 140, 0 }, { 1, cam_castle_enter_lobby, -2304, 145, -802, 140, 150, 140, 0 }, + #ifndef QOL_FIXES //! Sets the camera mode when leaving secret aquarium { 1, cam_castle_close_mode, 2816, 1200, -256, 100, 100, 100, 0 }, + #endif { 1, cam_castle_close_mode, 256, -161, -4226, 140, 150, 140, 0 }, { 1, cam_castle_close_mode, 256, 145, -1344, 140, 150, 140, 0 }, { 1, cam_castle_enter_lobby, 256, 145, -802, 140, 150, 140, 0 }, @@ -6333,8 +6424,10 @@ struct CameraTrigger sCamCastle[] = { { 1, cam_castle_close_mode, -3393, 350, -793, 140, 150, 140, 0x4000 }, { 1, cam_castle_enter_lobby, -2851, 350, -792, 140, 150, 140, 0x4000 }, { 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 }, + #ifndef QOL_FIXES //! Duplicate camera trigger outside JRB door { 1, cam_castle_enter_lobby, 803, 350, -228, 140, 150, 140, -0x4000 }, + #endif { 1, cam_castle_close_mode, 1345, 350, -229, 140, 150, 140, 0x4000 }, { 1, cam_castle_close_mode, -946, -929, 622, 300, 150, 300, 0 }, { 2, cam_castle_look_upstairs, -205, 1456, 2508, 210, 928, 718, 0 }, @@ -6591,11 +6684,17 @@ s16 camera_course_processing(struct Camera *c) { sCameraTriggers[level][b].boundsZ); // Check if Mario is inside the bounds + #ifndef QOL_FIXES if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, - sCameraTriggers[level][b].boundsYaw) == TRUE) { + sCameraTriggers[level][b].boundsYaw) == TRUE) { //! This should be checked before calling is_pos_in_bounds. (It doesn't belong //! outside the while loop because some events disable area processing) if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { + #else + if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { + if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, + sCameraTriggers[level][b].boundsYaw) == TRUE) { + #endif sCameraTriggers[level][b].event(c); insideBounds = TRUE; } @@ -6705,8 +6804,12 @@ s16 camera_course_processing(struct Camera *c) { break; case AREA_DDD_WHIRLPOOL: + #ifndef QOL_FIXES //! @bug this does nothing gLakituState.defMode = CAMERA_MODE_OUTWARD_RADIAL; + #else + c->defMode = CAMERA_MODE_OUTWARD_RADIAL; + #endif break; case AREA_DDD_SUB: @@ -6722,8 +6825,12 @@ s16 camera_course_processing(struct Camera *c) { } } } + #ifndef QOL_FIXES //! @bug this does nothing gLakituState.defMode = CAMERA_MODE_FREE_ROAM; + #else + c->defMode = CAMERA_MODE_FREE_ROAM; + #endif break; } } @@ -6826,7 +6933,11 @@ s32 rotate_camera_around_walls(struct Camera *c, Vec3f cPos, s16 *avoidYaw, s16 colData.z = sMarioCamState->pos[2] + ((cPos[2] - sMarioCamState->pos[2]) * checkDist); colData.radius = coarseRadius; // Increase the coarse check radius + #ifndef QOL_FIXES camera_approach_f32_symmetric_bool(&coarseRadius, 250.f, 30.f); + #else + camera_approach_f32_symmetric_bool(&coarseRadius, 200.f, 30.f); + #endif if (find_wall_collisions(&colData) != 0) { wall = colData.walls[colData.numWalls - 1]; @@ -7035,7 +7146,11 @@ void copy_spline_segment(struct CutsceneSplinePoint dst[], struct CutsceneSpline init_spline_point(&dst[i], src[j].index, src[j].speed, src[j].point); i += 1; j += 1; + #ifndef QOL_FIXES } while ((src[j].index != -1) && (src[j].index != -1)); //! same comparison performed twice + #else + } while (src[j].index != -1); + #endif } while (j > 16); // Create the end of the spline by duplicating the last point @@ -7069,7 +7184,11 @@ static UNUSED void unused_cutscene_mario_dialog_looking_down(UNUSED struct Camer /** * Cause Mario to enter the normal dialog state. */ +#ifndef TARGET_WEB static BAD_RETURN(s32) cutscene_mario_dialog(UNUSED struct Camera *c) { +#else +UNUSED static BAD_RETURN(s32) cutscene_mario_dialog(UNUSED struct Camera *c) { +#endif gCutsceneTimer = cutscene_common_set_dialog_state(1); } @@ -7264,7 +7383,11 @@ void cutscene_unsoften_music(UNUSED struct Camera *c) { sequence_player_unlower(SEQ_PLAYER_LEVEL, 60); } +#ifndef TARGET_WEB static void stub_camera_5(UNUSED struct Camera *c) { +#else +UNUSED static void stub_camera_5(UNUSED struct Camera *c) { +#endif } BAD_RETURN(s32) cutscene_unused_start(UNUSED struct Camera *c) { @@ -7480,9 +7603,14 @@ BAD_RETURN(s32) cutscene_ending_kiss_here_we_go(struct Camera *c) { set_fov_function(CAM_FOV_DEFAULT); vec3f_set(foc, 233.f, 1068.f, -1298.f); vec3f_set(pos, -250.f, 966.f, -1111.f); + #ifndef QOL_FIXES //! another double typo approach_vec3f_asymptotic(c->pos, pos, 0.2, 0.1f, 0.2f); approach_vec3f_asymptotic(c->focus, foc, 0.2, 0.1f, 0.2f); + #else + approach_vec3f_asymptotic(c->pos, pos, 0.2f, 0.1f, 0.2f); + approach_vec3f_asymptotic(c->focus, foc, 0.2f, 0.1f, 0.2f); + #endif } /** @@ -7750,7 +7878,11 @@ BAD_RETURN(s32) cutscene_dance_rotate_move_towards_mario(struct Camera *c) { /** * Speculated to be dance-related due to its proximity to the other dance functions */ +#ifndef TARGET_WEB static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { +#else +UNUSED static BAD_RETURN(s32) cutscene_dance_unused(UNUSED struct Camera *c) { +#endif } /** @@ -8124,11 +8256,15 @@ BAD_RETURN(s32) cutscene_bowser_arena_set_pos(struct Camera *c) { * The y offset starts at 120, then decreases to 0 before reaching ~240 on the last frame. */ BAD_RETURN(s32) cutscene_bowser_arena_focus_sine(UNUSED struct Camera *c) { + #ifndef QOL_FIXES //! unused initialization f32 yOff = 150.0f; // cvar4 was zeroed when the cutscene started. yOff = sins(sCutsceneVars[4].angle[1]) * 120.0f + 120.0f; + #else + f32 yOff = sins(sCutsceneVars[4].angle[1]) * 120.0f + 120.0f; + #endif sCutsceneVars[4].angle[1] -= 0x200; approach_f32_asymptotic_bool(&sCutsceneVars[0].point[1], yOff, 0.5f); } @@ -8307,7 +8443,7 @@ BAD_RETURN(s32) cutscene_star_spawn(struct Camera *c) { sStatusFlags |= CAM_FLAG_SMOOTH_MOVEMENT; if (gObjCutsceneDone) { - // Set the timer to CUTSCENE_LOOP, which start the next shot. + // Set the timer to CUTSCENE_LOOP, which starts the next shot. gCutsceneTimer = CUTSCENE_LOOP; } } @@ -8451,7 +8587,7 @@ BAD_RETURN(s32) cutscene_red_coin_star(struct Camera *c) { cutscene_event(cutscene_red_coin_star_set_fov, c, 30, -1); if (gObjCutsceneDone) { - // Set the timer to CUTSCENE_LOOP, which start the next shot. + // Set the timer to CUTSCENE_LOOP, which starts the next shot. gCutsceneTimer = CUTSCENE_LOOP; } } @@ -8663,7 +8799,11 @@ BAD_RETURN(s32) cutscene_death_stomach_goto_mario(struct Camera *c) { /** * Ah, yes */ +#ifndef TARGET_WEB static void unused_water_death_move_to_side_of_mario(struct Camera *c) { +#else +UNUSED static void unused_water_death_move_to_side_of_mario(struct Camera *c) { +#endif water_death_move_to_mario_side(c); } @@ -8906,7 +9046,9 @@ BAD_RETURN(s32) cutscene_pyramid_top_explode(struct Camera *c) { * End the pyramid top explosion cutscene. */ BAD_RETURN(s32) cutscene_pyramid_top_explode_end(struct Camera *c) { + #ifndef QOL_FIXES cutscene_stop_dialog(c); + #endif stop_cutscene_and_retrieve_stored_info(c); // Move the camera back to Mario transition_next_state(c, 30); @@ -8937,7 +9079,11 @@ BAD_RETURN(s32) cutscene_enter_pyramid_top(struct Camera *c) { } } +#ifndef TARGET_WEB static void unused_cutscene_goto_cvar(struct Camera *c) { +#else +UNUSED static void unused_cutscene_goto_cvar(struct Camera *c) { +#endif f32 dist; dist = calc_abs_dist(sCutsceneVars[3].point, sMarioCamState->pos); @@ -9098,7 +9244,11 @@ BAD_RETURN(s32) cutscene_read_message_start(struct Camera *c) { sCutsceneVars[0].angle[0] = 0; } +#ifndef TARGET_WEB static void unused_cam_to_mario(struct Camera *c) { +#else +UNUSED static void unused_cam_to_mario(struct Camera *c) { +#endif Vec3s dir; vec3s_set(dir, 0, sMarioCamState->faceAngle[1], 0); @@ -9141,6 +9291,9 @@ BAD_RETURN(s32) cutscene_read_message(struct Camera *c) { sModeOffsetYaw = sCutsceneVars[1].angle[1]; cutscene_unsoften_music(c); } + #ifdef QOL_FIXES + break; + #endif } sStatusFlags |= CAM_FLAG_UNUSED_CUTSCENE_ACTIVE; } @@ -9232,11 +9385,16 @@ BAD_RETURN(s32) cutscene_exit_bowser_succ_focus_left(UNUSED struct Camera *c) { * Instead of focusing on the key, just start a pitch shake. Clever! * The shake lasts 32 frames. */ +#ifndef QOL_FIXES BAD_RETURN(s32) cutscene_exit_bowser_key_toss_shake(struct Camera *c) { //! Unnecessary check. if (c->cutscene == CUTSCENE_EXIT_BOWSER_SUCC) { set_camera_pitch_shake(0x800, 0x40, 0x800); } +#else +BAD_RETURN(s32) cutscene_exit_bowser_key_toss_shake(UNUSED struct Camera *c) { + set_camera_pitch_shake(0x800, 0x40, 0x800); +#endif } /** @@ -9568,15 +9726,24 @@ s32 intro_peach_move_camera_start_to_pipe(struct Camera *c, struct CutsceneSplin // The two splines used by this function are reflected in the horizontal plane for some reason, // so they are rotated every frame. Why do this, Nintendo? + #ifndef TARGET_WEB rotate_in_xz(c->focus, c->focus, DEGREES(180)); rotate_in_xz(c->pos, c->pos, DEGREES(180)); + #else + rotate_in_xz(c->focus, c->focus, (s16)DEGREES(180)); + rotate_in_xz(c->pos, c->pos, (s16)DEGREES(180)); + #endif vec3f_set(offset, -1328.f, 260.f, 4664.f); vec3f_add(c->focus, offset); vec3f_add(c->pos, offset); posReturn += focusReturn; // Unused + #ifndef QOL_FIXES return focusReturn; + #else + return posReturn; + #endif } /** @@ -10346,8 +10513,12 @@ BAD_RETURN(s32) cutscene_door_fix_cam(struct Camera *c) { * Loop until Mario is no longer using the door. */ BAD_RETURN(s32) cutscene_door_loop(struct Camera *c) { + #ifndef QOL_FIXES //! bitwise AND instead of boolean if ((sMarioCamState->action != ACT_PULLING_DOOR) & (sMarioCamState->action != ACT_PUSHING_DOOR)) { + #else + if ((sMarioCamState->action != ACT_PULLING_DOOR) && (sMarioCamState->action != ACT_PUSHING_DOOR)) { + #endif gCutsceneTimer = CUTSCENE_STOP; c->cutscene = 0; } @@ -10366,11 +10537,15 @@ BAD_RETURN(s32) cutscene_door_move_behind_mario(struct Camera *c) { vec3s_set(sCutsceneVars[0].angle, 0, sMarioCamState->faceAngle[1] + doorRotation, 0); vec3f_set(camOffset, 0.f, 125.f, 250.f); + #ifndef QOL_FIXES if (doorRotation == 0) { //! useless code camOffset[0] = 0.f; } else { camOffset[0] = 0.f; } + #else + camOffset[0] = 0.f; + #endif offset_rotated(c->pos, sMarioCamState->pos, camOffset, sCutsceneVars[0].angle); } @@ -10664,7 +10839,9 @@ struct Cutscene sCutsceneEnterPyramidTop[] = { * Unused cutscene for when the pyramid explodes. */ struct Cutscene sCutscenePyramidTopExplode[] = { + #ifndef QOL_FIXES { cutscene_mario_dialog, CUTSCENE_LOOP }, + #endif { cutscene_pyramid_top_explode, 150 }, { cutscene_pyramid_top_explode_end, 0 } }; @@ -11306,9 +11483,13 @@ void play_cutscene(struct Camera *c) { #undef CUTSCENE if ((cutsceneDuration != 0) && !(gCutsceneTimer & CUTSCENE_STOP)) { + #ifndef QOL_FIXES //! @bug This should check for 0x7FFF (CUTSCENE_LOOP) //! instead, cutscenes that last longer than 0x3FFF frames will never end on their own if (gCutsceneTimer < 0x3FFF) { + #else + if (gCutsceneTimer < CUTSCENE_LOOP) { + #endif gCutsceneTimer += 1; } //! Because gCutsceneTimer is often set to 0x7FFF (CUTSCENE_LOOP), this conditional can only @@ -11533,6 +11714,10 @@ Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context) approach_fov_60(marioState); break; //! No default case + #ifdef QOL_FIXES + default: + break; + #endif } } diff --git a/src/game/debug.c b/src/game/debug.c index 66d808ed2..dd914c1a8 100644 --- a/src/game/debug.c +++ b/src/game/debug.c @@ -180,10 +180,14 @@ void print_mapinfo(void) { print_debug_top_down_normal("mapinfo", 0); print_debug_top_down_mapinfo("area %x", area); print_debug_top_down_mapinfo("wx %d", gCurrentObject->oPosX); + #ifndef QOL_FIXES //! Fat finger: programmer hit tab instead of space. Japanese // thumb shift keyboards had the tab key next to the spacebar, // so this was likely the reason. print_debug_top_down_mapinfo("wy\t %d", gCurrentObject->oPosY); + #else + print_debug_top_down_mapinfo("wy %d", gCurrentObject->oPosY); + #endif print_debug_top_down_mapinfo("wz %d", gCurrentObject->oPosZ); print_debug_top_down_mapinfo("bgY %d", bgY); print_debug_top_down_mapinfo("angY %d", angY); @@ -206,32 +210,36 @@ void print_mapinfo(void) { UNUSED f32 bgY; UNUSED f32 water; UNUSED s32 area; - // s32 angY; - // - // angY = gCurrentObject->oMoveAngleYaw / 182.044000; - // area = ((s32)gCurrentObject->oPosX + 0x2000) / 1024 - // + ((s32)gCurrentObject->oPosZ + 0x2000) / 1024 * 16; - // + #ifndef VERSION_EU + s32 angY; + + angY = gCurrentObject->oMoveAngleYaw / 182.044000; + area = ((s32)gCurrentObject->oPosX + 0x2000) / 1024 + + ((s32)gCurrentObject->oPosZ + 0x2000) / 1024 * 16; + + #endif bgY = find_floor(gCurrentObject->oPosX, gCurrentObject->oPosY, gCurrentObject->oPosZ, &pfloor); water = find_water_level(gCurrentObject->oPosX, gCurrentObject->oPosZ); print_debug_top_down_normal("mapinfo", 0); - // print_debug_top_down_mapinfo("area %x", area); - // print_debug_top_down_mapinfo("wx %d", gCurrentObject->oPosX); - // print_debug_top_down_mapinfo("wy\t %d", gCurrentObject->oPosY); - // print_debug_top_down_mapinfo("wz %d", gCurrentObject->oPosZ); - // print_debug_top_down_mapinfo("bgY %d", bgY); - // print_debug_top_down_mapinfo("angY %d", angY); - // - // if(pfloor) // not null - //{ - // print_debug_top_down_mapinfo("bgcode %d", pfloor->type); - // print_debug_top_down_mapinfo("bgstatus %d", pfloor->flags); - // print_debug_top_down_mapinfo("bgarea %d", pfloor->room); - //} - // - // if(gCurrentObject->oPosY < water) - // print_debug_top_down_mapinfo("water %d", water); + #ifndef VERSION_EU + print_debug_top_down_mapinfo("area %x", area); + print_debug_top_down_mapinfo("wx %d", gCurrentObject->oPosX); + print_debug_top_down_mapinfo("wy\t %d", gCurrentObject->oPosY); + print_debug_top_down_mapinfo("wz %d", gCurrentObject->oPosZ); + print_debug_top_down_mapinfo("bgY %d", bgY); + print_debug_top_down_mapinfo("angY %d", angY); + + if(pfloor) // not null + { + print_debug_top_down_mapinfo("bgcode %d", pfloor->type); + print_debug_top_down_mapinfo("bgstatus %d", pfloor->flags); + print_debug_top_down_mapinfo("bgarea %d", pfloor->room); + } + + if(gCurrentObject->oPosY < water) + print_debug_top_down_mapinfo("water %d", water); + #endif } #endif @@ -337,7 +345,11 @@ void reset_debug_objectinfo(void) { * C Right) and then toggles the debug flags from FF to 2; 2 is unused, * despite so this has no effect, being called. (unused) */ +#ifndef TARGET_WEB static void check_debug_button_seq(void) { +#else +UNUSED static void check_debug_button_seq(void) { +#endif s16 *buttonArr; s16 cButtonMask; @@ -367,7 +379,11 @@ static void check_debug_button_seq(void) { * Poll the debug info flags and controller for appropriate presses that * control sDebugPage's range. (unused) */ +#ifndef TARGET_WEB static void try_change_debug_page(void) { +#else +UNUSED static void try_change_debug_page(void) { +#endif if (gDebugInfoFlags & DEBUG_INFO_FLAG_DPRINT) { if ((gPlayer1Controller->buttonPressed & L_JPAD) && (gPlayer1Controller->buttonDown & (L_TRIG | R_TRIG))) { diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c index 16a927209..223cf7c9e 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c @@ -52,7 +52,7 @@ s32 particle_is_laterally_close(s32 index, s32 x, s32 z, s32 distance) { } /** - * Generate a uniform random number in range [-2000, -1000[ or [1000, 2000[ + * Generate a uniform random number in range [-2000, -1000] or [1000, 2000] * Used to position flower particles */ s32 random_flower_offset(void) { @@ -348,16 +348,20 @@ s32 envfx_init_bubble(s32 mode) { bzero(gEnvFxBubbleConfig, sizeof(gEnvFxBubbleConfig)); if (mode == ENVFX_LAVA_BUBBLES) { + #ifndef QOL_FIXES //! Dead code if (0) { } + #endif for (i = 0; i < sBubbleParticleCount; i++) { (gEnvFxBuffer + i)->animFrame = random_float() * 7.0f; } + #ifndef QOL_FIXES if (0) { } + #endif } gEnvFxMode = mode; diff --git a/src/game/envfx_snow.c b/src/game/envfx_snow.c index c3c14a5c0..858cff0fe 100644 --- a/src/game/envfx_snow.c +++ b/src/game/envfx_snow.c @@ -272,7 +272,11 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy * find it. The radius of 3000 units is quite large for that though, covering * more than half of the mirror room. */ +#ifndef TARGET_WEB static s32 is_in_mystery_snow_area(s32 x, UNUSED s32 y, s32 z) { +#else +UNUSED static s32 is_in_mystery_snow_area(s32 x, UNUSED s32 y, s32 z) { +#endif if (sqr(x - 3380) + sqr(z + 520) < sqr(3000)) { return 1; } diff --git a/src/game/game_init.c b/src/game/game_init.c index c2df4510b..8f5f2f9d4 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -129,7 +129,7 @@ void clear_z_buffer(void) { gDPSetFillColor(gDisplayListHead++, GPACK_ZDZ(G_MAXFBZ, 0) << 16 | GPACK_ZDZ(G_MAXFBZ, 0)); - gDPFillRectangle(gDisplayListHead++, 0, BORDER_HEIGHT, SCREEN_WIDTH - 1, + gDPFillRectangle(gDisplayListHead++, GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE(0), BORDER_HEIGHT, GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE(0) - 1, SCREEN_HEIGHT - 1 - BORDER_HEIGHT); } @@ -311,7 +311,11 @@ void display_and_vsync(void) { // this function records distinct inputs over a 255-frame interval to RAM locations and was likely // used to record the demo sequences seen in the final game. This function is unused. +#ifndef TARGET_WEB static void record_demo(void) { +#else +UNUSED static void record_demo(void) { +#endif // record the player's button mask and current rawStickX and rawStickY. u8 buttonMask = ((gPlayer1Controller->buttonDown & (A_BUTTON | B_BUTTON | Z_TRIG | START_BUTTON)) >> 8) diff --git a/src/game/hud.c b/src/game/hud.c index 1540b675a..0cb34a0f5 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -55,7 +55,11 @@ static struct PowerMeterHUD sPowerMeterHUD = { // when the power meter is hidden. s32 sPowerMeterVisibleTimer = 0; +#ifndef TARGET_WEB static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 }; +#else +UNUSED static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 }; +#endif static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE }; diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 7ae9f1e73..4fd1f773b 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -276,7 +276,7 @@ void render_generic_char(u8 c) { #ifdef VERSION_EU static void alloc_ia4_tex_from_i1(u8 *out, u8 *in, s16 width, s16 height) { - u32 size = (u32) width * (u32) height; + UNUSED u32 size = (u32) width * (u32) height; s32 inPos; s16 outPos = 0; u8 bitMask; @@ -414,7 +414,13 @@ void print_generic_string(s16 x, s16 y, const u8 *str) { case DIALOG_CHAR_LOWER_A_UMLAUT: render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('a'), str[strPos] & 0xF); break; + #ifndef QOL_FIXES case DIALOG_CHAR_UPPER_A_UMLAUT: // @bug grave and circumflex (0x64-0x65) are absent here + #else + case DIALOG_CHAR_UPPER_A_GRAVE: + case DIALOG_CHAR_UPPER_A_CIRCUMFLEX: + case DIALOG_CHAR_UPPER_A_UMLAUT: + #endif render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('A'), str[strPos] & 0xF); break; case DIALOG_CHAR_LOWER_E_GRAVE: @@ -434,14 +440,25 @@ void print_generic_string(s16 x, s16 y, const u8 *str) { case DIALOG_CHAR_LOWER_U_UMLAUT: render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('u'), str[strPos] & 0xF); break; + #ifndef QOL_FIXES case DIALOG_CHAR_UPPER_U_UMLAUT: // @bug grave and circumflex (0x84-0x85) are absent here + #else + case DIALOG_CHAR_UPPER_U_GRAVE: + case DIALOG_CHAR_UPPER_U_CIRCUMFLEX: + case DIALOG_CHAR_UPPER_U_UMLAUT: + #endif render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('U'), str[strPos] & 0xF); break; case DIALOG_CHAR_LOWER_O_CIRCUMFLEX: case DIALOG_CHAR_LOWER_O_UMLAUT: render_lowercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('o'), str[strPos] & 0xF); break; + #ifndef QOL_FIXES case DIALOG_CHAR_UPPER_O_UMLAUT: // @bug circumflex (0x95) is absent here + #else + case DIALOG_CHAR_UPPER_O_CIRCUMFLEX: + case DIALOG_CHAR_UPPER_O_UMLAUT: + #endif render_uppercase_diacritic(&xCoord, &yCoord, ASCII_TO_DIALOG('O'), str[strPos] & 0xF); break; case DIALOG_CHAR_LOWER_I_CIRCUMFLEX: @@ -589,11 +606,15 @@ void print_hud_lut_string(s8 hudLUT, s16 x, s16 y, const u8 *str) { #endif #if defined(VERSION_US) || defined(VERSION_SH) if (str[strPos] == GLOBAL_CHAR_SPACE) { + #ifndef QOL_FIXES if (0) //! dead code { } + #endif curX += 8; + #ifndef QOL_FIXES ; //! useless statement + #endif } else { #endif gDPPipeSync(gDisplayListHead++); @@ -751,6 +772,7 @@ void handle_menu_scrolling(s8 scrollDirection, s8 *currentIndex, s8 minIndex, s8 } if (((index ^ gMenuHoldKeyIndex) & index) == 2) { + #ifndef QOL_FIXES if (currentIndex[0] == maxIndex) { //! Probably originally a >=, but later replaced with an == and an else statement. currentIndex[0] = maxIndex; @@ -758,15 +780,31 @@ void handle_menu_scrolling(s8 scrollDirection, s8 *currentIndex, s8 minIndex, s8 play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); currentIndex[0]++; } + #else + // if <=, this could cause an OOB array access and crash. Use < instead here to fix this. + // >= is incorrect and will cause the menu to not function correctly + if (currentIndex[0] < maxIndex) { + play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); + currentIndex[0]++; + } + #endif } if (((index ^ gMenuHoldKeyIndex) & index) == 1) { + #ifndef QOL_FIXES if (currentIndex[0] == minIndex) { // Same applies to here as above } else { play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); currentIndex[0]--; } + #else + // if >=, this could cause an OOB array access and crash. Use > instead here to fix this. + if (currentIndex[0] > minIndex) { + play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); + currentIndex[0]--; + } + #endif } if (gMenuHoldKeyTimer == 10) { @@ -809,10 +847,14 @@ s16 get_str_x_pos_from_center_scale(s16 centerPos, u8 *str, f32 scale) { //! EU checks for dakuten and handakuten despite dialog code unable to handle it if (str[strPos] == DIALOG_CHAR_SPACE) { spacesWidth += 1.0; + #if (defined(VERSION_EU) && !defined(QOL_FIXES)) || defined(VERSION_JP) || defined(VERSION_SH) } else if (str[strPos] != DIALOG_CHAR_DAKUTEN && str[strPos] != DIALOG_CHAR_PERIOD_OR_HANDAKUTEN) { charsWidth += 1.0; } + #elif (defined(VERSION_EU) && defined(QOL_FIXES)) + } + #endif strPos++; } // return the x position of where the string starts as half the string's @@ -2176,6 +2218,20 @@ u8 gTextCourseArr[][7] = { { TEXT_COURSE_FR }, { TEXT_COURSE_DE } }; +#ifdef QOL_FIXES + +u8 gTextCatchArr[][8] = { + { TEXT_CATCH }, + { TEXT_CATCH_FR }, + { TEXT_CATCH_DE } +}; + +u8 gTextClearArr[][8] = { + { TEXT_CLEAR }, + { TEXT_CLEAR_FR }, + { TEXT_CLEAR_DE } +}; +#endif #endif #if defined(VERSION_JP) || defined(VERSION_SH) @@ -2781,7 +2837,11 @@ void print_hud_course_complete_coins(s16 x, s16 y) { gCourseCompleteCoins++; play_sound(SOUND_MENU_YOSHI_GAIN_LIVES, gDefaultSoundArgs); + #ifndef QOL_FIXES if (gCourseCompleteCoins == 50 || gCourseCompleteCoins == 100 || gCourseCompleteCoins == 150) { + #else + if (gCourseCompleteCoins % 50 == 0) { + #endif play_sound(SOUND_GENERAL_COLLECT_1UP, gDefaultSoundArgs); gMarioState[0].numLives++; } @@ -2825,15 +2885,25 @@ void render_course_complete_lvl_info_and_hud_str(void) { u8 textCourse[] = { TEXT_COURSE }; u8 textCatch[] = { TEXT_CATCH }; u8 textClear[] = { TEXT_CLEAR }; -#elif defined(VERSION_EU) +#elif defined(VERSION_EU) && !defined(QOL_FIXES) UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in EU u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE }; #define textCourse gTextCourseArr[gInGameLanguage] -#else +#elif defined(VERSION_US) && !defined(QOL_FIXES) u8 textCourse[] = { TEXT_COURSE }; UNUSED u8 textCatch[] = { TEXT_CATCH }; // unused in US UNUSED u8 textClear[] = { TEXT_CLEAR }; u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE }; +#elif defined(VERSION_EU) && defined(QOL_FIXES) + u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE }; +#define textCatch gTextCatchArr[gInGameLanguage] +#define textCourse gTextCourseArr[gInGameLanguage] +#define textClear gTextClearArr[gInGameLanguage] +#else + u8 textCourse[] = { TEXT_COURSE }; + u8 textCatch[] = { TEXT_CATCH }; + u8 textClear[] = { TEXT_CLEAR }; + u8 textSymStar[] = { GLYPH_STAR, GLYPH_SPACE }; #endif void **actNameTbl; @@ -2890,12 +2960,12 @@ void render_course_complete_lvl_info_and_hud_str(void) { centerX = get_str_x_pos_from_center(153, name, 12.0f); #endif print_generic_string(TXT_NAME_X1, 130, name); -#ifndef VERSION_EU +#if !defined(VERSION_EU) || defined(QOL_FIXES) print_generic_string(TXT_CLEAR_X1, 130, textClear); #endif gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); print_generic_string(TXT_NAME_X2, 132, name); -#ifndef VERSION_EU +#if !defined(VERSION_EU) || defined(QOL_FIXES) print_generic_string(TXT_CLEAR_X2, 132, textClear); #endif gSPDisplayList(gDisplayListHead++, dl_ia_text_end); @@ -2916,12 +2986,12 @@ void render_course_complete_lvl_info_and_hud_str(void) { gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, gDialogTextAlpha); print_generic_string(76, 145, name); -#if defined(VERSION_JP) || defined(VERSION_SH) +#if defined(VERSION_JP) || defined(VERSION_SH) || defined(QOL_FIXES) print_generic_string(220, 145, textCatch); #endif gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); print_generic_string(74, 147, name); -#if defined(VERSION_JP) || defined(VERSION_SH) +#if defined(VERSION_JP) || defined(VERSION_SH) || defined(QOL_FIXES) print_generic_string(218, 147, textCatch); #endif gSPDisplayList(gDisplayListHead++, dl_ia_text_end); @@ -2966,7 +3036,7 @@ void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e) { TEXT_SAVE_AND_QUIT_DE } }; - u8 textSaveExitGame[][26] = { // New function to exit game + u8 textSaveExitGame[][28] = { // New function to exit game { TEXT_SAVE_EXIT_GAME }, { TEXT_SAVE_EXIT_GAME_FR }, { TEXT_SAVE_EXIT_GAME_DE } diff --git a/src/game/interaction.c b/src/game/interaction.c index 7a9c5203b..e2183f222 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -525,7 +525,11 @@ void hit_object_from_below(struct MarioState *m, UNUSED struct Object *o) { set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW); } +#ifndef TARGET_WEB static u32 unused_determine_knockback_action(struct MarioState *m) { +#else +UNUSED static u32 unused_determine_knockback_action(struct MarioState *m) { +#endif u32 bonkAction; s16 angleToObject = mario_obj_angle_to_object(m, m->interactObj); s16 facingDYaw = angleToObject - m->faceAngle[1]; @@ -1050,7 +1054,11 @@ u32 interact_door(struct MarioState *m, UNUSED u32 interactType, struct Object * } u32 interact_cannon_base(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { + #ifndef QOL_FIXES if (m->action != ACT_IN_CANNON) { + #else + if (m->action != ACT_IN_CANNON && m->health >= 0x100) { + #endif mario_stop_riding_and_holding(m); o->oInteractStatus = INT_STATUS_INTERACTED; m->interactObj = o; @@ -1278,7 +1286,11 @@ u32 interact_shock(struct MarioState *m, UNUSED u32 interactType, struct Object return FALSE; } +#ifndef TARGET_WEB static u32 interact_stub(UNUSED struct MarioState *m, UNUSED u32 interactType, struct Object *o) { +#else +UNUSED static u32 interact_stub(UNUSED struct MarioState *m, UNUSED u32 interactType, struct Object *o) { +#endif if (!(o->oInteractionSubtype & INT_SUBTYPE_DELAY_INVINCIBILITY)) { sDelayInvincTimer = TRUE; } @@ -1477,7 +1489,7 @@ u32 interact_pole(struct MarioState *m, UNUSED u32 interactType, struct Object * s32 actionId = m->action & ACT_ID_MASK; if (actionId >= 0x080 && actionId < 0x0A0) { if (!(m->prevAction & ACT_FLAG_ON_POLE) || m->usedObj != o) { -#ifdef VERSION_SH +#if BUGFIX_PRESERVE_VEL_POLE f32 velConv = m->forwardVel; // conserve the velocity. struct Object *marioObj = m->marioObj; u32 lowSpeed; @@ -1488,7 +1500,7 @@ u32 interact_pole(struct MarioState *m, UNUSED u32 interactType, struct Object * mario_stop_riding_and_holding(m); -#ifdef VERSION_SH +#if BUGFIX_PRESERVE_VEL_POLE lowSpeed = (velConv <= 10.0f); #endif @@ -1496,6 +1508,9 @@ u32 interact_pole(struct MarioState *m, UNUSED u32 interactType, struct Object * m->usedObj = o; m->vel[1] = 0.0f; m->forwardVel = 0.0f; +#ifdef QOL_FIXES + m->pos[1] = max(o->oPosY, m->pos[1]); +#endif marioObj->oMarioPoleUnk108 = 0; marioObj->oMarioPoleYawVel = 0; @@ -1507,7 +1522,7 @@ u32 interact_pole(struct MarioState *m, UNUSED u32 interactType, struct Object * //! @bug Using m->forwardVel here is assumed to be 0.0f due to the set from earlier. // This is fixed in the Shindou version. -#ifdef VERSION_SH +#if BUGFIX_PRESERVE_VEL_POLE marioObj->oMarioPoleYawVel = (s32)(velConv * 0x100 + 0x1000); #else marioObj->oMarioPoleYawVel = (s32)(m->forwardVel * 0x100 + 0x1000); diff --git a/src/game/level_update.c b/src/game/level_update.c index 72a6a6073..49e073ebf 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1071,17 +1071,24 @@ void level_set_transition(s16 length, void (*updateFunction)(s16 *)) { s32 play_mode_change_area(void) { //! This maybe was supposed to be sTransitionTimer == -1? sTransitionUpdate // is never set to -1. + #ifndef QOL_FIXES if (sTransitionUpdate == (void (*)(s16 *)) - 1) { + #else + if (sTransitionTimer == -1) { + #endif update_camera(gCurrentArea->camera); } else if (sTransitionUpdate != NULL) { sTransitionUpdate(&sTransitionTimer); } if (sTransitionTimer > 0) { + #ifndef QOL_FIXES sTransitionTimer -= 1; + #else + sTransitionTimer--; + #endif } - //! If sTransitionTimer is -1, this will miss. if (sTransitionTimer == 0) { sTransitionUpdate = NULL; set_play_mode(PLAY_MODE_NORMAL); @@ -1098,7 +1105,6 @@ s32 play_mode_change_level(void) { sTransitionUpdate(&sTransitionTimer); } - //! If sTransitionTimer is -1, this will miss. if (--sTransitionTimer == -1) { gHudDisplay.flags = HUD_DISPLAY_NONE; sTransitionTimer = 0; @@ -1117,7 +1123,11 @@ s32 play_mode_change_level(void) { /** * Unused play mode. Doesn't call transition update and doesn't reset transition at the end. */ +#ifndef TARGET_WEB static s32 play_mode_unused(void) { +#else +UNUSED static s32 play_mode_unused(void) { +#endif if (--sTransitionTimer == -1) { gHudDisplay.flags = HUD_DISPLAY_NONE; @@ -1145,7 +1155,11 @@ s32 update_level(void) { changeLevel = play_mode_change_area(); break; case PLAY_MODE_CHANGE_LEVEL: + #ifdef USE_UNUSED_PLAY_STATE + changeLevel = play_mode_unused(); + #else changeLevel = play_mode_change_level(); + #endif break; case PLAY_MODE_FRAME_ADVANCE: changeLevel = play_mode_frame_advance(); diff --git a/src/game/macro_special_objects.c b/src/game/macro_special_objects.c index 17e4e6c40..d6b889271 100644 --- a/src/game/macro_special_objects.c +++ b/src/game/macro_special_objects.c @@ -79,7 +79,11 @@ void spawn_macro_abs_special(u32 model, const BehaviorScript *behavior, s16 x, s newObj->oMacroUnk110 = (f32) unkC; } +#ifndef TARGET_WEB static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) { +#else +UNUSED static void spawn_macro_coin_unknown(const BehaviorScript *behavior, s16 a1[]) { +#endif struct Object *sp3C; s16 model; diff --git a/src/game/main.c b/src/game/main.c index 88855ee5f..ce1b86336 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -112,7 +112,11 @@ void unknown_main_func(void) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnonnull" +#ifndef QOL_FIXES sprintf(NULL, NULL); +#else + sprintf("", ""); +#endif #pragma GCC diagnostic pop } diff --git a/src/game/mario.c b/src/game/mario.c index 5f8e5114e..748412bbb 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -879,7 +879,13 @@ static u32 set_mario_action_airborne(struct MarioState *m, u32 action, u32 actio // too much velocity, but misses backwards longs allowing high negative speeds. if ((m->forwardVel *= 1.5f) > 48.0f) { m->forwardVel = 48.0f; + #if BUGFIX_BLJ + } else if (m->forwardVel < -25.0f) { + m->forwardVel = -25.0f; } + #else + } + #endif break; case ACT_SLIDE_KICK: @@ -1532,7 +1538,11 @@ void update_mario_health(struct MarioState *m) { } // Play a noise to alert the player when Mario is close to drowning. - if (((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) && (m->health < 0x300)) { + if (((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) && (m->health < 0x300) +#ifdef QOL_FIXES + && !((m->flags & (MARIO_METAL_CAP)) > 0) +#endif + ) { play_sound(SOUND_MOVING_ALMOST_DROWNING, gDefaultSoundArgs); if (!gRumblePakTimer) { gRumblePakTimer = 36; @@ -1702,7 +1712,11 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) { * An unused and possibly a debug function. Z + another button input * sets Mario with a different cap. */ +#ifndef TARGET_WEB static void debug_update_mario_cap(u16 button, s32 flags, u16 capTimer, u16 capMusic) { +#else +UNUSED static void debug_update_mario_cap(u16 button, s32 flags, u16 capTimer, u16 capMusic) { +#endif // This checks for Z_TRIG instead of Z_DOWN flag // (which is also what other debug functions do), // so likely debug behavior rather than unused behavior. @@ -1908,7 +1922,11 @@ void init_mario(void) { vec3f_copy(gMarioState->marioObj->header.gfx.pos, gMarioState->pos); vec3s_set(gMarioState->marioObj->header.gfx.angle, 0, gMarioState->faceAngle[1], 0); - if (save_file_get_cap_pos(capPos)) { + if (save_file_get_cap_pos(capPos) +#ifdef QOL_FIXES + && (count_objects_with_behavior(bhvNormalCap) > 1) +#endif + ) { capObject = spawn_object(gMarioState->marioObj, MODEL_MARIOS_CAP, bhvNormalCap); capObject->oPosX = capPos[0]; diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 17e45ae43..f30894244 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -71,12 +71,16 @@ s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" + #ifndef TARGET_WEB //! Never true if (m->actionState == ACT_GROUND_POUND) { damageHeight = 600.0f; } else { damageHeight = 1150.0f; } + #else + damageHeight = 1150.0f; + #endif #pragma GCC diagnostic pop @@ -160,7 +164,11 @@ s32 check_horizontal_wind(struct MarioState *m) { if (speed > 48.0f) { m->slideVelX = m->slideVelX * 48.0f / speed; m->slideVelZ = m->slideVelZ * 48.0f / speed; + #ifndef QOL_FIXES speed = 32.0f; //! This was meant to be 48? + #else + speed = 48.0f; + #endif } else if (speed > 32.0f) { speed = 32.0f; } @@ -2069,17 +2077,54 @@ s32 act_special_triple_jump(struct MarioState *m) { switch (perform_air_step(m, 0)) { case AIR_STEP_LANDED: + #ifndef QOL_FIXES if (m->actionState++ == 0) { m->vel[1] = 42.0f; } else { set_mario_action(m, ACT_FREEFALL_LAND_STOP, 0); } + #else + if (m->actionState++ != 0) { + set_mario_action(m, ACT_FREEFALL_LAND_STOP, 0); + } + #endif play_mario_landing_sound(m, SOUND_ACTION_TERRAIN_LANDING); break; + #ifdef QOL_FIXES + case AIR_STEP_HIT_WALL: + if (m->forwardVel > 16.0f) { + mario_bonk_reflection(m, FALSE); + m->faceAngle[1] += 0x8000; + if (m->wall != NULL) + set_mario_action(m, ACT_AIR_HIT_WALL, 0); + else { + if (m->vel[1] > 0.0f) + m->vel[1] = 0.0f; + if (m->forwardVel >= 38.0f) { + m->particleFlags |= PARTICLE_VERTICAL_STAR; + set_mario_action(m, ACT_BACKWARD_AIR_KB, 0); + } else { + if (m->forwardVel > 8.0f) + mario_set_forward_vel(m, -8.0f); + return set_mario_action(m, ACT_SOFT_BONK, 0); + } + } + } else + mario_set_forward_vel(m, 0.0f); + break; + case AIR_STEP_GRABBED_LEDGE: + set_mario_animation(m, MARIO_ANIM_IDLE_ON_LEDGE); + drop_and_set_mario_action(m, ACT_LEDGE_GRAB, 0); + break; + case AIR_STEP_GRABBED_CEILING: + set_mario_action(m, ACT_START_HANGING, 0); + break; + #else case AIR_STEP_HIT_WALL: mario_bonk_reflection(m, TRUE); break; + #endif } if (m->actionState == 0 || m->vel[1] > 0.0f) { diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 72e769298..f5f5aa2a0 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -219,7 +219,11 @@ s32 geo_switch_peach_eyes(s32 run, struct GraphNode *node, UNUSED s32 a2) { } // unused +#ifndef TARGET_WEB static void stub_is_textbox_active(u16 *a0) { +#else +UNUSED static void stub_is_textbox_active(u16 *a0) { +#endif if (get_dialog_id() == -1) { *a0 = 0; } @@ -785,10 +789,28 @@ s32 launch_mario_until_land(struct MarioState *m, s32 endAction, s32 animation, } s32 act_unlocking_key_door(struct MarioState *m) { +#ifdef QOL_FIXES +#ifndef TARGET_WEB + f32 angle; +#else + f32 angle = 0.0f; +#endif +#endif m->faceAngle[1] = m->usedObj->oMoveAngleYaw; +#ifdef QOL_FIXES + if (m->faceAngle[1] >= -0x4000 && m->faceAngle[1] <= 0x4000) { + angle -= 75.0f; + } else { + angle += 75.0f; + } + + m->pos[0] = m->usedObj->oPosX + coss(m->faceAngle[1]) * angle; + m->pos[2] = m->usedObj->oPosZ + sins(m->faceAngle[1]) * angle; +#else m->pos[0] = m->usedObj->oPosX + coss(m->faceAngle[1]) * 75.0f; m->pos[2] = m->usedObj->oPosZ + sins(m->faceAngle[1]) * 75.0f; +#endif if (m->actionArg & 2) { m->faceAngle[1] += 0x8000; @@ -1119,15 +1141,27 @@ s32 act_exit_land_save_dialog(struct MarioState *m) { switch (animFrame) { case -1: spawn_obj_at_mario_rel_yaw(m, MODEL_BOWSER_KEY_CUTSCENE, bhvBowserKeyCourseExit, -32768); + #ifdef QOL_FIXES + break; + #endif //! fall through case 67: play_sound(SOUND_ACTION_KEY_SWISH, m->marioObj->header.gfx.cameraToObject); + #ifdef QOL_FIXES + break; + #endif //! fall through case 83: play_sound(SOUND_ACTION_PAT_BACK, m->marioObj->header.gfx.cameraToObject); + #ifdef QOL_FIXES + break; + #endif //! fall through case 111: play_sound(SOUND_ACTION_UNKNOWN45C, m->marioObj->header.gfx.cameraToObject); + #ifdef QOL_FIXES + break; + #endif // no break } handle_save_menu(m); @@ -1965,10 +1999,16 @@ void generate_yellow_sparkles(s16 x, s16 y, s16 z, f32 radius) { spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_NONE, bhvSparkleSpawn, x + offsetX, y + offsetY, z + offsetZ, 0, 0, 0); + #ifndef QOL_FIXES //! copy paste error offsetX = offsetX * 4 / 3; offsetX = offsetY * 4 / 3; offsetX = offsetZ * 4 / 3; + #else + offsetX = offsetX * 4 / 3; + offsetY = offsetY * 4 / 3; + offsetZ = offsetZ * 4 / 3; + #endif spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_NONE, bhvSparkleSpawn, x - offsetX, y - offsetY, z - offsetZ, 0, 0, 0); diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 0ccbccf10..9c2bba09f 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -151,7 +151,12 @@ void slide_bonk(struct MarioState *m, u32 fastAction, u32 slowAction) { s32 set_triple_jump_action(struct MarioState *m, UNUSED u32 action, UNUSED u32 actionArg) { if (m->flags & MARIO_WING_CAP) { return set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0); + #ifndef QOL_FIXES } else if (m->forwardVel > 20.0f) { + #else + } else if (m->forwardVel > 20.0f && ((mario_get_floor_class(m) == SURFACE_CLASS_NOT_SLIPPERY) || (mario_get_floor_class(m) == SURFACE_CLASS_DEFAULT) + || (mario_get_floor_class(m) == SURFACE_HARD_NOT_SLIPPERY) || (mario_get_floor_class(m) == SURFACE_HARD_SLIPPERY))) { + #endif return set_mario_action(m, ACT_TRIPLE_JUMP, 0); } else { return set_mario_action(m, ACT_JUMP, 0); @@ -386,7 +391,13 @@ void update_shell_speed(struct MarioState *m) { //! No backward speed cap (shell hyperspeed) if (m->forwardVel > 64.0f) { m->forwardVel = 64.0f; + #if !BUGFIX_BLJ } + #else + } else if (m->forwardVel < -64.0f) { + m->forwardVel = -64.0f; + } + #endif m->faceAngle[1] = m->intendedYaw - approach_s32((s16)(m->intendedYaw - m->faceAngle[1]), 0, 0x800, 0x800); @@ -524,11 +535,19 @@ s32 begin_braking_action(struct MarioState *m) { } void anim_and_audio_for_walk(struct MarioState *m) { + #ifndef QOL_FIXES s32 val14; + #else + s64 val14; + #endif struct Object *marioObj = m->marioObj; s32 val0C = TRUE; s16 targetPitch = 0; + #ifndef QOL_FIXES f32 val04; + #else + f64 val04; + #endif val04 = m->intendedMag > m->forwardVel ? m->intendedMag : m->forwardVel; @@ -537,7 +556,11 @@ void anim_and_audio_for_walk(struct MarioState *m) { } if (m->quicksandDepth > 50.0f) { + #ifndef QOL_FIXES val14 = (s32)(val04 / 4.0f * 0x10000); + #else + val14 = (s64)(val04 / 4.0f * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_MOVE_IN_QUICKSAND, val14); play_step_sound(m, 19, 93); m->actionTimer = 0; @@ -549,7 +572,11 @@ void anim_and_audio_for_walk(struct MarioState *m) { m->actionTimer = 2; } else { //! (Speed Crash) If Mario's speed is more than 2^17. + #ifndef QOL_FIXES if ((val14 = (s32)(val04 / 4.0f * 0x10000)) < 0x1000) { + #else + if ((val14 = (s64)(val04 / 4.0f * 0x10000)) < 0x1000) { + #endif val14 = 0x1000; } set_mario_anim_with_accel(m, MARIO_ANIM_START_TIPTOE, val14); @@ -567,7 +594,11 @@ void anim_and_audio_for_walk(struct MarioState *m) { m->actionTimer = 2; } else { //! (Speed Crash) If Mario's speed is more than 2^17. + #ifndef QOL_FIXES if ((val14 = (s32)(val04 * 0x10000)) < 0x1000) { + #else + if ((val14 = (s64)(val04 * 0x10000)) < 0x1000) { + #endif val14 = 0x1000; } set_mario_anim_with_accel(m, MARIO_ANIM_TIPTOE, val14); @@ -584,7 +615,11 @@ void anim_and_audio_for_walk(struct MarioState *m) { m->actionTimer = 3; } else { //! (Speed Crash) If Mario's speed is more than 2^17. + #ifndef QOL_FIXES val14 = (s32)(val04 / 4.0f * 0x10000); + #else + val14 = (s64)(val04 / 4.0f * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_WALKING, val14); play_step_sound(m, 10, 49); @@ -597,7 +632,11 @@ void anim_and_audio_for_walk(struct MarioState *m) { m->actionTimer = 2; } else { //! (Speed Crash) If Mario's speed is more than 2^17. + #ifndef QOL_FIXES val14 = (s32)(val04 / 4.0f * 0x10000); + #else + val14 = (s64)(val04 / 4.0f * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_RUNNING, val14); play_step_sound(m, 9, 45); targetPitch = tilt_body_running(m); @@ -615,9 +654,17 @@ void anim_and_audio_for_walk(struct MarioState *m) { } void anim_and_audio_for_hold_walk(struct MarioState *m) { + #ifndef QOL_FIXES s32 val0C; + #else + s64 val0C; + #endif s32 val08 = TRUE; + #ifndef QOL_FIXES f32 val04; + #else + f64 val04; + #endif val04 = m->intendedMag > m->forwardVel ? m->intendedMag : m->forwardVel; @@ -632,7 +679,11 @@ void anim_and_audio_for_hold_walk(struct MarioState *m) { m->actionTimer = 1; } else { //! (Speed Crash) Crashes if Mario's speed exceeds or equals 2^15. + #ifndef QOL_FIXES val0C = (s32)(val04 * 0x10000); + #else + val0C = (s64)(val04 * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_SLOW_WALK_WITH_LIGHT_OBJ, val0C); play_step_sound(m, 12, 62); @@ -647,7 +698,11 @@ void anim_and_audio_for_hold_walk(struct MarioState *m) { m->actionTimer = 2; } else { //! (Speed Crash) Crashes if Mario's speed exceeds or equals 2^15. + #ifndef QOL_FIXES val0C = (s32)(val04 * 0x10000); + #else + val0C = (s64)(val04 * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_WALK_WITH_LIGHT_OBJ, val0C); play_step_sound(m, 12, 62); @@ -660,7 +715,11 @@ void anim_and_audio_for_hold_walk(struct MarioState *m) { m->actionTimer = 1; } else { //! (Speed Crash) Crashes if Mario's speed exceeds or equals 2^16. + #ifndef QOL_FIXES val0C = (s32)(val04 / 2.0f * 0x10000); + #else + val0C = (s64)(val04 / 2.0f * 0x10000); + #endif set_mario_anim_with_accel(m, MARIO_ANIM_RUN_WITH_LIGHT_OBJ, val0C); play_step_sound(m, 10, 49); @@ -684,7 +743,11 @@ void push_or_sidle_wall(struct MarioState *m, Vec3f startPos) { f32 dz = m->pos[2] - startPos[2]; f32 movedDistance = sqrtf(dx * dx + dz * dz); //! (Speed Crash) If a wall is after moving 16384 distance, this crashes. + #ifndef QOL_FIXES s32 val04 = (s32)(movedDistance * 2.0f * 0x10000); + #else + s64 val04 = (s64)(movedDistance * 2.0f * 0x10000); + #endif if (m->forwardVel > 6.0f) { mario_set_forward_vel(m, 6.0f); @@ -723,15 +786,25 @@ void tilt_body_walking(struct MarioState *m, s16 startYaw) { UNUSED struct Object *marioObj = m->marioObj; s16 animID = m->marioObj->header.gfx.unk38.animID; s16 dYaw; + #ifndef QOL_FIXES s16 val02; s16 val00; + #else + s64 val02; + s64 val00; + #endif if (animID == MARIO_ANIM_WALKING || animID == MARIO_ANIM_RUNNING) { dYaw = m->faceAngle[1] - startYaw; //! (Speed Crash) These casts can cause a crash if (dYaw * forwardVel / 12) or //! (forwardVel * 170) exceed or equal 2^31. + #ifndef QOL_FIXES val02 = -(s16)(dYaw * m->forwardVel / 12.0f); val00 = (s16)(m->forwardVel * 170.0f); + #else + val02 = -(s64)(dYaw * m->forwardVel / 12.0f); + val00 = (s64)(m->forwardVel * 170.0f); + #endif if (val02 > 0x1555) { val02 = 0x1555; @@ -749,7 +822,9 @@ void tilt_body_walking(struct MarioState *m, s16 startYaw) { val0C->torsoAngle[2] = approach_s32(val0C->torsoAngle[2], val02, 0x400, 0x400); val0C->torsoAngle[0] = approach_s32(val0C->torsoAngle[0], val00, 0x400, 0x400); + #ifndef QOL_FIXES ; + #endif } else { val0C->torsoAngle[2] = 0; val0C->torsoAngle[0] = 0; @@ -763,8 +838,13 @@ void tilt_body_ground_shell(struct MarioState *m, s16 startYaw) { //! (Speed Crash) These casts can cause a crash if (dYaw * forwardVel / 12) or //! (forwardVel * 170) exceed or equal 2^31. Harder (if not impossible to do) //! while on a Koopa Shell making this less of an issue. + #ifndef QOL_FIXES s16 val04 = -(s16)(dYaw * m->forwardVel / 12.0f); s16 val02 = (s16)(m->forwardVel * 170.0f); + #else + s64 val04 = -(s64)(dYaw * m->forwardVel / 12.0f); + s64 val02 = (s64)(m->forwardVel * 170.0f); + #endif if (val04 > 0x1800) { val04 = 0x1800; @@ -814,9 +894,20 @@ s32 act_walking(struct MarioState *m) { return begin_braking_action(m); } +#ifdef QOL_FIXES + if (analog_stick_held_back(m)) { + if (m->forwardVel >= 16.0f) { + return set_mario_action(m, ACT_TURNING_AROUND, 0); + } else if ((m->forwardVel) < 10.0f && (m->forwardVel > 0.0f)) { + m->faceAngle[1] = m->intendedYaw; + return set_mario_action(m, ACT_TURNING_AROUND, 0); + } + } +#else if (analog_stick_held_back(m) && m->forwardVel >= 16.0f) { return set_mario_action(m, ACT_TURNING_AROUND, 0); } +#endif if (m->input & INPUT_Z_PRESSED) { return set_mario_action(m, ACT_CROUCH_SLIDE, 0); @@ -857,7 +948,16 @@ s32 act_move_punching(struct MarioState *m) { } if (m->actionState == 0 && (m->input & INPUT_A_DOWN)) { + #ifndef QOL_FIXES return set_mario_action(m, ACT_JUMP_KICK, 0); + #else + if ((mario_get_floor_class(m) == SURFACE_CLASS_NOT_SLIPPERY) || (mario_get_floor_class(m) == SURFACE_CLASS_DEFAULT) + || (mario_get_floor_class(m) == SURFACE_HARD_NOT_SLIPPERY) || (mario_get_floor_class(m) == SURFACE_HARD_SLIPPERY)) { + return set_mario_action(m, ACT_JUMP_KICK, 0); + } else { + return set_mario_action(m, ACT_DIVE, 0); + } + #endif } m->actionState = 1; @@ -1084,7 +1184,11 @@ s32 act_braking(struct MarioState *m) { } s32 act_decelerating(struct MarioState *m) { + #ifndef QOL_FIXES s32 val0C; + #else + s64 val0C; + #endif s16 slopeClass = mario_get_floor_class(m); if (!(m->input & INPUT_FIRST_PERSON)) { @@ -1134,7 +1238,11 @@ s32 act_decelerating(struct MarioState *m) { m->particleFlags |= PARTICLE_DUST; } else { // (Speed Crash) Crashes if speed exceeds 2^17. + #ifndef QOL_FIXES if ((val0C = (s32)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) { + #else + if ((val0C = (s64)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) { + #endif val0C = 0x1000; } @@ -1146,7 +1254,11 @@ s32 act_decelerating(struct MarioState *m) { } s32 act_hold_decelerating(struct MarioState *m) { + #ifndef QOL_FIXES s32 val0C; + #else + s64 val0C; + #endif s16 slopeClass = mario_get_floor_class(m); if (m->marioObj->oInteractStatus & INT_STATUS_MARIO_DROP_OBJECT) { @@ -1200,7 +1312,11 @@ s32 act_hold_decelerating(struct MarioState *m) { m->particleFlags |= PARTICLE_DUST; } else { //! (Speed Crash) This crashes if Mario has more speed than 2^15 speed. + #ifndef QOL_FIXES if ((val0C = (s32)(m->forwardVel * 0x10000)) < 0x1000) { + #else + if ((val0C = (s64)(m->forwardVel * 0x10000)) < 0x1000) { + #endif val0C = 0x1000; } @@ -1298,6 +1414,9 @@ s32 act_crawling(struct MarioState *m) { mario_set_forward_vel(m, 10.0f); } //! Possibly unintended missing break + #ifdef QOL_FIXES + break; + #endif case GROUND_STEP_NONE: align_with_floor(m); @@ -1762,6 +1881,12 @@ s32 common_landing_cancels(struct MarioState *m, struct LandingAction *landingAc //! Everything here, including floor steepness, is checked before checking // if Mario is actually on the floor. This leads to e.g. remote sliding. + #ifdef QOL_FIXES + if (m->input & INPUT_OFF_FLOOR) { + return set_mario_action(m, landingAction->offFloorAction, 0); + } + #endif + if (m->floor->normal.y < 0.2923717f) { return mario_push_off_steep_floor(m, landingAction->verySteepAction, 0); } @@ -1784,9 +1909,11 @@ s32 common_landing_cancels(struct MarioState *m, struct LandingAction *landingAc return setAPressAction(m, landingAction->aPressedAction, 0); } + #ifndef QOL_FIXES if (m->input & INPUT_OFF_FLOOR) { return set_mario_action(m, landingAction->offFloorAction, 0); } + #endif return FALSE; } diff --git a/src/game/mario_actions_object.c b/src/game/mario_actions_object.c index e34192a50..d881fffe3 100644 --- a/src/game/mario_actions_object.c +++ b/src/game/mario_actions_object.c @@ -220,7 +220,11 @@ s32 act_dive_picking_up(struct MarioState *m) { // landing from a dive grab sets Mario's action to a non-holding action // without dropping the object, causing the hands-free holding glitch. if (m->input & INPUT_OFF_FLOOR) { + #ifndef QOL_FIXES return set_mario_action(m, ACT_FREEFALL, 0); + #else + return drop_and_set_mario_action(m, ACT_FREEFALL, 0); + #endif } if (m->input & INPUT_ABOVE_SLIDE) { diff --git a/src/game/mario_step.c b/src/game/mario_step.c index ba8315ca1..22cf59167 100644 --- a/src/game/mario_step.c +++ b/src/game/mario_step.c @@ -8,6 +8,9 @@ #include "game_init.h" #include "interaction.h" #include "mario_step.h" +#ifdef QOL_FIXES +#include "object_list_processor.h" +#endif static s16 sMovingSandSpeeds[] = { 12, 8, 4, 0 }; @@ -16,6 +19,10 @@ struct Surface gWaterSurfacePseudoFloor = { { 0.0f, 1.0f, 0.0f }, 0.0f, NULL, }; +#ifdef QOL_FIXES +static struct Object *sTrampoline; +#endif + /** * Always returns zero. This may have been intended * to be used for the beta trampoline. Its return value @@ -27,7 +34,11 @@ struct Surface gWaterSurfacePseudoFloor = { * and if so return a higher value than 0. */ f32 get_additive_y_vel_for_jumps(void) { + #ifndef QOL_FIXES return 0.0f; + #else + return (sTrampoline != NULL) ? sTrampoline->oBetaTrampolineAdditiveYVel : 0.0f; + #endif } /** @@ -50,6 +61,9 @@ void stub_mario_step_1(UNUSED struct MarioState *x) { * or to set a variable with its intended additive Y vel. */ void stub_mario_step_2(void) { + #ifdef QOL_FIXES + sTrampoline = gCurrentObject; + #endif } void transfer_bully_speed(struct BullyCollisionData *obj1, struct BullyCollisionData *obj2) { @@ -57,8 +71,27 @@ void transfer_bully_speed(struct BullyCollisionData *obj1, struct BullyCollision f32 rz = obj2->posZ - obj1->posZ; //! Bully NaN crash + #ifndef QOL_FIXES f32 projectedV1 = (rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz); f32 projectedV2 = (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz); + #else + f32 projectedV1 = 0.0f; + f32 projectedV2 = 0.0f; + if ((rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz) != NAN + && (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz) != NAN) { + projectedV1 = (rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz); + projectedV2 = (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz); + } else if ((rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz) == NAN) { + projectedV1 = 0.0f; + projectedV2 = (-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz); + } else if ((-rx * obj2->velX - rz * obj2->velZ) / (rx * rx + rz * rz) == NAN) { + projectedV1 = (rx * obj1->velX + rz * obj1->velZ) / (rx * rx + rz * rz); + projectedV2 = 0.0f; + } else { + projectedV1 = 0.0f; + projectedV2 = 0.0f; + } + #endif // Kill speed along r. Convert one object's speed along r and transfer it to // the other object. @@ -281,7 +314,12 @@ static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) { if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) { floorHeight = waterLevel; floor = &gWaterSurfacePseudoFloor; + #ifndef QOL_FIXES floor->originOffset = floorHeight; //! Wrong origin offset (no effect) + #else + // this might have been waterLevel instead + floor->originOffset = waterLevel; + #endif } if (nextPos[1] > floorHeight + 100.0f) { @@ -424,7 +462,12 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr if ((m->action & ACT_FLAG_RIDING_SHELL) && floorHeight < waterLevel) { floorHeight = waterLevel; floor = &gWaterSurfacePseudoFloor; + #ifndef QOL_FIXES floor->originOffset = floorHeight; //! Incorrect origin offset (no effect) + #else + // this might have been waterLevel instead + floor->originOffset = waterLevel; + #endif } //! This check uses f32, but findFloor uses short (overflow jumps) @@ -439,6 +482,11 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr //! When ceilHeight - floorHeight <= 160, the step result says that // Mario landed, but his movement is cancelled and his referenced floor // isn't updated (pedro spots) + #ifdef QOL_FIXES + m->pos[0] = nextPos[0]; + m->pos[2] = nextPos[2]; + m->floor = floor; + #endif m->pos[1] = floorHeight; return AIR_STEP_LANDED; } diff --git a/src/game/memory.c b/src/game/memory.c index 14862ccac..ca0d42235 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -222,7 +222,7 @@ u32 main_pool_pop_state(void) { * function blocks until completion. */ static void dma_read(u8 *dest, u8 *srcStart, u8 *srcEnd) { - u32 size = ALIGN16(srcEnd - srcStart); + UNUSED u32 size = ALIGN16(srcEnd - srcStart); memcpy(dest, srcStart, srcEnd - srcStart); } diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index 601c45f14..ed16bdb77 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -182,7 +182,9 @@ s32 turn_obj_away_from_steep_floor(struct Surface *objFloor, f32 floorY, f32 obj if (objFloor == NULL) { //! (OOB Object Crash) TRUNC overflow exception after 36 minutes + #ifndef QOL_FIXES o->oMoveAngleYaw += 32767.999200000002; /* ¯\_(ツ)_/¯ */ + #endif return FALSE; } @@ -283,7 +285,11 @@ void calc_new_obj_vel_and_pos_y(struct Surface *objFloor, f32 objFloorY, f32 obj } //! (Obj Position Crash) If you got an object with height past 2^31, the game would crash. + #ifndef QOL_FIXES if ((s32) o->oPosY >= (s32) objFloorY && (s32) o->oPosY < (s32) objFloorY + 37) { + #else + if ((s64) o->oPosY >= (s64) objFloorY && (s64) o->oPosY < (s64) objFloorY + 37) { + #endif obj_orient_graph(o, floor_nX, floor_nY, floor_nZ); // Adds horizontal component of gravity for horizontal speed. @@ -525,12 +531,16 @@ s32 is_point_close_to_object(struct Object *obj, f32 x, f32 y, f32 z, s32 dist) /** * Sets an object as visible if within a certain distance of Mario's graphical position. */ +#ifndef NODRAWINGDISTANCE void set_object_visibility(struct Object *obj, s32 dist) { +#else +void set_object_visibility(struct Object *obj, UNUSED s32 dist) { +#endif +#ifndef NODRAWINGDISTANCE f32 objX = obj->oPosX; f32 objY = obj->oPosY; f32 objZ = obj->oPosZ; -#ifndef NODRAWINGDISTANCE if (is_point_within_radius_of_mario(objX, objY, objZ, dist) == TRUE) { #endif obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; @@ -720,6 +730,9 @@ void obj_check_floor_death(s16 collisionFlags, struct Surface *floor) { o->oAction = OBJ_ACT_LAVA_DEATH; break; //! @BUG Doesn't check for the vertical wind death floor. + #ifdef QOL_FIXES + case SURFACE_VERTICAL_WIND: + #endif case SURFACE_DEATH_PLANE: o->oAction = OBJ_ACT_DEATH_PLANE_DEATH; break; diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index 28461d5df..511f062ec 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -564,7 +564,11 @@ static s32 obj_resolve_object_collisions(s32 *targetYaw) { dx = otherObject->oPosX - o->oPosX; dz = otherObject->oPosZ - o->oPosZ; + #ifndef QOL_FIXES angle = atan2s(dx, dz); //! This should be atan2s(dz, dx) + #else + angle = atan2s(dz, dx); + #endif radius = o->hitboxRadius; otherRadius = otherObject->hitboxRadius; @@ -628,8 +632,10 @@ static void obj_die_if_health_non_positive(void) { } else { obj_spawn_loot_yellow_coins(o, o->oNumLootCoins, 20.0f); } + #ifndef QOL_FIXES // This doesn't do anything obj_spawn_loot_yellow_coins(o, o->oNumLootCoins, 20.0f); + #endif if (o->oHealth < 0) { cur_obj_hide(); @@ -640,7 +646,11 @@ static void obj_die_if_health_non_positive(void) { } } +#ifndef TARGET_WEB static void obj_unused_die(void) { +#else +UNUSED static void obj_unused_die(void) { +#endif o->oHealth = 0; obj_die_if_health_non_positive(); } diff --git a/src/game/object_collision.c b/src/game/object_collision.c index 71f3268b9..22df9d69f 100644 --- a/src/game/object_collision.c +++ b/src/game/object_collision.c @@ -56,6 +56,9 @@ int detect_object_hitbox_overlap(struct Object *a, struct Object *b) { return 1; } +#if defined(QOL_FIXES) || defined(TARGET_WEB) + return 0; +#endif //! no return value } @@ -88,6 +91,9 @@ int detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { return 1; } +#if defined(QOL_FIXES) || defined(TARGET_WEB) + return 0; +#endif //! no return value } diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 22b45b322..b104701cb 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -1261,6 +1261,9 @@ static s32 cur_obj_move_xz(f32 steepSlopeNormalY, s32 careAboutEdgesAndSteepSlop o->oPosZ = intendedZ; //! Returning FALSE but moving anyway (not exploitable; return value is // never used) + #ifdef QOL_FIXES + return TRUE; + #endif } // We are likely trying to move onto a steep upward slope @@ -1387,7 +1390,11 @@ void cur_obj_move_y(f32 gravity, f32 bounciness, f32 buoyancy) { } } +#ifndef TARGET_WEB static void stub_obj_helpers_1(void) { +#else +UNUSED static void stub_obj_helpers_1(void) { +#endif } static s32 clear_move_flag(u32 *bitSet, s32 flag) { @@ -1748,8 +1755,12 @@ static void cur_obj_update_floor(void) { o->oMoveFlags |= OBJ_MOVE_ABOVE_LAVA; } #ifndef VERSION_JP + #ifndef QOL_FIXES else if (floor->type == SURFACE_DEATH_PLANE) { //! This misses SURFACE_VERTICAL_WIND (and maybe SURFACE_WARP) + #else + else if (floor->type == SURFACE_DEATH_PLANE || floor->type == SURFACE_VERTICAL_WIND || floor->type == SURFACE_WARP) { + #endif o->oMoveFlags |= OBJ_MOVE_ABOVE_DEATH_BARRIER; } #endif @@ -2247,7 +2258,11 @@ void bhv_dust_smoke_loop(void) { o->oSmokeTimer++; } +#ifndef TARGET_WEB static void stub_obj_helpers_2(void) { +#else +UNUSED static void stub_obj_helpers_2(void) { +#endif } s32 cur_obj_set_direction_table(s8 *a0) { @@ -2273,7 +2288,11 @@ s32 cur_obj_progress_direction_table(void) { return spF; } +#ifndef TARGET_WEB void stub_obj_helpers_3(UNUSED s32 sp0, UNUSED s32 sp4) { +#else +UNUSED void stub_obj_helpers_3(UNUSED s32 sp0, UNUSED s32 sp4) { +#endif } void cur_obj_scale_over_time(s32 a0, s32 a1, f32 sp10, f32 sp14) { @@ -2300,7 +2319,11 @@ void cur_obj_set_pos_to_home_with_debug(void) { cur_obj_scale(gDebugInfo[5][3] / 100.0f + 1.0l); } +#ifndef TARGET_WEB void stub_obj_helpers_4(void) { +#else +UNUSED void stub_obj_helpers_4(void) { +#endif } s32 cur_obj_is_mario_on_platform(void) { @@ -2395,7 +2418,11 @@ s32 is_item_in_array(s8 item, s8 *array) { return FALSE; } +#ifndef TARGET_WEB static void stub_obj_helpers_5(void) { +#else +UNUSED static void stub_obj_helpers_5(void) { +#endif } void bhv_init_room(void) { @@ -2590,6 +2617,7 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s UNUSED s32 doneTurning = TRUE; switch (o->oDialogState) { +#ifndef QOL_FIXES #ifdef VERSION_JP case DIALOG_UNK1_ENABLE_TIME_STOP: //! We enable time stop even if Mario is not ready to speak. This @@ -2601,6 +2629,20 @@ s32 cur_obj_update_dialog(s32 actionArg, s32 dialogFlags, s32 dialogID, UNUSED s o->oDialogState++; } break; +#else + case DIALOG_UNK1_ENABLE_TIME_STOP: + // Patched :( + // Wait for Mario to be ready to speak, and then enable time stop + if (mario_ready_to_speak() || gMarioState->action == ACT_READING_NPC_DIALOG) { + gTimeStopState |= TIME_STOP_ENABLED; + o->activeFlags |= ACTIVE_FLAG_INITIATED_TIME_STOP; + o->oDialogState++; + } else { + break; + } + // Fall through so that Mario's action is interrupted immediately + // after time is stopped +#endif #else case DIALOG_UNK1_ENABLE_TIME_STOP: // Patched :( @@ -2667,7 +2709,7 @@ s32 cur_obj_update_dialog_with_cutscene(s32 actionArg, s32 dialogFlags, s32 cuts s32 doneTurning = TRUE; switch (o->oDialogState) { -#ifdef VERSION_JP +#if (defined(VERSION_JP) && !defined(QOL_FIXES)) case DIALOG_UNK2_ENABLE_TIME_STOP: //! We enable time stop even if Mario is not ready to speak. This // allows us to move during time stop as long as Mario never enters diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 7113e7c81..c8c4e3132 100644 --- a/src/game/object_list_processor.c +++ b/src/game/object_list_processor.c @@ -460,7 +460,7 @@ void spawn_objects_from_info(UNUSED s32 unused, struct SpawnInfo *spawnInfo) { //! (Spawning Displacement) On the Japanese version, Mario's platform object // isn't cleared when transitioning between areas. This can cause Mario to // receive displacement after spawning. -#ifndef VERSION_JP +#if BUGFIX_SPAWNING_DISPLACEMENT clear_mario_platform(); #endif @@ -563,7 +563,11 @@ void clear_objects(void) { void update_terrain_objects(void) { gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SPAWNER]); //! This was meant to be += + #ifdef QOL_FIXES + gObjectCounter += update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]); + #else gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]); + #endif } /** @@ -602,7 +606,11 @@ void unload_deactivated_objects(void) { /** * Unused profiling function. */ +#ifndef TARGET_WEB static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) { +#else +UNUSED static u16 unused_get_elapsed_time(u64 *cycleCounts, s32 index) { +#endif u16 time; f64 cycles; diff --git a/src/game/options_menu.c b/src/game/options_menu.c index 56ebdebea..d858b2857 100644 --- a/src/game/options_menu.c +++ b/src/game/options_menu.c @@ -62,7 +62,11 @@ static const u8 menuStr[][32] = { { TEXT_OPT_CHEATS }, }; +#ifndef TARGET_WEB static const u8 optsCameraStr[][32] = { +#else +UNUSED static const u8 optsCameraStr[][32] = { +#endif { TEXT_OPT_CAMX }, { TEXT_OPT_CAMY }, { TEXT_OPT_INVERTX }, @@ -134,7 +138,11 @@ static const u8 *filterChoices[] = { optsVideoStr[8], }; +#ifndef TARGET_WEB static const u8 *vsyncChoices[] = { +#else +UNUSED static const u8 *vsyncChoices[] = { +#endif toggleStr[0], toggleStr[1], optsVideoStr[6], diff --git a/src/game/paintings.c b/src/game/paintings.c index 6cae19c02..cea1ec160 100644 --- a/src/game/paintings.c +++ b/src/game/paintings.c @@ -16,6 +16,9 @@ #include "paintings.h" #include "save_file.h" #include "segment2.h" +#ifdef QOL_FIXES +#include "include/libc/math.h" +#endif /** * @file paintings.c @@ -214,10 +217,19 @@ void stop_other_paintings(s16 *idptr, struct Painting *paintingGroup[]) { f32 painting_mario_y(struct Painting *painting) { //! Unnecessary use of double constants // Add 50 to make the ripple closer to Mario's center of mass. + #ifndef QOL_FIXES f32 relY = gPaintingMarioYPos - painting->posY + 50.0; + #else + f32 relY = gPaintingMarioYPos - painting->posY + 50.0f; + #endif + #ifndef QOL_FIXES if (relY < 0.0) { relY = 0.0; + #else + if (relY < 0.0f) { + relY = 0.0f; + #endif } else if (relY > painting->size) { relY = painting->size; } @@ -254,6 +266,9 @@ f32 painting_ripple_y(struct Painting *painting, s8 ySource) { return painting->size / 2.0; // some concentric ripples don't care about Mario break; } + #ifdef TARGET_WEB + return 0; + #endif } /** @@ -278,7 +293,13 @@ f32 painting_nearest_4th(struct Painting *painting) { return secondQuarter; } else if (painting->floorEntered & ENTER_RIGHT) { return thirdQuarter; + #ifndef TARGET_WEB } + #else + } else { + return 0; + } + #endif } /** @@ -310,6 +331,9 @@ f32 painting_ripple_x(struct Painting *painting, s8 xSource) { return painting->size / 2.0; break; } + #ifdef TARGET_WEB + return 0; + #endif } /** @@ -578,7 +602,15 @@ void painting_update_ripple_state(struct Painting *painting) { //! 16777216 (1 << 24), at which point it will freeze (due to floating-point //! imprecision?) and the painting will stop rippling. This happens to HMC, DDD, and //! CotMC. This happens on Wii VC. Untested on N64 and Wii U VC. + #ifndef QOL_FIXES painting->rippleTimer += 1.0; + #else + if (painting->rippleTimer >= 16777216.0) { + painting->rippleTimer = 0.0; + } else { + painting->rippleTimer += 1.0; + } + #endif } if (painting->rippleTrigger == RIPPLE_TRIGGER_PROXIMITY) { // if the painting is barely rippling, make it stop rippling @@ -633,7 +665,11 @@ s16 calculate_ripple_at_point(struct Painting *painting, f32 posX, f32 posY) { } else { // use a cosine wave to make the ripple go up and down, // scaled by the painting's ripple magnitude + #ifndef QOL_FIXES f32 rippleZ = rippleMag * cosf(rippleRate * (2 * M_PI) * (rippleTimer - rippleDistance)); + #else + f32 rippleZ = rippleMag * cosf(rippleRate * (2 * M__PI) * (rippleTimer - rippleDistance)); + #endif // round it to an int and return it return round_float(rippleZ); diff --git a/src/game/platform_displacement.c b/src/game/platform_displacement.c index 29a741c23..7de6d335c 100644 --- a/src/game/platform_displacement.c +++ b/src/game/platform_displacement.c @@ -177,6 +177,7 @@ void apply_mario_platform_displacement(void) { } } +#ifndef QOL_FIXES #ifndef VERSION_JP /** * Set Mario's platform to NULL. @@ -185,3 +186,11 @@ void clear_mario_platform(void) { gMarioPlatform = NULL; } #endif +#else +/** + * Set Mario's platform to NULL. + */ +void clear_mario_platform(void) { + gMarioPlatform = NULL; +} +#endif diff --git a/src/game/platform_displacement.h b/src/game/platform_displacement.h index 556192b50..9cd3fdb9f 100644 --- a/src/game/platform_displacement.h +++ b/src/game/platform_displacement.h @@ -10,8 +10,12 @@ void get_mario_pos(f32 *x, f32 *y, f32 *z); void set_mario_pos(f32 x, f32 y, f32 z); void apply_platform_displacement(u32 isMario, struct Object *platform); void apply_mario_platform_displacement(void); +#ifndef QOL_FIXES #ifndef VERSION_JP void clear_mario_platform(void); #endif +#else +void clear_mario_platform(void); +#endif #endif // PLATFORM_DISPLACEMENT_H diff --git a/src/game/profiler.c b/src/game/profiler.c index 9f968c6a7..53feeedf0 100644 --- a/src/game/profiler.c +++ b/src/game/profiler.c @@ -79,12 +79,21 @@ void draw_profiler_bar(OSTime clockBase, OSTime clockStart, OSTime clockEnd, s16 //! I believe this is supposed to cap rectX1 and rectX2 to 320, but the // code seems to use the wrong variables... it's possible that the variable // names were very similar within a single letter. + #ifndef QOL_FIXES if (rectX1 > 319) { clockStart = 319; } if (rectX2 > 319) { clockEnd = 319; } + #else + if (rectX1 > 320) { + rectX1 = 320; + } + if (rectX2 > 320) { + rectX2 = 320; + } + #endif // perform the render if start is less than end. in most cases, it should be. if (rectX1 < rectX2) { @@ -261,7 +270,11 @@ void draw_profiler_mode_0(void) { // potentially be passed to draw_profiler_bar, because it could be sending // pairs that are beyond the numVblankTimes enforced non-odd limit, due to // using the wrong num value. + #ifndef QOL_FIXES for (i = 0; i < profiler->numSoundTimes; i += 2) { + #else + for (i = 0; i < profiler->numVblankTimes; i += 2) { + #endif vblank += (profiler->vblankTimes[i + 1] - profiler->vblankTimes[i]); } diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index d5bf57784..48c2fee94 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -760,8 +760,13 @@ static int obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO; if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) { + #ifndef QOL_FIXES cullingRadius = (f32)((struct GraphNodeCullingRadius *) geo)->cullingRadius; //! Why is there a f32 cast? + #else + cullingRadius = + ((struct GraphNodeCullingRadius *) geo)->cullingRadius; + #endif } else { cullingRadius = 300; } diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c index b49ddaf55..e5e3ec4f2 100644 --- a/src/game/screen_transition.c +++ b/src/game/screen_transition.c @@ -239,6 +239,9 @@ int render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct Wa return render_textured_transition(fadeTimer, transTime, transData, TEX_TRANS_BOWSER, TRANS_TYPE_MIRROR); break; } + #ifdef TARGET_WEB + return 0; + #endif } Gfx *render_cannon_circle_base(void) { diff --git a/src/game/shadow.c b/src/game/shadow.c index 324400e5c..7be1db4ae 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -1,6 +1,9 @@ #include #include #include +#ifdef QOL_FIXES +#include "include/libc/math.h" +#endif #include "engine/math_util.h" #include "engine/surface_collision.h" @@ -190,6 +193,9 @@ f32 get_water_level_below_shadow(struct Shadow *s) { } //! @bug Missing return statement. This compiles to return `waterLevel` //! incidentally. +#if defined(QOL_FIXES) || defined(TARGET_WEB) + return waterLevel; +#endif } /** @@ -214,6 +220,11 @@ s8 init_shadow(struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, if (gEnvironmentRegions != 0) { waterLevel = get_water_level_below_shadow(s); } +#ifdef QOL_FIXES + else { + waterLevel = 0; + } +#endif if (gShadowAboveWaterOrLava) { //! @bug Use of potentially undefined variable `waterLevel` s->floorHeight = waterLevel; @@ -358,8 +369,13 @@ void get_vertex_coords(s8 index, s8 shadowVertexType, s8 *xCoord, s8 *zCoord) { */ void calculate_vertex_xyz(s8 index, struct Shadow s, f32 *xPosVtx, f32 *yPosVtx, f32 *zPosVtx, s8 shadowVertexType) { + #ifndef QOL_FIXES f32 tiltedScale = cosf(s.floorTilt * M_PI / 180.0) * s.shadowScale; f32 downwardAngle = s.floorDownwardAngle * M_PI / 180.0; + #else + f32 tiltedScale = cosf(s.floorTilt * M__PI / 180.0) * s.shadowScale; + f32 downwardAngle = s.floorDownwardAngle * M__PI / 180.0; + #endif f32 halfScale; f32 halfTiltedScale; s8 xCoordUnit; diff --git a/src/game/skybox.c b/src/game/skybox.c index 09deeaf05..98090a5c4 100644 --- a/src/game/skybox.c +++ b/src/game/skybox.c @@ -139,7 +139,11 @@ f32 calculate_skybox_scaled_x(s8 player, f32 fov) { f32 yaw = sSkyBoxInfo[player].yaw; //! double literals are used instead of floats + #ifndef QOL_FIXES f32 scaledX = SCREEN_WIDTH * 360.0 * yaw / (fov * 65536.0); + #else + f32 scaledX = SCREEN_WIDTH * 360.0f * yaw / (fov * 65536.0f); + #endif if (scaledX > SKYBOX_WIDTH) { scaledX -= (s32) scaledX / SKYBOX_WIDTH * SKYBOX_WIDTH; diff --git a/src/game/sound_init.c b/src/game/sound_init.c index e86275626..569ceb344 100644 --- a/src/game/sound_init.c +++ b/src/game/sound_init.c @@ -29,7 +29,11 @@ static u16 sCurrentMusic = MUSIC_NONE; static u16 sCurrentShellMusic = MUSIC_NONE; static u16 sCurrentCapMusic = MUSIC_NONE; static u8 sPlayingInfiniteStairs = FALSE; +#ifndef TARGET_WEB static u8 unused8032C6D8[16] = { 0 }; +#else +UNUSED static u8 unused8032C6D8[16] = { 0 }; +#endif static s16 sSoundMenuModeToSoundMode[] = { SOUND_MODE_STEREO, SOUND_MODE_MONO, SOUND_MODE_HEADSET }; // Only the 20th array element is used. static u32 menuSoundsExtra[] = { diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index ee77f564b..dcf1ab838 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -162,7 +162,11 @@ void clear_object_lists(struct ObjectNode *objLists) { /** * Delete the leaf graph nodes under obj and obj's siblings. */ +#ifndef TARGET_WEB static void unused_delete_leaf_nodes(struct Object *obj) { +#else +UNUSED static void unused_delete_leaf_nodes(struct Object *obj) { +#endif struct Object *children; struct Object *sibling; struct Object *obj0 = obj; diff --git a/src/goddard/debug_utils.c b/src/goddard/debug_utils.c index 10984bbbb..b7ca1b5ef 100644 --- a/src/goddard/debug_utils.c +++ b/src/goddard/debug_utils.c @@ -410,9 +410,19 @@ void fatal_printf(const char *fmt, ...) { case 's': gd_printf("%s", va_arg(vl, char *)); break; + #ifndef TARGET_WEB case 'c': + #ifndef QOL_FIXES gd_printf("%c", va_arg(vl, char)); + #else + gd_printf("%c", va_arg(vl, int)); + #endif break; + #else + case 'c': + gd_printf("%c", va_arg(vl, int)); + break; + #endif case 'x': gd_printf("%x", va_arg(vl, s32)); break; diff --git a/src/goddard/draw_objects.c b/src/goddard/draw_objects.c index e6d24d28e..b64d6e1bd 100644 --- a/src/goddard/draw_objects.c +++ b/src/goddard/draw_objects.c @@ -61,7 +61,11 @@ static struct GdColour sClrYellow = { 1.0, 1.0, 0.0 }; // @ 801A80DC static struct GdColour sLightColours[1] = { { 1.0, 1.0, 0.0 } }; // @ 801A80E8 static struct GdColour *sSelectedColour = &sClrRed; // @ 801A80F4 struct ObjCamera *gViewUpdateCamera = NULL; // @ 801A80F8 +#ifndef TARGET_WEB static void *sUnref801A80FC = NULL; +#else +UNUSED static void *sUnref801A80FC = NULL; +#endif static s32 sUnreadShapeFlag = 0; // @ 801A8100 struct GdColour *sColourPalette[5] = { // @ 801A8104 &sClrWhite, &sClrYellow, &sClrRed, &sClrBlack, &sClrBlack @@ -71,20 +75,36 @@ struct GdColour *sWhiteBlack[2] = { &sClrWhite, &sClrBlack, }; +#ifndef TARGET_WEB static Mat4f sUnref801A8120 = { +#else +UNUSED static Mat4f sUnref801A8120 = { +#endif { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 } }; +#ifndef TARGET_WEB static Mat4f sUnrefIden801A8160 = { +#else +UNUSED static Mat4f sUnrefIden801A8160 = { +#endif { 1.0, 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 0.0 }, { 0.0, 0.0, 0.0, 1.0 } }; static s32 sLightDlCounter = 1; // @ 801A81A0 +#ifndef TARGET_WEB static s32 sUnref801A81A4[4] = { 0 }; +#else +UNUSED static s32 sUnref801A81A4[4] = { 0 }; +#endif // bss u8 gUnref_801B9B30[0x88]; struct ObjGroup *gGdLightGroup; // @ 801B9BB8; is this the main light group? only light group? +#ifndef TARGET_WEB static u8 sUnref_801B9BBC[0x40]; +#else +UNUSED static u8 sUnref_801B9BBC[0x40]; +#endif static enum SceneType sSceneProcessType; // @ 801B9C00 static s32 sUseSelectedColor; // @ 801B9C04 static s16 sPickBuffer[100]; ///< buffer of objects near click @@ -457,9 +477,11 @@ void draw_face(struct ObjFace *face) { } } } + #ifndef QOL_FIXES if (FALSE) { } + #endif } check_tri_display(face->vtxCount); diff --git a/src/goddard/dynlist_proc.c b/src/goddard/dynlist_proc.c index 7621f0e08..f2b0de36d 100644 --- a/src/goddard/dynlist_proc.c +++ b/src/goddard/dynlist_proc.c @@ -2952,7 +2952,9 @@ void d_set_matrix(Mat4f *src) { gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128); //! @bug When setting an `ObjNet` matrix, the source is copied twice //! due to a probable copy-paste line repeat error + #ifndef QOL_FIXES gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128); + #endif break; case OBJ_TYPE_JOINTS: gd_copy_mat4f(src, &((struct ObjJoint *) sDynListCurObj)->matE8); diff --git a/src/goddard/gd_main.c b/src/goddard/gd_main.c index bdf5b8a62..9d2d8a102 100644 --- a/src/goddard/gd_main.c +++ b/src/goddard/gd_main.c @@ -14,11 +14,20 @@ // data s32 gGdMoveScene = TRUE; // @ 801A8050 +#ifndef TARGET_WEB static s32 sUnref801A8054 = TRUE; +#else +UNUSED static s32 sUnref801A8054 = TRUE; +#endif f32 D_801A8058 = -600.0f; s32 gGdUseVtxNormal = TRUE; // @ 801A805C; instead of face normals +#ifndef TARGET_WEB static s32 sUnrefScnWidth = 320; static s32 sUnrefScnHeight = 240; +#else +UNUSED static s32 sUnrefScnWidth = 320; +UNUSED static s32 sUnrefScnHeight = 240; +#endif // bss struct GdControl gGdCtrl; // @ 801B9920; processed controller info diff --git a/src/goddard/gd_math.c b/src/goddard/gd_math.c index 0050a7535..c8a95c1eb 100644 --- a/src/goddard/gd_math.c +++ b/src/goddard/gd_math.c @@ -692,7 +692,11 @@ void UNUSED gd_create_quat_rot_mat(f32 quat[4], UNUSED s32 unused, Mat4f *mtx) { //! latter portions remain what they were originally. Perhaps this was meant //! to call gd_create_neg_vec_zero_first_mat_row? (*mtx)[0][0] = 1.0f; + #ifndef QOL_FIXES gd_shift_mat_up(mtx); + #else + gd_create_neg_vec_zero_first_mat_row(mtx, 0, 0, 0, 0); + #endif } /** diff --git a/src/goddard/old_menu.c b/src/goddard/old_menu.c index f62694380..f95ee3fb0 100644 --- a/src/goddard/old_menu.c +++ b/src/goddard/old_menu.c @@ -23,7 +23,11 @@ // bss static char sMenuStrBuf[0x100]; static struct GdVec3f sStaticVec; +#ifndef TARGET_WEB static struct GdVec3f unusedVec; +#else +UNUSED static struct GdVec3f unusedVec; +#endif static struct ObjGadget *sCurGadgetPtr; // forward declarations diff --git a/src/goddard/particles.c b/src/goddard/particles.c index aa353b9b9..ccd7504c3 100644 --- a/src/goddard/particles.c +++ b/src/goddard/particles.c @@ -26,7 +26,11 @@ struct Connection { }; // data +#ifndef TARGET_WEB static void *sUnused801A81D0 = NULL; +#else +UNUSED static void *sUnused801A81D0 = NULL; +#endif static s32 D_801A81D4[25] = { /* ID? X Y Z */ 9, 3, 12, -14, 25, 5, 16, -25, 42, 4, 15, -39, 55, diff --git a/src/goddard/renderer.c b/src/goddard/renderer.c index 3d2a8356d..b2d1a3e69 100644 --- a/src/goddard/renderer.c +++ b/src/goddard/renderer.c @@ -97,7 +97,11 @@ u8 EUpad2[0x64]; static OSMesg sGdMesgBuf[1]; // @ 801BE944 u8 EUpad3[0x34]; static OSMesg D_801BE97C; // msg buf for D_801BE8B0 queue +#ifndef TARGET_WEB static OSIoMesg D_801BE980; +#else +UNUSED static OSIoMesg D_801BE980; +#endif static struct ObjView *D_801BE994; // store if View flag 0x40 set u8 EUpad4[0x88]; @@ -110,10 +114,18 @@ static u8 D_801BAEA0; static struct ObjGadget *sTimerGadgets[GD_NUM_TIMERS]; // @ 801BAEA8 static u32 D_801BAF28; // RAM addr offset? static s16 D_801BAF30[13][8]; // [[s16; 8]; 13]? vert indices? +#ifndef TARGET_WEB static u32 unref_801bb000[3]; +#else +UNUSED static u32 unref_801bb000[3]; +#endif static u8 *sMemBlockPoolBase; // @ 801BB00C static u32 sAllocMemory; // @ 801BB010; malloc-ed bytes +#ifndef TARGET_WEB static u32 unref_801bb014; +#else +UNUSED static u32 unref_801bb014; +#endif static s32 D_801BB018; static s32 D_801BB01C; static void *D_801BB020[0x10]; // texture pointers @@ -133,11 +145,23 @@ static s32 D_801BB0CC; // Vtx start in GD Dl static struct ObjView *sCarSceneView; // @ 801BB0D0 static s32 sUpdateYoshiScene; // @ 801BB0D4; update dl Vtx from ObjVertex? static s32 sUpdateMarioScene; // @ 801BB0D8; update dl Vtx from ObjVertex? +#ifndef TARGET_WEB static u32 unref_801bb0dc; +#else +UNUSED static u32 unref_801bb0dc; +#endif static s32 sUpdateCarScene; // @ 801BB0E0; guess, not really used +#ifndef TARGET_WEB static u32 unref_801bb0e4; +#else +UNUSED static u32 unref_801bb0e4; +#endif static struct GdVec3f D_801BB0E8; +#ifndef TARGET_WEB static u32 unref_801bb0f8[2]; +#else +UNUSED static u32 unref_801bb0f8[2]; +#endif static Mtx sIdnMtx; // @ 801BB100 static Mat4f sInitIdnMat4; // @ 801BB140 static s8 sVtxCvrtNormBuf[3]; // @ 801BB180 @@ -168,21 +192,45 @@ static LookAt D_801BE7D0[3]; #ifndef VERSION_EU static OSMesgQueue D_801BE830; // controller msg queue static OSMesg D_801BE848[10]; +#ifndef TARGET_WEB static u32 unref_801be870[16]; +#else +UNUSED static u32 unref_801be870[16]; +#endif static OSMesgQueue D_801BE8B0; static OSMesgQueue sGdDMAQueue; // @ 801BE8C8 +#ifndef TARGET_WEB static u32 unref_801be8e0[25]; +#else +UNUSED static u32 unref_801be8e0[25]; +#endif static OSMesg sGdMesgBuf[1]; // @ 801BE944 +#ifndef TARGET_WEB static u32 unref_801be948[13]; +#else +UNUSED static u32 unref_801be948[13]; +#endif static OSMesg D_801BE97C; // msg buf for D_801BE8B0 queue +#ifndef TARGET_WEB static OSIoMesg D_801BE980; +#else +UNUSED static OSIoMesg D_801BE980; +#endif static struct ObjView *D_801BE994; // store if View flag 0x40 set #endif // data +#ifndef TARGET_WEB static u32 unref_801a8670 = 0; +#else +UNUSED static u32 unref_801a8670 = 0; +#endif static s32 D_801A8674 = 0; +#ifndef TARGET_WEB static u32 unref_801a8678 = 0; +#else +UNUSED static u32 unref_801a8678 = 0; +#endif static s32 D_801A867C = 0; static s32 D_801A8680 = 0; static f32 sTracked1FrameTime = 0.0f; // @ 801A8684 @@ -197,11 +245,19 @@ static struct GdTimer *D_801A86A4 = NULL; // timer for dlgen, dynamics, or rcp static struct GdTimer *D_801A86A8 = NULL; // timer for dlgen, dynamics, or rcp static struct GdTimer *D_801A86AC = NULL; // timer for dlgen, dynamics, or rcp s32 gGdFrameBuf = 0; // @ 801A86B0 +#ifndef TARGET_WEB static u32 unref_801a86B4 = 0; +#else +UNUSED static u32 unref_801a86B4 = 0; +#endif static struct ObjShape *sHandShape = NULL; // @ 801A86B8 static s32 D_801A86BC = 1; static s32 D_801A86C0 = 0; // gd_dl id for something? +#ifndef TARGET_WEB static u32 unref_801a86C4 = 10; +#else +UNUSED static u32 unref_801a86C4 = 10; +#endif static s32 sMtxParamType = G_MTX_PROJECTION; static struct GdVec3f D_801A86CC = { 1.0f, 1.0f, 1.0f }; static struct ObjView *sActiveView = NULL; // @ 801A86D8 current view? used when drawing dl @@ -212,10 +268,18 @@ static struct ObjView *sMenuView = NULL; // @ 801A86E8 static u32 sItemsInMenu = 0; // @ 801A86EC static s32 D_801A86F0 = 0; // frame buffer idx into D_801BD7A0? static s32 sNewZPresses = 0; // @ 801A86F4; timing activate cool down counter? +#ifndef TARGET_WEB static u32 unref_801a86F8 = 0; +#else +UNUSED static u32 unref_801a86F8 = 0; +#endif static struct GdDisplayList *sCurrentGdDl = NULL; // @ 801A86FC static u32 sGdDlCount = 0; // @ 801A8700 +#ifndef TARGET_WEB static struct DynListBankInfo sDynLists[] = { // @ 801A8704 +#else +UNUSED static struct DynListBankInfo sDynLists[] = { // @ 801A8704 +#endif { STD_LIST_BANK, dynlist_test_cube }, { STD_LIST_BANK, dynlist_unused }, { STD_LIST_BANK, dynlist_mario_master }, @@ -223,7 +287,11 @@ static struct DynListBankInfo sDynLists[] = { // @ 801A8704 }; // textures and display list data +#ifndef TARGET_WEB static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728 +#else +UNUSED static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728 +#endif gsSPEndDisplayList(), }; @@ -231,7 +299,11 @@ ALIGNED8 static u8 gd_texture_hand_open[] = { #include "textures/intro_raw/hand_open.rgba16.inc.c" }; +#ifndef TARGET_WEB static Gfx gd_texture2_dummy_aligner1[] = { +#else +UNUSED static Gfx gd_texture2_dummy_aligner1[] = { +#endif gsSPEndDisplayList() }; @@ -492,8 +564,12 @@ ALIGNED8 static u8 gd_texture_sparkle_4[] = { //! No reference to this texture. Two DL's uses the same previous texture // instead of using this texture. -// Fixed via setting TEXTURE_FIX to 1. +// Fixed via setting QOL_FIXES to 1. +#ifndef TARGET_WEB ALIGNED8 static u8 gd_texture_sparkle_5[] = { +#else +UNUSED ALIGNED8 static u8 gd_texture_sparkle_5[] = { +#endif #include "textures/intro_raw/sparkle_5.rgba16.inc.c" }; @@ -569,8 +645,8 @@ static Gfx gd_dl_red_sparkle_4[] = { gsSPBranchList(gd_dl_sparkle), }; -#ifndef TEXTURE_FIX -static Gfx gd_dl_red_sparkle_4_dup[] ={ +#ifndef QOL_FIXES +static Gfx gd_dl_red_sparkle_4_dup[] = { gsDPPipeSync(), gsSPDisplayList(gd_dl_sparkle_red_color), gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_4), // 4 again, correct texture would be 5 @@ -578,7 +654,7 @@ static Gfx gd_dl_red_sparkle_4_dup[] ={ }; #else -static Gfx gd_dl_red_sparkle_5[] ={ +static Gfx gd_dl_red_sparkle_5[] = { gsDPPipeSync(), gsSPDisplayList(gd_dl_sparkle_red_color), gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, gd_texture_sparkle_5), @@ -621,7 +697,7 @@ static Gfx gd_dl_silver_sparkle_4[] = { gsSPBranchList(gd_dl_sparkle), }; -#ifndef TEXTURE_FIX +#ifndef QOL_FIXES static Gfx gd_dl_silver_sparkle_4_dup[] = { gsDPPipeSync(), gsSPDisplayList(gd_dl_sparkle_white_color), @@ -649,7 +725,7 @@ static Gfx *gd_red_sparkle_dl_array[] = { gd_dl_red_sparkle_1, gd_dl_red_sparkle_0, gd_dl_red_sparkle_0, -#ifndef TEXTURE_FIX +#ifndef QOL_FIXES gd_dl_red_sparkle_4_dup, gd_dl_red_sparkle_4_dup, #else @@ -669,7 +745,7 @@ static Gfx *gd_silver_sparkle_dl_array[] = { gd_dl_silver_sparkle_1, gd_dl_silver_sparkle_0, gd_dl_silver_sparkle_0, -#ifndef TEXTURE_FIX +#ifndef QOL_FIXES gd_dl_silver_sparkle_4_dup, gd_dl_silver_sparkle_4_dup, #else @@ -678,7 +754,11 @@ static Gfx *gd_silver_sparkle_dl_array[] = { #endif }; +#ifndef TARGET_WEB static Gfx gd_texture3_dummy_aligner1[] = { +#else +UNUSED static Gfx gd_texture3_dummy_aligner1[] = { +#endif gsSPEndDisplayList(), }; @@ -723,13 +803,25 @@ static Gfx gd_dl_rdp_init[] = { gsSPEndDisplayList(), }; +#ifndef TARGET_WEB static u32 gd_unused_pad1 = 0; +#else +UNUSED static u32 gd_unused_pad1 = 0; +#endif float sGdPerspTimer = 1.0; +#ifndef TARGET_WEB static u32 gd_unused_pad2 = 0; +#else +UNUSED static u32 gd_unused_pad2 = 0; +#endif +#ifndef TARGET_WEB static Gfx gd_texture4_dummy_aligner1[] = { +#else +UNUSED static Gfx gd_texture4_dummy_aligner1[] = { +#endif gsDPPipeSync(), gsSPEndDisplayList(), }; @@ -746,7 +838,11 @@ static Vtx_t gd_unused_mesh_vertex_group2[] = { {{ 3, -7, 0}, 0, { 0, 0}, { 0xFF, 0x00, 0x00, 0xFF}}, }; +#ifndef TARGET_WEB static Gfx gd_dl_unused_mesh[] = { +#else +UNUSED static Gfx gd_dl_unused_mesh[] = { +#endif gsDPPipeSync(), gsDPSetRenderMode(G_RM_OPA_SURF, G_RM_OPA_SURF2), gsSPClearGeometryMode(0xFFFFFFFF), @@ -941,7 +1037,11 @@ void gd_printf(const char *format, ...) { break; case 'c': //! @bug formatter 'c' uses `s32` for va_arg instead of `char` + #ifndef QOL_FIXES *csr = va_arg(args, s32); + #else + *csr = va_arg(args, int); + #endif csr++; *csr = '\0'; break; @@ -1323,8 +1423,10 @@ void *gdm_gettestdl(s32 id) { fatal_printf("gdm_gettestdl(): DL number %d undefined", id); } //! @bug Code treats `sYoshiSceneView` as group; not called in game though + #ifndef QOL_FIXES apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) update_view, (struct ObjGroup *) sYoshiSceneView); + #endif dobj = d_use_obj("yoshi_scene"); gddl = sGdDLArray[((struct ObjView *) dobj)->gdDlNum]; sUpdateYoshiScene = TRUE; @@ -1354,8 +1456,10 @@ void *gdm_gettestdl(s32 id) { fatal_printf("gdm_gettestdl(): DL number %d undefined", id); } //! @bug Code treats `sCarSceneView` as group; not called in game though + #ifndef QOL_FIXES apply_to_obj_types_in_group(OBJ_TYPE_VIEWS, (applyproc_t) update_view, (struct ObjGroup *) sCarSceneView); + #endif dobj = d_use_obj("car_scene"); gddl = sGdDLArray[((struct ObjView *) dobj)->gdDlNum]; sUpdateCarScene = TRUE; @@ -2754,7 +2858,7 @@ s32 setup_view_buffers(const char *name, struct ObjView *view, UNUSED s32 ulx, U //! doesn't use four of its parameters, this function may have //! had a fair amount of its code commented out. In game, the //! returned value is always 0, so the fix returns that value -#ifdef AVOID_UB +#if defined(AVOID_UB) || defined(TARGET_WEB) return 0; #endif } @@ -2781,6 +2885,9 @@ void func_801A43DC(UNUSED struct GdObj *obj) { /* 252BC0 -> 252BE0 */ void *func_801A43F0(UNUSED const char *menufmt, ...) { //! @bug no return; function was stubbed + #ifdef TARGET_WEB + return 0; + #endif } /* 252BE0 -> 252BF0 */ diff --git a/src/goddard/shape_helper.c b/src/goddard/shape_helper.c index adca3b946..2274a6fa8 100644 --- a/src/goddard/shape_helper.c +++ b/src/goddard/shape_helper.c @@ -65,10 +65,22 @@ static struct UnkData sUnref801A835C = { { { 1, 4, &sUnref801A835C }; +#ifndef TARGET_WEB static s32 sUnref801A838C[6] = { 0 }; +#else +UNUSED static s32 sUnref801A838C[6] = { 0 }; +#endif struct ObjShape *D_801A83A4 = NULL; +#ifndef TARGET_WEB static s32 sUnref801A83A8[31] = { 0 }; +#else +UNUSED static s32 sUnref801A83A8[31] = { 0 }; +#endif +#ifndef TARGET_WEB static struct DynList sSimpleDylist[8] = { +#else +UNUSED static struct DynList sSimpleDylist[8] = { +#endif StartList(), StartGroup("simpleg"), MakeDynObj(D_NET, "simple"), @@ -83,17 +95,29 @@ static struct DynList sDynlist801A84E4[3] = { SetFlag(0x1800), StopList(), }; +#ifndef TARGET_WEB static struct DynList sDynlist801A85B3[5] = { +#else +UNUSED static struct DynList sDynlist801A85B3[5] = { +#endif StartList(), JumpToList(sDynlist801A84E4), SetFlag(0x400), SetFriction(0.04, 0.01, 0.01), StopList(), }; +#ifndef TARGET_WEB static struct DynList sDynlist801A85A4[4] = { +#else +UNUSED static struct DynList sDynlist801A85A4[4] = { +#endif StartList(), JumpToList(sDynlist801A84E4), SetFriction(0.04, 0.01, 0.01), StopList(), }; +#ifndef TARGET_WEB static struct DynList sDynlist801A8604[4] = { +#else +UNUSED static struct DynList sDynlist801A8604[4] = { +#endif StartList(), JumpToList(sDynlist801A84E4), SetFriction(0.005, 0.005, 0.005), @@ -102,35 +126,76 @@ static struct DynList sDynlist801A8604[4] = { static f64 D_801A8668 = 0.0; // bss +#ifndef TARGET_WEB static u8 sUnrefSpaceB00[0x2C]; // @ 801BAB00 +#else +UNUSED static u8 sUnrefSpaceB00[0x2C]; // @ 801BAB00 +#endif static struct ObjGroup *sCubeShapeGroup; // @ 801BAB2C +#ifndef TARGET_WEB static u8 sUnrefSpaceB30[0xC]; // @ 801BAB30 +#else +UNUSED static u8 sUnrefSpaceB30[0xC]; // @ 801BAB30 +#endif static struct ObjShape *sCubeShape; // @ 801BAB3C +#ifndef TARGET_WEB static u8 sUnrefSpaceB40[0x8]; // @ 801BAB40 +#else +UNUSED static u8 sUnrefSpaceB40[0x8]; // @ 801BAB40 +#endif static char sGdLineBuf[0x100]; // @ 801BAB48 static s32 sGdLineBufCsr; // @ 801BAC48 static struct GdFile *sGdShapeFile; // @ 801BAC4C static struct ObjShape *sGdShapeListHead; // @ 801BAC50 static u32 sGdShapeCount; // @ 801BAC54 +#ifndef TARGET_WEB static u8 sUnrefSpaceC58[0x8]; // @ 801BAC58 +#else +UNUSED static u8 sUnrefSpaceC58[0x8]; // @ 801BAC58 +#endif static struct GdVec3f D_801BAC60; +#ifndef TARGET_WEB static u32 sUnrefSpaceC6C; // @ 801BAC6C static u32 sUnrefSpaceC70; // @ 801BAC70 +#else +UNUSED static u32 sUnrefSpaceC6C; // @ 801BAC6C +UNUSED static u32 sUnrefSpaceC70; // @ 801BAC70 +#endif static struct ObjPlane *D_801BAC74; static struct ObjPlane *D_801BAC78; // sShapeNetHead? +#ifndef TARGET_WEB static u8 sUnrefSpaceC80[0x1C]; // @ 801BAC80 +#else +UNUSED static u8 sUnrefSpaceC80[0x1C]; // @ 801BAC80 +#endif static struct ObjFace *D_801BAC9C; static struct ObjFace *D_801BACA0; +#ifndef TARGET_WEB static u8 sUnrefSpaceCA8[0x10]; // @ 801BACA8 +#else +UNUSED static u8 sUnrefSpaceCA8[0x10]; // @ 801BACA8 +#endif /// factor for scaling vertices in an `ObjShape` when calling `scale_verts_in_shape()` static struct GdVec3f sVertexScaleFactor; /// factor for translating vertices in an `ObjShape` when calling `translate_verts_in_shape()` static struct GdVec3f sVertexTranslateOffset; +#ifndef TARGET_WEB static u8 sUnrefSpaceCD8[0x30]; // @ 801BACD8 +#else +UNUSED static u8 sUnrefSpaceCD8[0x30]; // @ 801BACD8 +#endif static struct ObjGroup *D_801BAD08; // group of planes from make_netfromshape +#ifndef TARGET_WEB static u8 sUnrefSpaceD10[0x20]; // @ 801BAD10 +#else +UNUSED static u8 sUnrefSpaceD10[0x20]; // @ 801BAD10 +#endif static struct GdVec3f D_801BAD30; // printed with "c=" +#ifndef TARGET_WEB static u8 sUnrefSpaceD40[0x120]; // @ 801BAD40 +#else +UNUSED static u8 sUnrefSpaceD40[0x120]; // @ 801BAD40 +#endif // Forward Declarations struct ObjMaterial *find_or_add_new_mtl(struct ObjGroup *, s32, f32, f32, f32); diff --git a/src/menu/file_select.c b/src/menu/file_select.c index df28306a9..5319ab08f 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -39,7 +39,11 @@ // the large length difference between options. // sSoundTextY unused (EU supports its existence). static s16 sSoundTextX; +#ifndef TARGET_WEB static s16 sSoundTextY; +#else +UNUSED static s16 sSoundTextY; +#endif #endif //! @Bug (UB Array Access) For PAL, more buttons were added than the array was extended. @@ -63,8 +67,13 @@ static struct Object *sMainMenuButtons[NUM_BUTTONS]; // The current sound mode is automatically centered on US due to // the large length difference between options. // sSoundTextY is unused +#ifndef TARGET_WEB static s16 sSoundTextX; static s16 sSoundTextY; +#else +UNUSED static s16 sSoundTextX; +UNUSED static s16 sSoundTextY; +#endif #endif // Used to defined yes/no fade colors after a file is selected in the erase menu. @@ -1177,6 +1186,7 @@ void load_score_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceBut // If the previous button is in default state if (sMainMenuButtons[prevMenuButtonID]->oMenuButtonState == MENU_BUTTON_STATE_DEFAULT) { // Hide buttons of corresponding button menu groups + #ifndef QOL_FIXES if (prevMenuButtonID == MENU_BUTTON_SCORE) //! Not possible, this is checking if the score menu //! was opened from the score menu! { @@ -1184,6 +1194,7 @@ void load_score_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceBut mark_obj_for_deletion(sMainMenuButtons[buttonID]); } } + #endif if (prevMenuButtonID == MENU_BUTTON_COPY) { for (buttonID = MENU_BUTTON_COPY_MIN; buttonID < MENU_BUTTON_COPY_MAX; buttonID++) { mark_obj_for_deletion(sMainMenuButtons[buttonID]); @@ -1223,6 +1234,7 @@ void load_copy_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceButt mark_obj_for_deletion(sMainMenuButtons[buttonID]); } } + #ifndef QOL_FIXES if (prevMenuButtonID == MENU_BUTTON_COPY) //! Not possible, this is checking if the copy menu //! was opened from the copy menu! { @@ -1230,6 +1242,7 @@ void load_copy_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceButt mark_obj_for_deletion(sMainMenuButtons[buttonID]); } } + #endif if (prevMenuButtonID == MENU_BUTTON_ERASE) { for (buttonID = MENU_BUTTON_ERASE_MIN; buttonID < MENU_BUTTON_ERASE_MAX; buttonID++) { mark_obj_for_deletion(sMainMenuButtons[buttonID]); @@ -1269,6 +1282,7 @@ void load_erase_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceBut mark_obj_for_deletion(sMainMenuButtons[buttonID]); } } + #ifndef QOL_FIXES if (prevMenuButtonID == MENU_BUTTON_ERASE) //! Not possible, this is checking if the erase menu //! was opened from the erase menu! { @@ -1276,6 +1290,7 @@ void load_erase_menu_from_submenu(s16 prevMenuButtonID, struct Object *sourceBut mark_obj_for_deletion(sMainMenuButtons[buttonID]); } } + #endif // Play zoom in sound, select erase menu and render it's buttons sSelectedButtonID = MENU_BUTTON_ERASE; play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gDefaultSoundArgs); diff --git a/src/menu/level_select_menu.c b/src/menu/level_select_menu.c index b48478d3e..aa7f1b594 100644 --- a/src/menu/level_select_menu.c +++ b/src/menu/level_select_menu.c @@ -27,7 +27,7 @@ static char gLevelSelect_StageNamesText[64][16] = { static u16 gDemoCountdown = 0; #ifndef VERSION_JP -static s16 D_U_801A7C34 = 1; +static s16 playMarioGreeting = 1; static s16 gameOverNotPlayed = 1; #endif @@ -61,6 +61,9 @@ int run_press_start_demo_timer(s32 timer) { timer = (s8)((struct DemoInput *) gDemo.targetAnim)->timer; gCurrSaveFileNum = 1; gCurrActNum = 1; + #ifndef VERSION_JP + playMarioGreeting = 1; + #endif } } else { // activity was detected, so reset the demo countdown. gDemoCountdown = 0; @@ -69,9 +72,25 @@ int run_press_start_demo_timer(s32 timer) { return timer; } +#ifndef QOL_FIXES +#ifndef TARGET_WEB extern int gDemoInputListID_2; +#endif +#endif +#ifdef QOL_FIXES +extern unsigned int gDemoInputListID_2; +#endif +#ifdef TARGET_WEB +extern unsigned int gDemoInputListID_2; +#endif extern int gPressedStart; +#ifndef QOL_FIXES +#ifndef TARGET_WEB +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#endif +#endif int start_demo(int timer) { gCurrDemoInput = NULL; @@ -91,6 +110,11 @@ int start_demo(int timer) gCurrActNum = 6; return timer; } +#ifndef QOL_FIXES +#ifndef TARGET_WEB +#pragma GCC diagnostic pop +#endif +#endif // input loop for the level select menu. updates the selected stage // count if an input was received. signals the stage to be started @@ -162,9 +186,13 @@ int intro_default(void) { s32 sp1C = 0; #ifndef VERSION_JP - if (D_U_801A7C34 == 1) { - play_sound(SOUND_MARIO_HELLO, gDefaultSoundArgs); - D_U_801A7C34 = 0; + if (playMarioGreeting == 1) { + if (gGlobalTimer < 0x81) { + play_sound(SOUND_MARIO_HELLO, gDefaultSoundArgs); + } else { + play_sound(SOUND_MARIO_PRESS_START_TO_PLAY, gDefaultSoundArgs); + } + playMarioGreeting = 0; } #endif print_intro_text(); @@ -173,7 +201,7 @@ int intro_default(void) { play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs); sp1C = 100 + gDebugLevelSelect; #ifndef VERSION_JP - D_U_801A7C34 = 1; + playMarioGreeting = 1; #endif } return run_press_start_demo_timer(sp1C); diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 08b988e65..438fd2197 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -95,7 +95,16 @@ void render_100_coin_star(u8 stars) { bhvActSelectorStarType, 370, 24, -300, 0, 0, 0); sStarSelectorModels[6]->oStarSelectorSize = 0.8; sStarSelectorModels[6]->oStarSelectorType = STAR_SELECTOR_100_COINS; + #ifndef QOL_FIXES } + #else + } else if ((sObtainedStars == 6)) { + sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_TRANSPARENT_STAR, + bhvActSelectorStarType, 300, 30, -300, 0, 0, 0); + sStarSelectorModels[6]->oStarSelectorSize = 0.8; + sStarSelectorModels[6]->oStarSelectorType = STAR_SELECTOR_100_COINS; + } + #endif } /** @@ -141,9 +150,11 @@ void bhv_act_selector_init(void) { //! Useless, since sInitSelectedActNum has already been set in this //! scenario by the code that shows the next uncollected star. + #ifndef QOL_FIXES if (sObtainedStars == 0) { sInitSelectedActNum = 1; } + #endif // Render star selector objects for (i = 0; i < sVisibleStars; i++) { diff --git a/src/pc/README-n64-fast32-engine.md b/src/pc/README-n64-fast3d-engine.md similarity index 90% rename from src/pc/README-n64-fast32-engine.md rename to src/pc/README-n64-fast3d-engine.md index 4aa387d49..277433ba9 100644 --- a/src/pc/README-n64-fast32-engine.md +++ b/src/pc/README-n64-fast3d-engine.md @@ -1,10 +1,10 @@ -# About n64-fast32-engine +# About n64-fast3d-engine -sm64pc supports OpenGL through [n64-fast32-engine](https://github.com/Emill/n64-fast3d-engine/), by [Emill](https://github.com/Emill/). +sm64pc supports OpenGL through [n64-fast3d-engine](https://github.com/Emill/n64-fast3d-engine/), by [Emill](https://github.com/Emill/). We recommend that you visit the repo if you wish for a better understanding on how this port was possible. -n64-fast32-engine is licensed under +n64-fast3d-engine is licensed under ``` Copyright (c) 2020, Emill @@ -25,4 +25,4 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -``` +``` \ No newline at end of file diff --git a/src/pc/audio/audio_null.c b/src/pc/audio/audio_null.c index 4d0dd9234..e54e0f033 100644 --- a/src/pc/audio/audio_null.c +++ b/src/pc/audio/audio_null.c @@ -1,4 +1,5 @@ #include "audio_api.h" +#include "macros.h" static bool audio_null_init(void) { return true; @@ -12,7 +13,7 @@ static int audio_null_get_desired_buffered(void) { return 0; } -static void audio_null_play(const uint8_t *buf, size_t len) { +static void audio_null_play(UNUSED const uint8_t *buf, UNUSED size_t len) { } static void audio_null_shutdown(void) { diff --git a/src/pc/controller/controller_recorded_tas.c b/src/pc/controller/controller_recorded_tas.c index 73b507dcf..a426bd5ce 100644 --- a/src/pc/controller/controller_recorded_tas.c +++ b/src/pc/controller/controller_recorded_tas.c @@ -1,4 +1,5 @@ #include +#include #include #include "controller_api.h" @@ -9,14 +10,20 @@ static void tas_init(void) { fp = fopen("cont.m64", "rb"); if (fp != NULL) { uint8_t buf[0x400]; - fread(buf, 1, sizeof(buf), fp); + if (fread(buf, 1, sizeof(buf), fp) != 1) { + printf("I/O error occurred."); + exit(1); + }; } } static void tas_read(OSContPad *pad) { if (fp != NULL) { uint8_t bytes[4] = {0}; - fread(bytes, 1, 4, fp); + if (fread(bytes, 1, 4, fp) != 1) { + printf("I/O error occurred."); + exit(1); + }; pad->button = (bytes[0] << 8) | bytes[1]; pad->stick_x = bytes[2]; pad->stick_y = bytes[3]; diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index c7e9c7c7d..e7e978f90 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -46,7 +46,11 @@ static u32 joy_binds[MAX_JOYBINDS][2]; static u32 mouse_binds[MAX_JOYBINDS][2]; static bool joy_buttons[MAX_JOYBUTTONS] = { false }; +#ifndef TARGET_WEB static u32 mouse_buttons = 0; +#else +UNUSED static u32 mouse_buttons = 0; +#endif static u32 last_mouse = VK_INVALID; static u32 last_joybutton = VK_INVALID; diff --git a/src/pc/discord/discordrpc.c b/src/pc/discord/discordrpc.c index e2f5aa7d3..a9f998503 100644 --- a/src/pc/discord/discordrpc.c +++ b/src/pc/discord/discordrpc.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -221,22 +222,22 @@ static void set_state(void) { } void set_logo(void) { - if (lastCourseNum) - snprintf(largeImageKey, sizeof(largeImageKey), "%d", lastCourseNum); - else + if (lastCourseNum) { + if (snprintf(largeImageKey, sizeof(largeImageKey), "%d", lastCourseNum) < 0) + abort(); + } else { strcpy(largeImageKey, "0"); + } - /* - if (lastActNum) - snprintf(smallImageKey, sizeof(largeImageKey), "%d", lastActNum); - else + if (lastActNum) { + if (snprintf(smallImageKey, sizeof(smallImageKey), "%d", lastActNum) < 0) + abort(); + } else { smallImageKey[0] = '\0'; - */ + } discordRichPresence.largeImageKey = largeImageKey; - //discordRichPresence.largeImageText = ""; - //discordRichPresence.smallImageKey = smallImageKey; - //discordRichPresence.smallImageText = ""; + discordRichPresence.smallImageKey = smallImageKey; } void discord_update_rich_presence(void) { diff --git a/src/pc/gfx/gfx_direct3d_common.cpp b/src/pc/gfx/gfx_direct3d_common.cpp index c4d6014ed..62f3879fb 100644 --- a/src/pc/gfx/gfx_direct3d_common.cpp +++ b/src/pc/gfx/gfx_direct3d_common.cpp @@ -299,7 +299,7 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f if (cc_features.opt_alpha && cc_features.opt_noise) { append_line(buf, &len, " float2 coords = (input.screenPos.xy / input.screenPos.w) * noise_scale;"); - append_line(buf, &len, " texel.a *= round(random(float3(floor(coords), noise_frame)));"); + append_line(buf, &len, " texel.a *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.a - 0.5));"); } if (cc_features.opt_alpha) { diff --git a/src/pc/gfx/gfx_opengl.c b/src/pc/gfx/gfx_opengl.c index 324f082ed..1c58d771a 100644 --- a/src/pc/gfx/gfx_opengl.c +++ b/src/pc/gfx/gfx_opengl.c @@ -172,6 +172,9 @@ static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_ return "texVal1.a"; } } + #ifdef TARGET_WEB + return "0"; + #endif } static void append_formula(char *buf, size_t *len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) { @@ -378,7 +381,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad } if (opt_alpha && opt_noise) - append_line(fs_buf, &fs_len, "texel.a *= floor(random(floor(vec3(gl_FragCoord.xy, frame_count))) + 0.5);"); + append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(floor(vec3(gl_FragCoord.xy, frame_count))) + texel.a, 0.0, 1.0));"); if (opt_alpha) { append_line(fs_buf, &fs_len, "gl_FragColor = texel;"); @@ -390,11 +393,13 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(uint32_t shad vs_buf[vs_len] = '\0'; fs_buf[fs_len] = '\0'; - /*puts("Vertex shader:"); + #ifdef DEBUG + puts("Vertex shader:"); puts(vs_buf); puts("Fragment shader:"); puts(fs_buf); - puts("End");*/ + puts("End"); + #endif const GLchar *sources[2] = { vs_buf, fs_buf }; const GLint lengths[2] = { vs_len, fs_len }; @@ -522,14 +527,14 @@ static GLuint gfx_opengl_new_texture(void) { } static void gfx_opengl_select_texture(int tile, GLuint texture_id) { - opengl_tex[tile] = tex_cache + texture_id; - opengl_curtex = tile; - glActiveTexture(GL_TEXTURE0 + tile); - glBindTexture(GL_TEXTURE_2D, opengl_tex[tile]->gltex); - gfx_opengl_set_texture_uniforms(opengl_prg, tile); + opengl_tex[tile] = tex_cache + texture_id; + opengl_curtex = tile; + glActiveTexture(GL_TEXTURE0 + tile); + glBindTexture(GL_TEXTURE_2D, opengl_tex[tile]->gltex); + gfx_opengl_set_texture_uniforms(opengl_prg, tile); } -static void gfx_opengl_upload_texture(uint8_t *rgba32_buf, int width, int height) { +static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, int width, int height) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); opengl_tex[opengl_curtex]->size[0] = width; opengl_tex[opengl_curtex]->size[1] = height; @@ -595,7 +600,9 @@ static void gfx_opengl_set_use_alpha(bool use_alpha) { } static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) { - //printf("flushing %d tris\n", buf_vbo_num_tris); + #ifdef DEBUG + printf("flushing %d tris\n", buf_vbo_num_tris); + #endif glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW); glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris); } diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index a78f2ffdd..6e202f3ae 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -28,6 +28,8 @@ #include "../configfile.h" #include "../fs/fs.h" +#include "macros.h" + #define SUPPORT_CHECK(x) assert(x) // SCALE_M_N: upscale/downscale M-bit integer to N-bit @@ -179,7 +181,11 @@ static struct GfxRenderingAPI *gfx_rapi; // 4x4 pink-black checkerboard texture to indicate missing textures #define MISSING_W 4 #define MISSING_H 4 +#ifndef TARGET_WEB static const uint8_t missing_texture[MISSING_W * MISSING_H * 4] = { +#else +UNUSED static const uint8_t missing_texture[MISSING_W * MISSING_H * 4] = { +#endif 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, @@ -195,21 +201,31 @@ static inline size_t string_hash(const uint8_t *str) { } #endif +#ifndef TARGET_WEB static unsigned long get_time(void) { return 0; } +#else +UNUSED static unsigned long get_time(void) { + return 0; +} +#endif static void gfx_flush(void) { if (buf_vbo_len > 0) { - int num = buf_vbo_num_tris; + UNUSED int num = buf_vbo_num_tris; + #ifdef DEBUG unsigned long t0 = get_time(); + #endif gfx_rapi->draw_triangles(buf_vbo, buf_vbo_len, buf_vbo_num_tris); buf_vbo_len = 0; buf_vbo_num_tris = 0; + #ifdef DEBUG unsigned long t1 = get_time(); - /*if (t1 - t0 > 1000) { + if (t1 - t0 > 1000) { printf("f: %d %d\n", num, (int)(t1 - t0)); - }*/ + } + #endif } } @@ -299,7 +315,7 @@ static bool gfx_texture_cache_lookup(int tile, struct TextureHashmapNode **n, co hash = (hash >> HASH_SHIFT) & HASH_MASK; struct TextureHashmapNode **node = &gfx_texture_cache.hashmap[hash]; - while (*node != NULL && *node - gfx_texture_cache.pool < gfx_texture_cache.pool_pos) { + while (*node != NULL && *node - gfx_texture_cache.pool < (long)gfx_texture_cache.pool_pos) { if (CMPADDR((*node)->texture_addr, orig_addr) && (*node)->fmt == fmt && (*node)->siz == siz) { gfx_rapi->select_texture(tile, (*node)->texture_id); *n = *node; @@ -311,7 +327,9 @@ static bool gfx_texture_cache_lookup(int tile, struct TextureHashmapNode **n, co // Pool is full. We just invalidate everything and start over. gfx_texture_cache.pool_pos = 0; node = &gfx_texture_cache.hashmap[hash]; - // puts("Clearing texture cache"); + #ifdef DEBUG + puts("Clearing texture cache"); + #endif } *node = &gfx_texture_cache.pool[gfx_texture_cache.pool_pos++]; if ((*node)->texture_addr == NULL) { @@ -619,7 +637,9 @@ static void import_texture(int tile) { load_texture(texname); #else // the texture data is actual texture data + #ifdef DEBUG int t0 = get_time(); + #endif if (fmt == G_IM_FMT_RGBA) { if (siz == G_IM_SIZ_32b) { import_texture_rgba32(tile); @@ -658,8 +678,10 @@ static void import_texture(int tile) { } else { sys_fatal("unsupported texture format: %u", fmt); } + #ifdef DEBUG int t1 = get_time(); - //printf("Time diff: %d\n", t1 - t0); + printf("Time diff: %d\n", t1 - t0); + #endif #endif } @@ -1062,11 +1084,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx) { } } } - /*struct RGBA *color = &v_arr[i]->color; - buf_vbo[buf_vbo_len++] = color->r / 255.0f; - buf_vbo[buf_vbo_len++] = color->g / 255.0f; - buf_vbo[buf_vbo_len++] = color->b / 255.0f; - buf_vbo[buf_vbo_len++] = color->a / 255.0f;*/ } if (++buf_vbo_num_tris == MAX_BUFFERED) { gfx_flush(); @@ -1130,14 +1147,14 @@ static void gfx_sp_movemem(uint8_t index, uint8_t offset, const void* data) { } } -static void gfx_sp_moveword(uint8_t index, uint16_t offset, uint32_t data) { +static void gfx_sp_moveword(uint8_t index, UNUSED uint16_t offset, uint32_t data) { switch (index) { case G_MW_NUMLIGHT: #ifdef F3DEX_GBI_2 rsp.current_num_lights = data / 24 + 1; // add ambient light #else // Ambient light is included - // The 31th bit is a flag that lights should be recalculated + // The 31st bit is a flag that lights should be recalculated rsp.current_num_lights = (data - 0x80000000U) / 32; #endif rsp.lights_changed = 1; @@ -1149,12 +1166,12 @@ static void gfx_sp_moveword(uint8_t index, uint16_t offset, uint32_t data) { } } -static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on) { +static void gfx_sp_texture(uint16_t sc, uint16_t tc, UNUSED uint8_t level, UNUSED uint8_t tile, UNUSED uint8_t on) { rsp.texture_scaling_factor.s = sc; rsp.texture_scaling_factor.t = tc; } -static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) { +static void gfx_dp_set_scissor(UNUSED uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry) { float x = ulx / 4.0f * RATIO_X; float y = (SCREEN_HEIGHT - lry / 4.0f) * RATIO_Y; float width = (lrx - ulx) / 4.0f * RATIO_X; @@ -1168,12 +1185,12 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32 rdp.viewport_or_scissor_changed = true; } -static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr) { +static void gfx_dp_set_texture_image(UNUSED uint32_t format, uint32_t size, UNUSED uint32_t width, const void* addr) { rdp.texture_to_load.addr = addr; rdp.texture_to_load.siz = size; } -static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, uint32_t shifts) { +static void gfx_dp_set_tile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, uint32_t cmt, UNUSED uint32_t maskt, UNUSED uint32_t shiftt, uint32_t cms, UNUSED uint32_t masks, UNUSED uint32_t shifts) { if (tile == G_TX_RENDERTILE) { SUPPORT_CHECK(palette == 0); // palette should set upper 4 bits of color index in 4b mode @@ -1202,13 +1219,13 @@ static void gfx_dp_set_tile_size(uint8_t tile, uint16_t uls, uint16_t ult, uint1 } } -static void gfx_dp_load_tlut(uint8_t tile, uint32_t high_index) { +static void gfx_dp_load_tlut(uint8_t tile, UNUSED uint32_t high_index) { SUPPORT_CHECK(tile == G_TX_LOADTILE); SUPPORT_CHECK(rdp.texture_to_load.siz == G_IM_SIZ_16b); rdp.palette = rdp.texture_to_load.addr; } -static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t dxt) { +static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, UNUSED uint32_t dxt) { if (tile == 1) return; SUPPORT_CHECK(tile == G_TX_LOADTILE); SUPPORT_CHECK(uls == 0); @@ -1404,7 +1421,7 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr } } -static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls, int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) { +static void gfx_dp_texture_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, UNUSED uint8_t tile, int16_t uls, int16_t ult, int16_t dsdx, int16_t dtdy, bool flip) { uint32_t saved_combine_mode = rdp.combine_mode; if ((rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_COPY) { // Per RDP Command Summary Set Tile's shift s and this dsdx should be set to 4 texels @@ -1484,7 +1501,7 @@ static void gfx_dp_set_z_image(void *z_buf_address) { rdp.z_buf_address = z_buf_address; } -static void gfx_dp_set_color_image(uint32_t format, uint32_t size, uint32_t width, void* address) { +static void gfx_dp_set_color_image(UNUSED uint32_t format, UNUSED uint32_t size, UNUSED uint32_t width, void* address) { rdp.color_image_address = address; } @@ -1504,7 +1521,7 @@ static inline void *seg_addr(uintptr_t w1) { #define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1)) static void gfx_run_dl(Gfx* cmd) { - int dummy = 0; + UNUSED int dummy = 0; for (;;) { uint32_t opcode = cmd->words.w0 >> 24; @@ -1650,7 +1667,7 @@ static void gfx_run_dl(Gfx* cmd) { case G_TEXRECT: case G_TEXRECTFLIP: { - int32_t lrx, lry, tile, ulx, uly; + int32_t lrx, lry, tile = 0, ulx, uly; uint32_t uls, ult, dsdx, dtdy; #ifdef F3DEX_GBI_2E lrx = (int32_t)(C0(0, 24) << 8) >> 8; @@ -1783,7 +1800,9 @@ void gfx_start_frame(void) { void gfx_run(Gfx *commands) { gfx_sp_reset(); - //puts("New frame"); + #ifdef DEBUG + puts("New frame"); + #endif if (!gfx_wapi->start_frame()) { dropped_frame = true; @@ -1791,12 +1810,16 @@ void gfx_run(Gfx *commands) { } dropped_frame = false; + #ifdef DEBUG double t0 = gfx_wapi->get_time(); + #endif gfx_rapi->start_frame(); gfx_run_dl(commands); gfx_flush(); + #ifdef DEBUG double t1 = gfx_wapi->get_time(); - //printf("Process %f %f\n", t1, t1 - t0); + printf("Process %f %f\n", t1, t1 - t0); + #endif gfx_rapi->end_frame(); gfx_wapi->swap_buffers_begin(); } diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index f808db901..1eeb6115b 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -36,11 +36,15 @@ #include "src/pc/controller/controller_keyboard.h" +#ifdef TARGET_WEB +#include "macros.h" +#endif + // TODO: figure out if this shit even works #ifdef VERSION_EU -# define FRAMERATE 25 + #define FRAMERATE 25 #else -# define FRAMERATE 30 + #define FRAMERATE 30 #endif static SDL_Window *wnd; @@ -268,7 +272,11 @@ static int translate_scancode(int scancode) { } } +#ifndef TARGET_WEB static void gfx_sdl_onkeydown(int scancode) { +#else +UNUSED static void gfx_sdl_onkeydown(int scancode) { +#endif if (kb_key_down) kb_key_down(translate_scancode(scancode)); @@ -280,7 +288,11 @@ static void gfx_sdl_onkeydown(int scancode) { } } +#ifndef TARGET_WEB static void gfx_sdl_onkeyup(int scancode) { +#else +UNUSED static void gfx_sdl_onkeyup(int scancode) { +#endif if (kb_key_up) kb_key_up(translate_scancode(scancode)); } diff --git a/src/pc/mixer.c b/src/pc/mixer.c index 282aef9f2..68ebc37e3 100644 --- a/src/pc/mixer.c +++ b/src/pc/mixer.c @@ -16,7 +16,9 @@ #define HAS_NEON 0 #endif +#ifndef TARGET_WEB #pragma GCC optimize ("unroll-loops") +#endif #if HAS_SSE41 #define LOADLH(l, h) _mm_castpd_si128(_mm_loadh_pd(_mm_load_sd((const double *)(l)), (const double *)(h))) diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 923e7ea84..23e130374 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -39,6 +39,8 @@ #include "pc/discord/discordrpc.h" #endif +#include "macros.h" + OSMesg D_80339BEC; OSMesgQueue gSIEventMesgQueue; @@ -61,10 +63,10 @@ extern void thread5_game_loop(void *arg); extern void create_next_audio_buffer(s16 *samples, u32 num_samples); void game_loop_one_iteration(void); -void dispatch_audio_sptask(struct SPTask *spTask) { +void dispatch_audio_sptask(UNUSED struct SPTask *spTask) { } -void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg) { +void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) { } static bool inited = false; @@ -96,16 +98,22 @@ void produce_one_frame(void) { int samples_left = audio_api->buffered(); u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW; - //printf("Audio samples: %d %u\n", samples_left, num_audio_samples); + #ifdef DEBUG + printf("Audio samples: %d %u\n", samples_left, num_audio_samples); + #endif s16 audio_buffer[SAMPLES_HIGH * 2 * 2]; for (int i = 0; i < 2; i++) { - /*if (audio_cnt-- == 0) { + #ifdef DEBUG + if (audio_cnt-- == 0) { audio_cnt = 2; } - u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/ + u32 num_audio_samples = audio_cnt < 2 ? 528 : 544; + #endif create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples); } - //printf("Audio samples before submitting: %d\n", audio_api->buffered()); + #ifdef DEBUG + printf("Audio samples before submitting: %d\n", audio_api->buffered()); + #endif audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4); diff --git a/text/de/dialogs.h b/text/de/dialogs.h index fba15c161..12dbfce12 100644 --- a/text/de/dialogs.h +++ b/text/de/dialogs.h @@ -1251,9 +1251,19 @@ die Temperatur!")) DEFINE_DIALOG(DIALOG_098, 1, 1, 95, 200, _("\ Komm nur näher, hehehe!")) +#ifndef QOL_FIXES DEFINE_DIALOG(DIALOG_099, 1, 3, 95, 200, _("\ ")) +#else +DEFINE_DIALOG(DIALOG_099, 1, 3, 95, 200, _("\ +Eh he he...\n\ +Du gehörst mir, hee hee!\n\ +Ich gehe einfach durch\n\ +diese Wand. Kannst du\n\ +das auch? Heh, heh, heh!")) + +#endif DEFINE_DIALOG(DIALOG_100, 1, 2, 95, 200, _("\ Jippiiiiieee, ich hab' sie!\n\ Jetzt gehört sie mir!!!")) diff --git a/text/us/dialogs.h b/text/us/dialogs.h index fc847e13d..95de6a82b 100644 --- a/text/us/dialogs.h +++ b/text/us/dialogs.h @@ -16,6 +16,12 @@ #define GIVE_UP "give" #endif +#ifdef QOL_FIXES +#define YOSHI_IT "Is" +#else +#define YOSHI_IT "It" +#endif + DEFINE_DIALOG(DIALOG_000, 1, 6, 30, 200, _("\ Wow! You're smack in the\n\ middle of the battlefield.\n\ @@ -1982,7 +1988,7 @@ Enjoy!!!" DEFINE_DIALOG(DIALOG_161, 1, 4, 30, 200, _("\ Mario!!!\n\ -Is that really you???\n\ +" YOSHI_IT " that really you???\n\ It has been so long since\n\ our last adventure!\n\ They told me that I might\n\ diff --git a/tools/.gitignore b/tools/.gitignore index 469b30622..e51f7b739 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -11,6 +11,7 @@ /tabledesign /textconv /vadpcm_enc +/gen_asset_list !/ido5.3_compiler/lib/*.so !/ido5.3_compiler/usr/lib/*.so !/ido5.3_compiler/usr/lib/*.so.1 diff --git a/tools/Makefile b/tools/Makefile index d663fb0a2..4cb616c72 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,8 +1,9 @@ CC := gcc CXX := g++ -CFLAGS := -I../include -I. -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s +CFLAGS := -I../include -I. -Wall -Wextra -pedantic -std=c99 -O2 -s LDFLAGS := -lm PROGRAMS := n64graphics n64graphics_ci mio0 n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv +GENASSETLIST := gen_asset_list default: all @@ -25,32 +26,43 @@ aifc_decode_SOURCES := aifc_decode.c aiff_extract_codebook_SOURCES := aiff_extract_codebook.c tabledesign_SOURCES := sdk-tools/tabledesign/codebook.c sdk-tools/tabledesign/estimate.c sdk-tools/tabledesign/print.c sdk-tools/tabledesign/tabledesign.c -tabledesign_CFLAGS := -Iaudiofile -Wno-uninitialized -tabledesign_LDFLAGS := -Laudiofile -laudiofile -lstdc++ -lm +tabledesign_CFLAGS := -Iaudiofile +tabledesign_LDFLAGS := -Laudiofile -laudiofile -lstdc++ vadpcm_enc_SOURCES := sdk-tools/adpcm/vadpcm_enc.c sdk-tools/adpcm/vpredictor.c sdk-tools/adpcm/quant.c sdk-tools/adpcm/util.c sdk-tools/adpcm/vencode.c -vadpcm_enc_CFLAGS := -Wno-unused-result -Wno-uninitialized -Wno-sign-compare -Wno-absolute-value +vadpcm_enc_CFLAGS := extract_data_for_mio_SOURCES := extract_data_for_mio.c skyconv_SOURCES := skyconv.c n64graphics.c utils.c +gen_asset_list_CXX := g++-8 +gen_asset_list_SOURCES := gen_asset_list.cpp +gen_asset_list_CFLAGS := -std=c++17 -Wall -Wextra -pedantic -O1 +gen_asset_list_LDFLAGS := -lstdc++fs + LIBAUDIOFILE := audiofile/libaudiofile.a $(LIBAUDIOFILE): @$(MAKE) -C audiofile -all: $(LIBAUDIOFILE) $(PROGRAMS) $(CXX_PROGRAMS) +all: $(LIBAUDIOFILE) $(PROGRAMS) $(CXX_PROGRAMS) $(GENASSETLIST) clean: - $(RM) $(PROGRAMS) $(CXX_PROGRAMS) + $(RM) $(PROGRAMS) $(CXX_PROGRAMS) $(GENASSETLIST) $(MAKE) -C audiofile clean define COMPILE $(1): $($1_SOURCES) - $(CC) $(CFLAGS) $($1_CFLAGS) $$^ -o $$@ $(LDFLAGS) $($1_LDFLAGS) + $(CC) $(CFLAGS) $($1_CFLAGS) $$^ -o $$@ $($1_LDFLAGS) $(LDFLAGS) +endef + +define GENASSETLIST_COMPILE +$(1): $($1_SOURCES) + $(gen_asset_list_CXX) $($1_CFLAGS) $$^ -o $$@ $($1_LDFLAGS) $(LDFLAGS) endef $(foreach p,$(PROGRAMS),$(eval $(call COMPILE,$(p)))) +$(foreach p,$(GENASSETLIST),$(eval $(call GENASSETLIST_COMPILE,$(p)))) .PHONY: all clean default diff --git a/tools/create_patch.sh b/tools/create_patch.sh index ea75d9cca..cb0bf81b8 100755 --- a/tools/create_patch.sh +++ b/tools/create_patch.sh @@ -20,6 +20,6 @@ fi # 'git diff' is stupid and doesn't show new untracked files, so we must add them first. git add . # Generate the patch. -git diff -p --staged > "$1" +git diff --ignore-space-at-eol -b -w -p --text --staged > "$1" # Undo the 'git add'. git reset diff --git a/tools/patch_libultra_math.c b/tools/patch_libultra_math.c index e6bdcc0cf..e6987ba9b 100644 --- a/tools/patch_libultra_math.c +++ b/tools/patch_libultra_math.c @@ -79,6 +79,7 @@ struct ar_header { #define FLAGS_MIPS3 0x20 #define FLAGS_O32ABI 0x100000 int main(int argc, char **argv) { + argc = 0; FILE *f = fopen(argv[1], "r+"); if (f == NULL) { @@ -122,5 +123,5 @@ int main(int argc, char **argv) { fseek(f, filesize - sizeof(hdr), SEEK_CUR); } fclose(f); - return 0; + return argc; } diff --git a/tools/sdk-tools/adpcm/Makefile b/tools/sdk-tools/adpcm/Makefile index b97991bee..7a32ecfb9 100644 --- a/tools/sdk-tools/adpcm/Makefile +++ b/tools/sdk-tools/adpcm/Makefile @@ -6,7 +6,7 @@ IRIX_CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc IRIX_CFLAGS := -fullwarn -woff 515,608,658,799 -Wab,-r4300_mul -g -Xcpluscomm -mips1 -o32 NATIVE_CC := gcc -NATIVE_CFLAGS := -g -Wall -O2 -Wno-unused-result -Wno-uninitialized +NATIVE_CFLAGS := -g -Wall -O2 default: native all: irix native diff --git a/tools/sdk-tools/adpcm/util.c b/tools/sdk-tools/adpcm/util.c index 22acdd768..dc6688e0c 100644 --- a/tools/sdk-tools/adpcm/util.c +++ b/tools/sdk-tools/adpcm/util.c @@ -10,12 +10,12 @@ static u32 getshort(FILE *ifile) u32 c1; u32 c2; - if ((c1 = getc(ifile)) == -1) + if ((c1 = getc(ifile)) == (u32)EOF) { return 0; } - if ((c2 = getc(ifile)) == -1) + if ((c2 = getc(ifile)) == (u32)EOF) { return 0; } @@ -30,7 +30,7 @@ u32 readbits(u32 nbits, FILE *ifile) u32 left; u32 mask; - if (nbits <= in_bit_pos + 1) + if (nbits <= (u32)in_bit_pos + 1) { mask = (1U << nbits) - 1; b = ((u32) input_word >> (in_bit_pos - nbits + 1)) & mask; @@ -60,13 +60,22 @@ char *ReadPString(FILE *ifile) u8 c; char *st; - fread(&c, 1, 1, ifile); + if (fread(&c, 1, 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; st = malloc(c + 1); - fread(st, c, 1, ifile); + if (fread(st, c, 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; st[c] = '\0'; if ((c & 1) == 0) { - fread(&c, 1, 1, ifile); + if (fread(&c, 1, 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; } return st; } @@ -91,12 +100,18 @@ ALADPCMloop *readlooppoints(FILE *ifile, s16 *nloops) s32 i; ALADPCMloop *al; - fread(nloops, sizeof(s16), 1, ifile); + if (fread(nloops, sizeof(s16), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(*nloops) al = malloc(*nloops * sizeof(ALADPCMloop)); for (i = 0; i < *nloops; i++) { - fread(&al[i], sizeof(ALADPCMloop), 1, ifile); + if (fread(&al[i], sizeof(ALADPCMloop), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP32(al[i].start) BSWAP32(al[i].end) BSWAP32(al[i].count) diff --git a/tools/sdk-tools/adpcm/vadpcm_dec.c b/tools/sdk-tools/adpcm/vadpcm_dec.c index 95d445972..8148b89a8 100644 --- a/tools/sdk-tools/adpcm/vadpcm_dec.c +++ b/tools/sdk-tools/adpcm/vadpcm_dec.c @@ -212,8 +212,7 @@ s32 main(s32 argc, char **argv) if (coefTable == NULL) { - // @bug should use progname; argv[0] may be an option - fprintf(stderr, "%s: Codebook missing from bitstream [%s]\n", argv[0], argv[1]); + fprintf(stderr, "%s: Codebook missing from bitstream [%s]\n", progname, argv[1]); exit(1); } diff --git a/tools/sdk-tools/adpcm/vadpcm_enc.c b/tools/sdk-tools/adpcm/vadpcm_enc.c index 0fd3a11f5..a2c55037f 100644 --- a/tools/sdk-tools/adpcm/vadpcm_enc.c +++ b/tools/sdk-tools/adpcm/vadpcm_enc.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) s16 numMarkers; s16 *inBuffer; s16 ts; - s32 minLoopLength = 800; + u32 minLoopLength = 800; s32 ***coefTable = NULL; s32 *state; s32 order; @@ -31,10 +31,10 @@ int main(int argc, char **argv) s32 i; s32 j; s32 k; - s32 nFrames; + u32 nFrames; s32 offset; s32 cChunkPos; - s32 currentPos; + u32 currentPos; s32 soundPointer = 0; s32 startPointer = 0; s32 startSoundPointer = 0; @@ -53,8 +53,8 @@ int main(int argc, char **argv) SoundDataChunk SndDChunk; InstrumentChunk InstChunk; Loop *loops = NULL; - ALADPCMloop *aloops; - Marker *markers; + ALADPCMloop *aloops = NULL; + Marker *markers = NULL; CodeChunk cChunk; char filename[1024]; FILE *fhandle; @@ -92,7 +92,7 @@ int main(int argc, char **argv) break; case 'l': - sscanf(optarg, "%d", &minLoopLength); + sscanf(optarg, "%d", (s32 *)&minLoopLength); break; default: @@ -132,15 +132,17 @@ int main(int argc, char **argv) inBuffer = malloc(16 * sizeof(s16)); - fread(&FormChunk, sizeof(Chunk), 1, ifile); + if (fread(&FormChunk, sizeof(Chunk), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP32(FormChunk.ckID) BSWAP32(FormChunk.ckSize) BSWAP32(FormChunk.formType) - // @bug This doesn't check for FORM for AIFF files, probably due to mistaken operator precedence. - if (!((FormChunk.ckID == 0x464f524d && // FORM - FormChunk.formType == 0x41494643) || // AIFC - FormChunk.formType == 0x41494646)) // AIFF + if (!(FormChunk.ckID == 0x464f524d && // FORM + (FormChunk.formType == 0x41494643 || // AIFC + FormChunk.formType == 0x41494646))) // AIFF { fprintf(stderr, "%s: [%s] is not an AIFF-C File\n", progname, argv[1]); exit(1); @@ -198,7 +200,10 @@ int main(int argc, char **argv) case 0x53534e44: // SSND offset = ftell(ifile); - fread(&SndDChunk, sizeof(SoundDataChunk), 1, ifile); + if (fread(&SndDChunk, sizeof(SoundDataChunk), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP32(SndDChunk.offset) BSWAP32(SndDChunk.blockSize) // The assert error messages specify line numbers 219/220. Match @@ -214,16 +219,25 @@ int main(int argc, char **argv) case 0x4d41524b: // MARK offset = ftell(ifile); - fread(&numMarkers, sizeof(s16), 1, ifile); + if (fread(&numMarkers, sizeof(s16), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(numMarkers) markers = malloc(numMarkers * sizeof(Marker)); for (i = 0; i < numMarkers; i++) { - fread(&markers[i], sizeof(Marker), 1, ifile); + if (fread(&markers[i], sizeof(Marker), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(markers[i].MarkerID) BSWAP16(markers[i].positionH) BSWAP16(markers[i].positionL) - fread(&strnLen, 1, 1, ifile); + if (fread(&strnLen, 1, 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; if ((strnLen & 1) != 0) { fseek(ifile, strnLen, SEEK_CUR); @@ -238,7 +252,10 @@ int main(int argc, char **argv) case 0x494e5354: // INST offset = ftell(ifile); - fread(&InstChunk, sizeof(InstrumentChunk), 1, ifile); + if (fread(&InstChunk, sizeof(InstrumentChunk), 1, ifile) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(InstChunk.sustainLoop.playMode) BSWAP16(InstChunk.sustainLoop.beginLoop) BSWAP16(InstChunk.sustainLoop.endLoop) @@ -414,10 +431,16 @@ int main(int argc, char **argv) } } left = aloops[i].end - currentPos; - fread(inBuffer, sizeof(s16), left, ifile); + if (fread(inBuffer, sizeof(s16), left, ifile) != (u32)left) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16_MANY(inBuffer, left) fseek(ifile, startPointer, SEEK_SET); - fread(inBuffer + left, sizeof(s16), 16 - left, ifile); + if (fread(inBuffer + left, sizeof(s16), 16 - left, ifile) != (u32)16 - left) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16_MANY(inBuffer + left, 16 - left) vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16); nBytes += 9; @@ -429,7 +452,7 @@ int main(int argc, char **argv) } nFrames = (CommChunk.numFramesH << 16) + CommChunk.numFramesL; - if ((nloops > 0U) & truncate) + if ((nloops > 0) & truncate) { lookupMarker(&loopEnd, loops[nloops - 1].endLoop, markers, numMarkers); nFrames = (loopEnd + 16 < nFrames ? loopEnd + 16 : nFrames); @@ -446,7 +469,7 @@ int main(int argc, char **argv) nsam = 16; } - if (fread(inBuffer, 2, nsam, ifile) == nsam) + if (fread(inBuffer, 2, (u32)nsam, ifile) == (u32)nsam) { BSWAP16_MANY(inBuffer, nsam) vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, nsam); diff --git a/tools/sdk-tools/adpcm/vencode.c b/tools/sdk-tools/adpcm/vencode.c index 6d5b4ab3a..bda2f871c 100644 --- a/tools/sdk-tools/adpcm/vencode.c +++ b/tools/sdk-tools/adpcm/vencode.c @@ -126,7 +126,7 @@ void vencodeframe(FILE *ofile, s16 *inBuffer, s32 *state, s32 ***coefTable, s32 max = 0; for (i = 0; i < 16; i++) { - if (fabs(ie[i]) > fabs(max)) + if (fabs((f32)ie[i]) > fabs((f32)max)) { max = ie[i]; } diff --git a/tools/sdk-tools/adpcm/vpredictor.c b/tools/sdk-tools/adpcm/vpredictor.c index 3c35e2fcb..5af107ebb 100644 --- a/tools/sdk-tools/adpcm/vpredictor.c +++ b/tools/sdk-tools/adpcm/vpredictor.c @@ -9,8 +9,14 @@ s32 readcodebook(FILE *fhandle, s32 ****table, s32 *order, s32 *npredictors) s32 j; s32 k; - fscanf(fhandle, "%d", order); - fscanf(fhandle, "%d", npredictors); + if (fscanf(fhandle, "%d", order) != 1) { + printf("I/O error occurred."); + exit(1); + }; + if (fscanf(fhandle, "%d", npredictors) != 1) { + printf("I/O error occurred."); + exit(1); + }; *table = malloc(*npredictors * sizeof(s32 **)); for (i = 0; i < *npredictors; i++) { @@ -28,7 +34,10 @@ s32 readcodebook(FILE *fhandle, s32 ****table, s32 *order, s32 *npredictors) { for (k = 0; k < 8; k++) { - fscanf(fhandle, "%d", &table_entry[k][j]); + if (fscanf(fhandle, "%d", &table_entry[k][j]) != 1) { + printf("I/O error occurred."); + exit(1); + }; } } @@ -63,9 +72,15 @@ s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors) s32 k; s16 ts; - fread(order, sizeof(s16), 1, fhandle); + if (fread(order, sizeof(s16), 1, fhandle) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(*order) - fread(npredictors, sizeof(s16), 1, fhandle); + if (fread(npredictors, sizeof(s16), 1, fhandle) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(*npredictors) *table = malloc(*npredictors * sizeof(s32 **)); for (i = 0; i < *npredictors; i++) @@ -84,7 +99,10 @@ s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors) { for (k = 0; k < 8; k++) { - fread(&ts, sizeof(s16), 1, fhandle); + if (fread(&ts, sizeof(s16), 1, fhandle) != 1) { + printf("I/O error occurred."); + exit(1); + }; BSWAP16(ts) table_entry[k][j] = ts; } diff --git a/tools/sdk-tools/tabledesign/Makefile b/tools/sdk-tools/tabledesign/Makefile index a06d70af3..a3f1740a9 100644 --- a/tools/sdk-tools/tabledesign/Makefile +++ b/tools/sdk-tools/tabledesign/Makefile @@ -6,7 +6,7 @@ IRIX_CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc IRIX_CFLAGS := -fullwarn -Wab,-r4300_mul -Xcpluscomm -mips1 -O2 NATIVE_CC := gcc -NATIVE_CFLAGS := -Wall -Wno-uninitialized -O2 +NATIVE_CFLAGS := -Wall -O2 LDFLAGS := -lm -laudiofile diff --git a/tools/sdk-tools/tabledesign/estimate.c b/tools/sdk-tools/tabledesign/estimate.c index da2b4e88b..5507ed87b 100644 --- a/tools/sdk-tools/tabledesign/estimate.c +++ b/tools/sdk-tools/tabledesign/estimate.c @@ -4,7 +4,7 @@ /** * Computes the autocorrelation of a vector. More precisely, it computes the - * dot products of vec[i:] and vec[:-i] for i in [0, k). Unused. + * dot products of vec[i:] and vec[:-i] for i in (0, k). Unused. * * See https://en.wikipedia.org/wiki/Autocorrelation. */ @@ -244,7 +244,7 @@ void acvect(short *in, int n, int m, double *out) */ int lud(double **a, int n, int *indx, int *d) { - int i,imax,j,k; + int i,imax=0,j,k; double big,dum,sum,temp; double min,max; double *vv;