diff --git a/Dockerfile b/Dockerfile index b3200018c0..3adaa86042 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:18.04 as build RUN apt-get update && \ + apt-get upgrade && \ apt-get install -y \ binutils-mips-linux-gnu \ bsdmainutils \ diff --git a/Makefile b/Makefile index 621aedd9a3..a055c72899 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,8 @@ 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 # Enable extended options menu by default EXT_OPTIONS_MENU ?= 1 # Disable text-based save-files by default @@ -102,10 +102,22 @@ ifeq ($(WINDOWS_BUILD),1) TARGET_ARCH = i386pe TARGET_BITS = 32 NO_BZERO_BCOPY := 1 + NO_PIE = 0 else ifeq ($(CROSS),x86_64-w64-mingw32.static-) + TARGET_ARCH = i386pep + TARGET_BITS = 64 + NO_BZERO_BCOPY := 1 + NO_PIE = 0 + else ifeq ($(CROSS),mxe-i686-w64-mingw32.static-) TARGET_ARCH = i386pe + TARGET_BITS = 32 + NO_BZERO_BCOPY := 1 + NO_PIE = 0 + else ifeq ($(CROSS),mxe-x86_64-w64-mingw32.static-) + TARGET_ARCH = i386pep TARGET_BITS = 64 NO_BZERO_BCOPY := 1 + NO_PIE = 0 endif endif @@ -117,14 +129,11 @@ 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. @@ -132,9 +141,6 @@ ifeq ($(VERSION),sh) else $(error unknown version "$(VERSION)") endif -endif -endif -endif TARGET := sm64.$(VERSION) VERSION_CFLAGS := -D$(VERSION_DEF) -D_LANGUAGE_C @@ -155,34 +161,26 @@ 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_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 @@ -227,8 +225,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 +242,6 @@ ifeq ($(DUMMY),FAIL) $(error Failed to build tools) endif -endif endif ################ Target Executable and Sources ############### @@ -263,17 +259,12 @@ 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 +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 @@ -319,34 +310,32 @@ ifeq ($(TARGET_WEB),1) endif ifeq ($(TARGET_RPI),1) - machine = $(shell sh -c 'uname -m 2>/dev/null || echo unknown') + 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 + ifneq (,$(findstring armv6l,$(machine))) + 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 +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 @@ -457,6 +446,10 @@ else ifeq ($(WINDOWS_BUILD),1) LD := $(CC) else ifeq ($(CROSS),x86_64-w64-mingw32.static-) LD := $(CC) + else ifeq ($(CROSS),mxe-i686-w64-mingw32.static-) + LD := $(CC) + else ifeq ($(CROSS),mxe-x86_64-w64-mingw32.static-) + LD := $(CC) else LD := $(CXX) endif @@ -484,7 +477,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 +534,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 @@ -581,10 +573,10 @@ 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 extended options menu option @@ -642,7 +634,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 +716,7 @@ clean: $(RM) -r $(BUILD_DIR_BASE) cleantools: - $(MAKE) -s -C tools clean + $(MAKE) -C tools clean distclean: $(RM) -r $(BUILD_DIR_BASE) @@ -787,7 +779,7 @@ $(BUILD_DIR)/text/%/define_courses.inc.c: text/define_courses.inc.c text/%/cours $(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) @@ -996,7 +988,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 609222f0c0..d67c6cbb3a 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 1a99617fd8..5d8aa8541e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Please contribute **first** to the [nightly branch](https://github.com/sm64pc/sm * 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). + * 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. diff --git a/actors/boo/geo.inc.c b/actors/boo/geo.inc.c index 4fa9721bc1..d0c7e29d63 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 1b3ee4f3ac..f20d4b06c3 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 b5629c8d59..157ab697a7 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 d7e2a85f61..d1e967c595 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 bcf4fd6f4d..d62aee3ada 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 ad33677334..d54d73eea5 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 eb963a7e59..10ed51658f 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 81c017d123..726f9fc258 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 23fd462c01..b22d7e9078 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/hoot/geo.inc.c b/actors/hoot/geo.inc.c index e415a49201..c76e3e44c7 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 5b7ced61bf..b1265ad196 100644 --- a/actors/king_bobomb/geo.inc.c +++ b/actors/king_bobomb/geo.inc.c @@ -115,6 +115,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/koopa/model.inc.c b/actors/koopa/model.inc.c index 6bf2418765..12f535dafd 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 70dea53edf..6a6520e7b1 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 58948b5b11..c434113f4e 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 2d1db035b5..287cb9ec2f 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 a8aabeccf3..fddb7aca38 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/demo_data.json b/assets/demo_data.json index 5993222b51..5def715064 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. @@ -22,14 +22,15 @@ {"demofile":"bitdw", "ifdef":["VERSION_US"]}, /* Whomp's Fortress has the wrong size. - The original entries probably manually input the sizes. */ + The original entries probably manually input the sizes. + The unused demo will be showing up with the CCM demo's header in QOL_FIXES. */ {"demofile":"wf", "extraSize":368}, - {"demofile":"ccm"}, {"demofile":"bbh"}, {"demofile":"jrb"}, {"demofile":"hmc"}, - {"demofile":"pss"} + {"demofile":"pss"}, + {"demofile":"unused", "ifdef":["QOL_FIXES"]} ], "demofiles": [ {"name":"bbh"}, diff --git a/include/PR/os_libc.h b/include/PR/os_libc.h index 9eb872e79d..08afbc93c8 100644 --- a/include/PR/os_libc.h +++ b/include/PR/os_libc.h @@ -17,7 +17,7 @@ #undef bzero #undef bcopy #define bzero(buf, len) memset((buf), 0, (len)) -#define bcopy(src, dst, len) memcpy((dst), (src), (len)) +#define bcopy(src, dst, len) memmove((dst), (src), (len)) #else diff --git a/include/dxsdk/d3dx12.h b/include/dxsdk/d3dx12.h index 3aafbd252d..59e28948c4 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/model_ids.h b/include/model_ids.h index 1cd0a25392..d9e4df3739 100644 --- a/include/model_ids.h +++ b/include/model_ids.h @@ -215,6 +215,7 @@ #define MODEL_VCUTM_CHECKERBOARD_PLATFORM_SPAWNER 0x37 //! @bug this object doesn't have a geo associated with it, yet is placed in vcutm. // This causes a crash when the player quickly looks towards the // checkerboard platforms after spawning but before it is unloaded. + // This is partially fixed by having the game load a null model in QOL_FIXES. // bitfs #define MODEL_BITFS_PLATFORM_ON_TRACK 0x36 // bitfs_geo_000758 diff --git a/include/object_constants.h b/include/object_constants.h index 82a1676974..d27762c3fe 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_TRANSPARENT_STAR 3 + #endif /* Bird */ /* oAction */ diff --git a/include/stb/stb_image.h b/include/stb/stb_image.h index d9c21bc813..f2dadeff08 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); @@ -3912,17 +4110,19 @@ stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { - int b,s,k; + int s,k; + unsigned int b; // not resolved by fast table, so compute it the slow way // use jpeg approach, which requires MSbits at top k = stbi__bit_reverse(a->code_buffer, 16); 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 (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 +4131,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 +4150,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 +4257,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 +4288,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 +4310,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 +4572,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 +4941,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 +4967,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 +5087,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 +5119,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 +5225,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 +5246,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 +5260,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 +5270,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 +5283,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 +5329,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 +5378,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 +5389,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 +5426,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 +5440,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 +5475,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 +5493,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 +5535,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 +5715,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 +5760,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 +5888,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 +5973,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 +6039,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 +6330,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 +6381,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 +6442,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 +6472,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 +6481,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 +6595,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 +6633,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 +6680,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 +6703,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 +6726,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 +6735,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 +6770,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 +6792,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 +6852,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 +6861,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 +6996,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 +7146,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 +7313,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 +7540,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 c05e95812b..a685b9e7b8 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/types.h b/include/types.h index b3dc27e276..19b46a1cac 100644 --- a/include/types.h +++ b/include/types.h @@ -291,7 +291,11 @@ struct MarioState /*0x0C*/ u32 action; /*0x10*/ u32 prevAction; /*0x14*/ u32 terrainSoundAddend; + #ifdef QOL_FIXES + /*0x18*/ u32 actionState; + #else /*0x18*/ u16 actionState; + #endif /*0x1A*/ u16 actionTimer; /*0x1C*/ u32 actionArg; /*0x20*/ f32 intendedMag; @@ -329,10 +333,17 @@ struct MarioState /*0x9C*/ struct Controller *controller; /*0xA0*/ struct MarioAnimation *animation; /*0xA4*/ u32 collidedObjInteractTypes; + #ifndef QOL_FIXES /*0xA8*/ s16 numCoins; /*0xAA*/ s16 numStars; /*0xAC*/ s8 numKeys; // Unused key mechanic /*0xAD*/ s8 numLives; + #else + /*0xA8*/ u64 numCoins; + /*0xAA*/ u64 numStars; + /*0xAC*/ u64 numKeys; // Unused key mechanic + /*0xAD*/ u64 numLives; + #endif /*0xAE*/ s16 health; /*0xB0*/ s16 unkB0; /*0xB2*/ u8 hurtCounter; diff --git a/levels/castle_grounds/areas/1/11/geo.inc.c b/levels/castle_grounds/areas/1/11/geo.inc.c index e5127f1d02..50467408fb 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 1bff304785..c59c237299 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/ttm/areas/1/14/geo.inc.c b/levels/ttm/areas/1/14/geo.inc.c index 98ee9baae6..ec6da394dd 100644 --- a/levels/ttm/areas/1/14/geo.inc.c +++ b/levels/ttm/areas/1/14/geo.inc.c @@ -7,6 +7,11 @@ const GeoLayout ttm_geo_000920[] = { GEO_DISPLAY_LIST(LAYER_OPAQUE, ttm_seg7_dl_0700DF78), GEO_OPEN_NODE(), GEO_CLOSE_NODE(), - //! Too many open nodes. Unfortunately not exploitable - GEO_END(), + #ifndef QOL_FIXES + //! Too many open nodes. Unfortunately not exploitable + #else + GEO_CLOSE_NODE(), + GEO_CLOSE_NODE(), + #endif + GEO_END(), }; diff --git a/levels/vcutm/script.c b/levels/vcutm/script.c index fb52c9569f..bbcdb308e0 100644 --- a/levels/vcutm/script.c +++ b/levels/vcutm/script.c @@ -19,7 +19,9 @@ static const LevelScript script_func_local_1[] = { OBJECT(/*model*/ MODEL_VCUTM_SEESAW_PLATFORM, /*pos*/ 154, -1919, -6256, /*angle*/ 0, 270, 0, /*behParam*/ 0x00070000, /*beh*/ bhvSeesawPlatform), OBJECT(/*model*/ MODEL_VCUTM_SEESAW_PLATFORM, /*pos*/ -2047, -3378, -2047, /*angle*/ 0, 0, 0, /*behParam*/ 0x00070000, /*beh*/ bhvSeesawPlatform), + #ifndef QOL_FIXES //! @bug invalid model IDs - model ID 0x37 isn't loaded + #endif OBJECT(/*model*/ MODEL_VCUTM_CHECKERBOARD_PLATFORM_SPAWNER, /*pos*/ 3251, -1082, -6256, /*angle*/ 0, 270, 0, /*behParam*/ 0x014B0000, /*beh*/ bhvCheckerboardElevatorGroup), OBJECT(/*model*/ MODEL_VCUTM_CHECKERBOARD_PLATFORM_SPAWNER, /*pos*/ 2355, -1901, -6256, /*angle*/ 0, 270, 0, /*behParam*/ 0x014B0000, /*beh*/ bhvCheckerboardElevatorGroup), OBJECT(/*model*/ MODEL_VCUTM_CHECKERBOARD_PLATFORM_SPAWNER, /*pos*/ 1459, -1594, -6256, /*angle*/ 0, 90, 0, /*behParam*/ 0x014B0000, /*beh*/ bhvCheckerboardElevatorGroup), @@ -50,6 +52,11 @@ const LevelScript level_vcutm_entry[] = { JUMP_LINK(script_func_global_1), JUMP_LINK(script_func_global_9), LOAD_MODEL_FROM_GEO(MODEL_VCUTM_SEESAW_PLATFORM, vcutm_geo_0001F0), + #ifdef QOL_FIXES + // hard to tell exactly what was supposed to be loaded here, so load a blank model for now + // if anyone figures this out, PLEASE update this + 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), diff --git a/src/audio/heap.c b/src/audio/heap.c index a183a70747..8c9c46ff67 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -557,9 +557,14 @@ void func_eu_802e27e4_unused(f32 arg0, f32 arg1, u16 *arg2) { tmp[9] = (f32) (((arg0 * arg0) + arg1) * 262159.0f); for (i = 2; i < 8; i++) { + #ifndef QOL_FIXES //! @bug they probably meant to store the value to tmp[i] and tmp[8 + i] 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/load.c b/src/audio/load.c index d4c27b746f..45f67f0d5f 100644 --- a/src/audio/load.c +++ b/src/audio/load.c @@ -485,7 +485,7 @@ void patch_audio_bank(struct AudioBank *mem, u8 *offset, u32 numInstruments, u32 drum = PATCH(patched, mem); mem->drums[i] = drum; if (drum->loaded == 0) { -#ifndef VERSION_EU +#if !defined(VERSION_EU) || !defined(QOL_FIXES) //! copt replaces drum with 'patched' for these two lines PATCH_SOUND(&(*(struct Drum *)patched).sound, mem, offset); patched = (*(struct Drum *)patched).envelope; @@ -789,7 +789,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; diff --git a/src/audio/seq_channel_layer_process_script.h b/src/audio/seq_channel_layer_process_script.h index 17f6733585..2541e4187b 100644 --- a/src/audio/seq_channel_layer_process_script.h +++ b/src/audio/seq_channel_layer_process_script.h @@ -271,6 +271,7 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) { case 0xc4: // layer_somethingon case 0xc5: // layer_somethingoff + #ifndef QOL_FIXES //! copt needs a ternary: //layer->continuousNotes = (cmd == 0xc4) ? TRUE : FALSE; if (cmd == 0xc4) { @@ -278,6 +279,9 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) { } else { temp8 = FALSE; } + #else + temp8 = layer->continuousNotes = (cmd == 0xc4) ? TRUE : FALSE; + #endif layer->continuousNotes = temp8; seq_channel_layer_note_decay(layer); break; @@ -427,6 +431,7 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) { } if (layer->portamento.mode != 0) { + #ifndef QOL_FIXES //! copt needs a ternary: //usedSemitone = (layer->portamentoTargetNote < SEMITONE) ? SEMITONE : layer->portamentoTargetNote; if (layer->portamentoTargetNote < SEMITONE) { @@ -434,6 +439,9 @@ void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) { } else { USED_SEMITONE = layer->portamentoTargetNote; } + #else + USED_SEMITONE = (layer->portamentoTargetNote < SEMITONE) ? SEMITONE : layer->portamentoTargetNote; + #endif if (instrument != NULL) { sound = (u8) USED_SEMITONE < instrument->normalRangeLo ? &instrument->lowNotesSound diff --git a/src/engine/math_util.c b/src/engine/math_util.c index ca2a74571a..df27ee0daa 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -12,17 +12,17 @@ Vec4s *gSplineKeyframe; float gSplineKeyframeFraction; int gSplineState; -// These functions have bogus return values. -// Disable the compiler warning. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreturn-local-addr" +// These functions have bogus return values +// unless QOL_FIXES is set to 1. /// Copy vector 'src' to 'dest' void *vec3f_copy(Vec3f dest, Vec3f src) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Set vector 'dest' to (x, y, z) @@ -30,7 +30,9 @@ void *vec3f_set(Vec3f dest, f32 x, f32 y, f32 z) { dest[0] = x; dest[1] = y; dest[2] = z; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Add vector 'a' to 'dest' @@ -38,7 +40,9 @@ void *vec3f_add(Vec3f dest, Vec3f a) { dest[0] += a[0]; dest[1] += a[1]; dest[2] += a[2]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Make 'dest' the sum of vectors a and b. @@ -46,7 +50,9 @@ 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]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Multiply vector 'dest' by a @@ -55,7 +61,9 @@ void *vec3f_mul(Vec3f dest, f32 a) dest[0] *= a; dest[1] *= a; dest[2] *= a; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Copy vector src to dest @@ -63,7 +71,9 @@ void *vec3s_copy(Vec3s dest, Vec3s src) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Set vector 'dest' to (x, y, z) @@ -71,7 +81,9 @@ void *vec3s_set(Vec3s dest, s16 x, s16 y, s16 z) { dest[0] = x; dest[1] = y; dest[2] = z; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Add vector a to 'dest' @@ -79,7 +91,9 @@ void *vec3s_add(Vec3s dest, Vec3s a) { dest[0] += a[0]; dest[1] += a[1]; dest[2] += a[2]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Make 'dest' the sum of vectors a and b. @@ -87,7 +101,9 @@ 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]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Make 'dest' the difference of vectors a and b. @@ -95,7 +111,9 @@ 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]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Convert short vector a to float vector 'dest' @@ -103,7 +121,9 @@ void *vec3s_to_vec3f(Vec3f dest, Vec3s a) { dest[0] = a[0]; dest[1] = a[1]; dest[2] = a[2]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /** @@ -115,7 +135,9 @@ 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); - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /** @@ -127,7 +149,9 @@ 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]); - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Make vector 'dest' the cross product of vectors a and b. @@ -135,18 +159,32 @@ 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]; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Scale vector 'dest' so it has length 1 void *vec3f_normalize(Vec3f dest) { - //! Possible division by zero - f32 invsqrt = 1.0f / sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]); + #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 = 0.0f; + // Fix the division by zero warning by multiplying by 0 when the sqrtf equation happens to equal 0 + if (sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]) != 0) { + invsqrt = 1.0f / sqrtf(dest[0] * dest[0] + dest[1] * dest[1] + dest[2] * dest[2]); + } else { + invsqrt = 1.0f * 0.0f; + } + #endif dest[0] *= invsqrt; dest[1] *= invsqrt; dest[2] *= invsqrt; - return &dest; //! warning: function returns address of local variable + #ifndef QOL_FIXES + return &dest; //! warning: function returns address of local variable + #endif } /// Get length of vector 'a' @@ -161,8 +199,6 @@ f32 vec3f_dot(Vec3f a, Vec3f b) return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } -#pragma GCC diagnostic pop - /// Copy matrix 'src' to 'dest' void mtxf_copy(Mat4 dest, Mat4 src) { register s32 i; diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 1da535b9b6..473be3ecea 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -313,7 +313,7 @@ f32 find_ceil(f32 posX, f32 posY, f32 posZ, struct Surface **pceil) { s16 x, y, z; //! (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.) x = (s16) posX; y = (s16) posY; diff --git a/src/game/behaviors/bowling_ball.inc.c b/src/game/behaviors/bowling_ball.inc.c index f1e16cb135..72f3b5a6a1 100644 --- a/src/game/behaviors/bowling_ball.inc.c +++ b/src/game/behaviors/bowling_ball.inc.c @@ -78,12 +78,17 @@ 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 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 + // Fixed in QOL_FIXES sp18 = cur_obj_follow_path(sp18); o->oBowlingBallTargetYaw = o->oPathedTargetYaw; @@ -108,11 +113,16 @@ void bhv_bowling_ball_roll_loop(void) { } void bhv_bowling_ball_initializeLoop(void) { + #ifndef QOL_FIXES s32 sp1c; + #else + s32 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 + // Fixed in QOL_FIXES sp1c = cur_obj_follow_path(sp1c); o->oMoveAngleYaw = o->oPathedTargetYaw; @@ -260,7 +270,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/bully.inc.c b/src/game/behaviors/bully.inc.c index efe0ee1800..75dd9e350b 100644 --- a/src/game/behaviors/bully.inc.c +++ b/src/game/behaviors/bully.inc.c @@ -121,8 +121,12 @@ void bully_act_back_up(void) { // will be stuck in BULLY_ACT_BACK_UP forever until Mario hits it or its death // conditions are activated. However because its angle is set to its facing angle, // it will walk forward instead of backing up. - + // A potential fix for this is used in QOL_FIXES. + #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; diff --git a/src/game/behaviors/castle_floor_trap.inc.c b/src/game/behaviors/castle_floor_trap.inc.c index 9eeddbb4c4..067e271869 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) - cur_obj_play_sound_2(SOUND_GENERAL_CASTLE_TRAP_OPEN); + #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/falling_rising_platform.inc.c b/src/game/behaviors/falling_rising_platform.inc.c index 4bd7ecd532..3b38dd04c2 100644 --- a/src/game/behaviors/falling_rising_platform.inc.c +++ b/src/game/behaviors/falling_rising_platform.inc.c @@ -6,9 +6,14 @@ void bhv_squishable_platform_loop(void) { } void bhv_bitfs_sinking_platform_loop(void) { + // remove the conversion entirely in QOL_FIXES + #ifndef QOL_FIXES o->oPosY -= sins(o->oPlatformTimer) * 0.58; //! f32 double conversion error accumulates on Wii VC causing the platform to rise up + #else + o->oPosY -= sins(o->oPlatformTimer) * 0.58f; + #endif o->oPlatformTimer += 0x100; } diff --git a/src/game/behaviors/fish.inc.c b/src/game/behaviors/fish.inc.c index d169ecf78b..d7919490f7 100644 --- a/src/game/behaviors/fish.inc.c +++ b/src/game/behaviors/fish.inc.c @@ -8,31 +8,40 @@ * These settings are animations, colour, and spawn quantity. * Fish spawning restricted to within a set distance from Mario. */ + +#ifdef NODRAWINGDISTANCE +#include "macros.h" +#endif + 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/klepto.inc.c b/src/game/behaviors/klepto.inc.c index 22ab3e8fb7..99674a4a53 100644 --- a/src/game/behaviors/klepto.inc.c +++ b/src/game/behaviors/klepto.inc.c @@ -75,7 +75,14 @@ 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_TRANSPARENT_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; @@ -364,7 +371,13 @@ void bhv_klepto_update(void) { spawn_object(o, MODEL_MARIOS_CAP, bhvNormalCap); } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_STAR) { spawn_default_star(-5550.0f, 300.0f, -930.0f); + #ifndef QOL_FIXES } + #else + } else if (o->oAnimState == KLEPTO_ANIM_STATE_HOLDING_TRANSPARENT_STAR) { + spawn_default_star(-5550.0f, 300.0f, -930.0f); + } + #endif o->oAnimState = KLEPTO_ANIM_STATE_HOLDING_NOTHING; o->oAction = KLEPTO_ACT_STRUCK_BY_MARIO; diff --git a/src/game/behaviors/pokey.inc.c b/src/game/behaviors/pokey.inc.c index cfcc92c265..009d9dd2f7 100644 --- a/src/game/behaviors/pokey.inc.c +++ b/src/game/behaviors/pokey.inc.c @@ -75,8 +75,14 @@ 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. + // Partially fixed for now (a full fix is planned) in QOL_FIXES + #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 824d24f2b5..12114eea72 100644 --- a/src/game/behaviors/pyramid_top.inc.c +++ b/src/game/behaviors/pyramid_top.inc.c @@ -96,6 +96,9 @@ void bhv_pyramid_top_loop(void) { if (o->oPyramidTopPillarsTouched == 4) { play_puzzle_jingle(); o->oAction = PYRAMID_TOP_ACT_SPINNING; + #ifdef QOL_FIXES + cutscene_pyramid_top_explode(); + #endif } break; @@ -113,6 +116,9 @@ void bhv_pyramid_top_loop(void) { } bhv_pyramid_top_explode(); + #ifdef QOL_FIXES + cutscene_pyramid_top_explode_end(); + #endif break; } } diff --git a/src/game/behaviors/seaweed.inc.c b/src/game/behaviors/seaweed.inc.c index d1dc2b469e..002aabcde0 100644 --- a/src/game/behaviors/seaweed.inc.c +++ b/src/game/behaviors/seaweed.inc.c @@ -15,6 +15,10 @@ void bhv_seaweed_bundle_init(void) { seaweed->header.gfx.scale[1] = 1.0; seaweed->header.gfx.scale[2] = 1.0; //! gfx.animFrame uninitialized + // fixed in QOL_FIXES + #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/tilting_inverted_pyramid.inc.c b/src/game/behaviors/tilting_inverted_pyramid.inc.c index ebce64fc96..4ac62166c7 100644 --- a/src/game/behaviors/tilting_inverted_pyramid.inc.c +++ b/src/game/behaviors/tilting_inverted_pyramid.inc.c @@ -90,11 +90,16 @@ 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); //! Always true since dy = 500, making d >= 500. + // fixed above in QOL_FIXES if (d != 0.0f) { // Normalizing d = 1.0 / d; diff --git a/src/game/behaviors/tuxie.inc.c b/src/game/behaviors/tuxie.inc.c index 1dae585011..6da3353508 100644 --- a/src/game/behaviors/tuxie.inc.c +++ b/src/game/behaviors/tuxie.inc.c @@ -74,7 +74,12 @@ void tuxies_mother_act_1(void) { // o->prevObj->oUnknownUnk88 &= ~INT_SUBTYPE_DROP_IMMEDIATELY // which has no effect as o->prevObj->oUnknownUnk88 is always 0 // or 1, which is not affected by the bitwise AND. + // fix attempted in QOL_FIXES + #ifndef QOL_FIXES o->prevObj->OBJECT_FIELD_S32(o->oInteractionSubtype) &= ~INT_SUBTYPE_DROP_IMMEDIATELY; + #else + o->prevObj->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); @@ -87,7 +92,12 @@ void tuxies_mother_act_1(void) { case 2: if (o->prevObj->oHeldState == HELD_FREE) { //! Same bug as above + // fix attempted in QOL_FIXES + #ifndef QOL_FIXES o->prevObj->OBJECT_FIELD_S32(o->oInteractionSubtype) &= ~INT_SUBTYPE_DROP_IMMEDIATELY; + #else + o->prevObj->oInteractionSubtype &= ~INT_SUBTYPE_DROP_IMMEDIATELY; + #endif obj_set_behavior(o->prevObj, bhvPenguinBaby); o->oAction = 2; } diff --git a/src/game/behaviors/water_ring.inc.c b/src/game/behaviors/water_ring.inc.c index 5fa6efb858..569ef7345a 100644 --- a/src/game/behaviors/water_ring.inc.c +++ b/src/game/behaviors/water_ring.inc.c @@ -21,6 +21,7 @@ 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. + // This is documented, but more research is needed on the fix for QOL_FIXES o->oWaterRingNormalX = coss(o->oFaceAnglePitch) * sins(o->oFaceAngleRoll) * -1.0f; o->oWaterRingNormalY = coss(o->oFaceAnglePitch) * coss(o->oFaceAngleRoll); o->oWaterRingNormalZ = sins(o->oFaceAnglePitch); diff --git a/src/game/camera.c b/src/game/camera.c index bde066264c..6810dd0a27 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -664,11 +664,16 @@ 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)) { //! @bug this should use sMarioGeometry.waterHeight + // the variable itself is initialized to sMarioGeometry.waterHeight in QOL_FIXES if (floorHeight < (waterHeight = find_water_level(sMarioCamState->pos[0], sMarioCamState->pos[2]))) { floorHeight = waterHeight; } @@ -1578,9 +1583,11 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { } focusDistance = calc_abs_dist(sMarioCamState->pos, secondFocus) * 1.6f; + #ifndef QOL_FIXES if (focusDistance < 800.f) { focusDistance = 800.f; } + #endif if (focusDistance > 5000.f) { focusDistance = 5000.f; } @@ -1609,9 +1616,18 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { switch (gCurrLevelArea) { case AREA_BOB: pos[1] += 125.f; + #ifndef QOL_FIXES //! fall through, makes the BoB boss fight camera move up twice as high as it should + #else + break; + #endif case AREA_WF: pos[1] += 125.f; + // what if there's other bosses that have their boss fight cameras set here by mods? + // fix them with QOL_FIXES + #ifdef QOL_FIXES + break; + #endif } } @@ -1639,10 +1655,14 @@ s32 update_boss_fight_camera(struct Camera *c, Vec3f focus, Vec3f pos) { : -gMarioStates[0].angleVel[1]); } + #ifdef QOL_FIXES //! Unnecessary conditional, focusDistance is already bounded to 800 + // Under QOL_FIXES, this conditional takes effect instead of the other conditional that sets + // focusDistance's minimum bound to 800 if (focusDistance < 400.f) { focusDistance = 400.f; } + #endif // Set C-Down distance and pitch. // C-Down will essentially double the distance from the center. @@ -1781,10 +1801,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; @@ -2195,12 +2217,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 +2481,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); @@ -2924,14 +2952,17 @@ void update_lakitu(struct Camera *c) { if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) { } else { if (c->cutscene) { + #ifndef QOL_FIXES } 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; } else { //! dead code, moved to next_lakitu_state() + // no longer dead in QOL_FIXES vec3f_copy(newPos, c->pos); vec3f_copy(newFoc, c->focus); } @@ -4819,13 +4850,22 @@ 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) + // QOL_FIXES makes an attempt to fix this 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 +4937,11 @@ 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 if ((gCameraMovementFlags & CAM_MOVE_ENTERED_ROTATE_SURFACE) || !(gCameraMovementFlags & CAM_MOVE_ROTATE)) { @@ -4996,6 +5040,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { } //! returning uninitialized variable + // fixed in QOL_FIXES return dummy; } @@ -5172,8 +5217,13 @@ 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 + // This seemingly errant behavior is removed when QOL_FIXES=1 + #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); @@ -5386,8 +5436,12 @@ void offset_rotated(Vec3f dst, Vec3f from, Vec3f to, Vec3s rotation) { vec3f_copy(unusedCopy, from); // First rotate the direction by rotation's pitch + #ifndef QOL_FIXES //! The Z axis is flipped here. pitchRotated[2] = -(to[2] * coss(rotation[0]) - to[1] * sins(rotation[0])); + #else + pitchRotated[2] = to[2] * coss(rotation[0]) - to[1] * sins(rotation[0]); + #endif pitchRotated[1] = to[2] * sins(rotation[0]) + to[1] * coss(rotation[0]); pitchRotated[0] = to[0]; @@ -6310,8 +6364,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 +6389,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 }, @@ -6590,6 +6648,7 @@ s16 camera_course_processing(struct Camera *c) { sCameraTriggers[level][b].boundsY, sCameraTriggers[level][b].boundsZ); + #ifndef QOL_FIXES // Check if Mario is inside the bounds if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, sCameraTriggers[level][b].boundsYaw) == TRUE) { @@ -6600,6 +6659,15 @@ s16 camera_course_processing(struct Camera *c) { insideBounds = TRUE; } } + #else + if (!(sStatusFlags & CAM_FLAG_BLOCK_AREA_PROCESSING)) { + if (is_pos_in_bounds(sMarioCamState->pos, center, bounds, + sCameraTriggers[level][b].boundsYaw) == TRUE) { + sCameraTriggers[level][b].event(c); + insideBounds = TRUE; + } + } + #endif } if ((sCameraTriggers[level])[b].area == -1) { @@ -6705,8 +6773,13 @@ 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 + // maybe the above was supposed to be the following instead + set_mode_if_not_set_by_surface(c, CAMERA_MODE_OUTWARD_RADIAL); + #endif break; case AREA_DDD_SUB: @@ -6722,8 +6795,13 @@ s16 camera_course_processing(struct Camera *c) { } } } + #ifndef QOL_FIXES //! @bug this does nothing gLakituState.defMode = CAMERA_MODE_FREE_ROAM; + #else + // maybe the above was supposed to be the following instead + set_mode_if_not_set_by_surface(c, CAMERA_MODE_FREE_ROAM); + #endif break; } } @@ -7035,7 +7113,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 @@ -7480,9 +7562,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 } /** @@ -9232,11 +9319,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 } /** @@ -10347,7 +10439,12 @@ BAD_RETURN(s32) cutscene_door_fix_cam(struct Camera *c) { */ BAD_RETURN(s32) cutscene_door_loop(struct Camera *c) { //! bitwise AND instead of boolean + // fixed with QOL_FIXES + #ifndef QOL_FIXES 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 +10463,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); } @@ -11308,7 +11409,12 @@ void play_cutscene(struct Camera *c) { if ((cutsceneDuration != 0) && !(gCutsceneTimer & CUTSCENE_STOP)) { //! @bug This should check for 0x7FFF (CUTSCENE_LOOP) //! instead, cutscenes that last longer than 0x3FFF frames will never end on their own + // fixed with QOL_FIXES + #ifndef QOL_FIXES 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 +11639,11 @@ Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context) approach_fov_60(marioState); break; //! No default case + // fixed by QOL_FIXES + #ifdef QOL_FIXES + default: + break; + #endif } } diff --git a/src/game/camera.h b/src/game/camera.h index 173ab8a756..f2fdf57d4c 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -232,7 +232,7 @@ #define CUTSCENE_DANCE_FLY_AWAY 165 #define CUTSCENE_DANCE_CLOSEUP 166 #define CUTSCENE_KEY_DANCE 167 -#define CUTSCENE_SSL_PYRAMID_EXPLODE 168 // Never activated +#define CUTSCENE_SSL_PYRAMID_EXPLODE 168 // Never activated normally. Is now activated when QOL_FIXES=1. #define CUTSCENE_EXIT_SPECIAL_SUCC 169 #define CUTSCENE_NONPAINTING_DEATH 170 #define CUTSCENE_READ_MESSAGE 171 diff --git a/src/game/debug.c b/src/game/debug.c index 66d808ed26..2ce97c119f 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); diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c index 16a927209e..5ed677491a 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c @@ -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/game_init.c b/src/game/game_init.c index c2df4510b0..e22a894ffc 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); } diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 7ae9f1e735..881121d49b 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: @@ -517,8 +534,10 @@ void print_generic_string(s16 x, s16 y, const u8 *str) { create_dl_translation_matrix(MENU_MTX_NOPUSH, 10.0f, 0.0f, 0.0f); #else create_dl_translation_matrix(MENU_MTX_NOPUSH, (f32)(gDialogCharWidths[str[strPos]]), 0.0f, 0.0f); +#if !defined(VERSION_JP) || !defined(VERSION_SH) || !defined(QOL_FIXES) break; // what an odd difference. US added a useless break here. #endif +#endif #endif } @@ -751,13 +770,21 @@ 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. + // QOL_FIXES restores the original behavior of this if statement currentIndex[0] = maxIndex; } else { play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); currentIndex[0]++; } + #else + if (currentIndex[0] >= maxIndex) { + play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs); + currentIndex[0]++; + } + #endif } if (((index ^ gMenuHoldKeyIndex) & index) == 1) { @@ -806,13 +833,16 @@ s16 get_str_x_pos_from_center_scale(s16 centerPos, u8 *str, f32 scale) { f32 spacesWidth = 0.0f; while (str[strPos] != DIALOG_CHAR_TERMINATOR) { + #if defined(VERSION_EU) && !defined(QOL_FIXES) //! EU checks for dakuten and handakuten despite dialog code unable to handle it + // fixed in QOL_FIXES if (str[strPos] == DIALOG_CHAR_SPACE) { spacesWidth += 1.0; } else if (str[strPos] != DIALOG_CHAR_DAKUTEN && str[strPos] != DIALOG_CHAR_PERIOD_OR_HANDAKUTEN) { charsWidth += 1.0; } + #endif strPos++; } // return the x position of where the string starts as half the string's @@ -1551,12 +1581,16 @@ void handle_special_dialog_text(s16 dialogID) { // dialog ID tables, in order // Red Switch, Green Switch, Blue Switch, 100 coins star, Bowser Red Coin Star s16 dialogStarSound[] = { 10, 11, 12, 13, 14 }; // King Bob-omb (Start), Whomp (Defeated), King Bob-omb (Defeated, missing in JP), Eyerock (Defeated), Wiggler (Defeated) +#ifndef QOL_FIXES #if BUGFIX_KING_BOB_OMB_FADE_MUSIC s16 dialogBossStop[] = { 17, 115, 116, 118, 152 }; #else //! @bug JP misses King Bob-omb defeated dialog "116", meaning that the boss music will still //! play after King Bob-omb is defeated until BOB loads it's music after the star cutscene s16 dialogBossStop[] = { 17, 115, 118, 152 }; +#endif +#else + s16 dialogBossStop[] = { 17, 115, 116, 118, 152 }; #endif s16 i; @@ -2599,7 +2633,11 @@ void render_pause_castle_main_strings(s16 x, s16 y) { s8 gCourseCompleteCoinsEqual = 0; s32 gCourseDoneMenuTimer = 0; +#ifndef QOL_FIXES s32 gCourseCompleteCoins = 0; +#else +u64 gCourseCompleteCoins = 0; +#endif s8 gHudFlash = 0; s16 render_pause_courses_and_castle(void) { @@ -2768,8 +2806,11 @@ void print_hud_course_complete_coins(s16 x, s16 y) { print_hud_lut_string(HUD_LUT_GLOBAL, x + 32, y, courseCompleteCoinsStr); gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); - + #ifndef QOL_FIXES if (gCourseCompleteCoins >= gHudDisplay.coins) { + #else + if (gCourseCompleteCoins >= (u64)gHudDisplay.coins) { + #endif gCourseCompleteCoinsEqual = 1; gCourseCompleteCoins = gHudDisplay.coins; @@ -2780,21 +2821,32 @@ void print_hud_course_complete_coins(s16 x, s16 y) { if ((gCourseDoneMenuTimer & 1) || gHudDisplay.coins > 70) { 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++; } } + #ifndef QOL_FIXES if (gHudDisplay.coins == gCourseCompleteCoins && gGotFileCoinHiScore != 0) { + #else + if ((u64)gHudDisplay.coins == gCourseCompleteCoins && gGotFileCoinHiScore != 0) { + #endif play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs); } } } void play_star_fanfare_and_flash_hud(s32 arg, u8 starNum) { + #ifndef QOL_FIXES if (gHudDisplay.coins == gCourseCompleteCoins && (gCurrCourseStarFlags & starNum) == 0 && gHudFlash == 0) { + #else + if ((u64)gHudDisplay.coins == gCourseCompleteCoins && (gCurrCourseStarFlags & starNum) == 0 && gHudFlash == 0) { + #endif play_star_fanfare(); gHudFlash = arg; } @@ -2966,7 +3018,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 } @@ -3074,6 +3126,7 @@ s16 render_menus_and_dialogs() { if (gMenuMode != -1) { switch (gMenuMode) { + #ifndef QOL_FIXES case 0: mode = render_pause_courses_and_castle(); break; @@ -3086,6 +3139,16 @@ s16 render_menus_and_dialogs() { case 3: mode = render_course_complete_screen(); break; + #else + case 0: + case 1: + mode = render_pause_courses_and_castle(); + break; + case 2: + case 3: + mode = render_course_complete_screen(); + break; + #endif } gDialogColorFadeTimer = (s16) gDialogColorFadeTimer + 0x1000; diff --git a/src/game/interaction.c b/src/game/interaction.c index 7a9c5203b0..1fdb941862 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -1477,7 +1477,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 defined(VERSION_SH) || defined(QOL_FIXES) f32 velConv = m->forwardVel; // conserve the velocity. struct Object *marioObj = m->marioObj; u32 lowSpeed; @@ -1488,7 +1488,7 @@ u32 interact_pole(struct MarioState *m, UNUSED u32 interactType, struct Object * mario_stop_riding_and_holding(m); -#ifdef VERSION_SH +#if defined(VERSION_SH) || defined(QOL_FIXES) lowSpeed = (velConv <= 10.0f); #endif @@ -1507,7 +1507,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 defined(VERSION_SH) || defined(QOL_FIXES) 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 72a6a6073c..827f461950 100644 --- a/src/game/level_update.c +++ b/src/game/level_update.c @@ -1,6 +1,8 @@ #include #include - +#ifdef QOL_FIXES +#include +#endif #include "sm64.h" #include "seq_ids.h" #include "dialog_ids.h" @@ -894,7 +896,11 @@ void update_hud_values(void) { gHudDisplay.flags &= ~HUD_DISPLAY_FLAG_COIN_COUNT; } + #ifndef QOL_FIXES if (gHudDisplay.coins < gMarioState->numCoins) { + #else + if ((u64)gHudDisplay.coins < gMarioState->numCoins) { + #endif if (gGlobalTimer & 0x00000001) { u32 coinSound; if (gMarioState->action & (ACT_FLAG_SWIMMING | ACT_FLAG_METAL_WATER)) { @@ -907,7 +913,7 @@ void update_hud_values(void) { play_sound(coinSound, gMarioState->marioObj->header.gfx.cameraToObject); } } - +#ifndef QOL_FIXES if (gMarioState->numLives > 100) { gMarioState->numLives = 100; } @@ -925,7 +931,21 @@ void update_hud_values(void) { gMarioState->numLives = (s8) 999; //! Wrong variable } #endif +#else + if (gMarioState->numLives > ULLONG_MAX) { + gMarioState->numLives = ULLONG_MAX; + } + if (gMarioState->numKeys > ULLONG_MAX) { + gMarioState->numKeys = ULLONG_MAX; + } + + if (gMarioState->numCoins > ULLONG_MAX) { + gMarioState->numCoins = ULLONG_MAX; + } + + gHudDisplay.coins = gMarioState->numCoins; +#endif gHudDisplay.stars = gMarioState->numStars; gHudDisplay.lives = gMarioState->numLives; gHudDisplay.keys = gMarioState->numKeys; @@ -1069,20 +1089,33 @@ void level_set_transition(s16 length, void (*updateFunction)(s16 *)) { * Play the transition and then return to normal play mode. */ s32 play_mode_change_area(void) { +#ifndef QOL_FIXES //! This maybe was supposed to be sTransitionTimer == -1? sTransitionUpdate // is never set to -1. if (sTransitionUpdate == (void (*)(s16 *)) - 1) { +#else + if (sTransitionTimer == -1) { +#endif update_camera(gCurrentArea->camera); } else if (sTransitionUpdate != NULL) { sTransitionUpdate(&sTransitionTimer); } +// set sTransitionTimer to decrement to -1 instead of 0 using this statement in QOL_FIXES +#ifndef QOL_FIXES if (sTransitionTimer > 0) { +#else + if (sTransitionTimer >= 0) { +#endif sTransitionTimer -= 1; } +#ifndef QOL_FIXES //! If sTransitionTimer is -1, this will miss. if (sTransitionTimer == 0) { +#else + if (sTransitionTimer <= 0) { +#endif sTransitionUpdate = NULL; set_play_mode(PLAY_MODE_NORMAL); } @@ -1098,8 +1131,12 @@ s32 play_mode_change_level(void) { sTransitionUpdate(&sTransitionTimer); } +#ifndef QOL_FIXES //! If sTransitionTimer is -1, this will miss. if (--sTransitionTimer == -1) { +#else + if (sTransitionTimer <= -1) { +#endif gHudDisplay.flags = HUD_DISPLAY_NONE; sTransitionTimer = 0; sTransitionUpdate = NULL; @@ -1118,7 +1155,12 @@ s32 play_mode_change_level(void) { * Unused play mode. Doesn't call transition update and doesn't reset transition at the end. */ static s32 play_mode_unused(void) { +#ifndef QOL_FIXES + //! If sTransitionTimer is -1, this will miss. if (--sTransitionTimer == -1) { +#else + if (sTransitionTimer <= -1) { +#endif gHudDisplay.flags = HUD_DISPLAY_NONE; if (sWarpDest.type != WARP_TYPE_NOT_WARPING) { diff --git a/src/game/main.c b/src/game/main.c index 88855ee5fa..58ef37d8a4 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -109,13 +109,14 @@ void unknown_main_func(void) { osSetTime(time); osMapTLB(0, b, NULL, 0, 0, 0); osUnmapTLBAll(); - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull" +#ifndef QOL_FIXES sprintf(NULL, NULL); -#pragma GCC diagnostic pop +#else + sprintf("", ""); +#endif } +#ifndef QOL_FIXES void stub_main_1(void) { } @@ -124,6 +125,7 @@ void stub_main_2(void) { void stub_main_3(void) { } +#endif void setup_mesg_queues(void) { osCreateMesgQueue(&gDmaMesgQueue, gDmaMesgBuf, ARRAY_COUNT(gDmaMesgBuf)); diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 17e45ae43f..8cca58c0b8 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -68,18 +68,13 @@ s32 check_fall_damage(struct MarioState *m, u32 hardFallAction) { fallHeight = m->peakHeight - m->pos[1]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wtype-limits" - - //! Never true + //! Only true when QOL_FIXES is set to 1 if (m->actionState == ACT_GROUND_POUND) { damageHeight = 600.0f; } else { damageHeight = 1150.0f; } -#pragma GCC diagnostic pop - if (m->action != ACT_TWIRLING && m->floor->type != SURFACE_BURNING) { if (m->vel[1] < -55.0f) { if (fallHeight > 3000.0f) { @@ -160,7 +155,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; } diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index 72e7692984..648380dcfc 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -235,11 +235,19 @@ static void stub_is_textbox_active(u16 *a0) { s32 get_star_collection_dialog(struct MarioState *m) { s32 i; s32 dialogID = 0; + #ifndef QOL_FIXES s32 numStarsRequired; + #else + u64 numStarsRequired; + #endif for (i = 0; i < 6; i++) { numStarsRequired = sStarsNeededForDialog[i]; + #ifndef QOL_FIXES if (m->prevNumStarsForDialog < numStarsRequired && m->numStars >= numStarsRequired) { + #else + if ((u64)m->prevNumStarsForDialog < numStarsRequired && m->numStars >= numStarsRequired) { + #endif dialogID = i + DIALOG_141; break; } @@ -1120,15 +1128,31 @@ s32 act_exit_land_save_dialog(struct MarioState *m) { case -1: spawn_obj_at_mario_rel_yaw(m, MODEL_BOWSER_KEY_CUTSCENE, bhvBowserKeyCourseExit, -32768); //! fall through + // fixed with QOL_FIXES + #ifdef QOL_FIXES + break; + #endif case 67: play_sound(SOUND_ACTION_KEY_SWISH, m->marioObj->header.gfx.cameraToObject); //! fall through + // fixed with QOL_FIXES + #ifdef QOL_FIXES + break; + #endif case 83: play_sound(SOUND_ACTION_PAT_BACK, m->marioObj->header.gfx.cameraToObject); //! fall through + // fixed with QOL_FIXES + #ifdef QOL_FIXES + break; + #endif case 111: play_sound(SOUND_ACTION_UNKNOWN45C, m->marioObj->header.gfx.cameraToObject); // no break + // fixed with QOL_FIXES + #ifdef QOL_FIXES + break; + #endif } handle_save_menu(m); break; @@ -1965,10 +1989,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 0ccbccf104..0643b6705f 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -383,10 +383,18 @@ void update_shell_speed(struct MarioState *m) { m->forwardVel -= 1.0f; } + #ifndef QOL_FIXES //! No backward speed cap (shell hyperspeed) if (m->forwardVel > 64.0f) { m->forwardVel = 64.0f; } + #else + if (m->forwardVel > 64.0f) { + m->forwardVel = 64.0f; + } 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); @@ -1298,6 +1306,10 @@ s32 act_crawling(struct MarioState *m) { mario_set_forward_vel(m, 10.0f); } //! Possibly unintended missing break + // fixed in QOL_FIXES + #ifdef QOL_FIXES + break; + #endif case GROUND_STEP_NONE: align_with_floor(m); diff --git a/src/game/memory.c b/src/game/memory.c index 14862ccace..29a859db59 100644 --- a/src/game/memory.c +++ b/src/game/memory.c @@ -222,7 +222,11 @@ u32 main_pool_pop_state(void) { * function blocks until completion. */ static void dma_read(u8 *dest, u8 *srcStart, u8 *srcEnd) { + #ifndef QOL_FIXES u32 size = ALIGN16(srcEnd - srcStart); + #else + UNUSED u32 size = ALIGN16(srcEnd - srcStart); + #endif memcpy(dest, srcStart, srcEnd - srcStart); } diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index 601c45f14b..0458105631 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -31,7 +31,9 @@ #include "save_file.h" #include "spawn_object.h" #include "spawn_sound.h" - +#ifdef NODRAWINGDISTANCE +#include "macros.h" +#endif /** * @file obj_behaviors.c * This file contains a portion of the obj behaviors and many helper functions for those @@ -525,10 +527,17 @@ 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) { f32 objX = obj->oPosX; f32 objY = obj->oPosY; f32 objZ = obj->oPosZ; +#else +void set_object_visibility(struct Object *obj, UNUSED s32 dist) { + UNUSED f32 objX = obj->oPosX; + UNUSED f32 objY = obj->oPosY; + UNUSED f32 objZ = obj->oPosZ; +#endif #ifndef NODRAWINGDISTANCE if (is_point_within_radius_of_mario(objX, objY, objZ, dist) == TRUE) { diff --git a/src/game/object_collision.c b/src/game/object_collision.c index 71f3268b9b..574ba9602c 100644 --- a/src/game/object_collision.c +++ b/src/game/object_collision.c @@ -57,6 +57,10 @@ int detect_object_hitbox_overlap(struct Object *a, struct Object *b) { } //! no return value + // fixed in QOL_FIXES + #ifdef QOL_FIXES + return 0; + #endif } int detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { @@ -89,6 +93,10 @@ int detect_object_hurtbox_overlap(struct Object *a, struct Object *b) { } //! no return value + // fixed in QOL_FIXES + #ifdef QOL_FIXES + return 0; + #endif } void clear_object_collision(struct Object *a) { diff --git a/src/game/object_list_processor.c b/src/game/object_list_processor.c index 7113e7c816..63871ad255 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 !defined(VERSION_JP) || (defined(VERSION_JP) && defined(QOL_FIXES)) clear_mario_platform(); #endif @@ -562,8 +562,12 @@ void clear_objects(void) { */ void update_terrain_objects(void) { gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SPAWNER]); + #ifndef QOL_FIXES //! This was meant to be += gObjectCounter = update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]); + #else + gObjectCounter += update_objects_in_list(&gObjectLists[OBJ_LIST_SURFACE]); + #endif } /** diff --git a/src/game/paintings.c b/src/game/paintings.c index 6cae19c020..8b3c735eb7 100644 --- a/src/game/paintings.c +++ b/src/game/paintings.c @@ -578,7 +578,17 @@ 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. + // Work around this in QOL_FIXES by wrapping the timer value itself (this value) + // around to 0 and back again whenever it hits 16777216 (1 << 24). + #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 diff --git a/src/game/profiler.c b/src/game/profiler.c index 9f968c6a71..266d53f0a5 100644 --- a/src/game/profiler.c +++ b/src/game/profiler.c @@ -79,12 +79,22 @@ 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. + // We work based off this hunch in QOL_FIXES + #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) { diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index d5bf577842..89468ce8eb 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -760,8 +760,14 @@ 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) { + // I don't get it either, so removing the cast for QOL_FIXES + #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/save_file.c b/src/game/save_file.c index 6c0a341822..4cd55f6a7a 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -473,7 +473,11 @@ void save_file_reload(void) { * Update the current save file after collecting a star or a key. * If coin score is greater than the current high score, update it. */ +#ifndef QOL_FIXES void save_file_collect_star_or_key(s16 coinScore, s16 starIndex) { +#else +void save_file_collect_star_or_key(u64 coinScore, s16 starIndex) { +#endif s32 fileIndex = gCurrSaveFileNum - 1; s32 courseIndex = gCurrCourseNum - 1; @@ -488,12 +492,24 @@ void save_file_collect_star_or_key(s16 coinScore, s16 starIndex) { if (courseIndex >= 0 && courseIndex < COURSE_STAGES_COUNT) { //! Compares the coin score as a 16 bit value, but only writes the 8 bit // truncation. This can allow a high score to decrease. - + // Because the coin score value was increased to a u64 in QOL_FIXES, we + // must fix this a different way than we would otherwise + + #ifndef QOL_FIXES if (coinScore > ((u16) save_file_get_max_coin_score(courseIndex) & 0xFFFF)) { sUnusedGotGlobalCoinHiScore = 1; } + #else + if (coinScore > ((u64) save_file_get_max_coin_score(courseIndex) & 0xFFFFFFFFFFFFFFFFL)) { + sUnusedGotGlobalCoinHiScore = 1; + } + #endif + #ifndef QOL_FIXES if (coinScore > save_file_get_course_coin_score(fileIndex, courseIndex)) { + #else + if (coinScore > (u64)save_file_get_course_coin_score(fileIndex, courseIndex)) { + #endif gSaveBuffer.files[fileIndex][0].courseCoinScores[courseIndex] = coinScore; touch_coin_score_age(fileIndex, courseIndex); diff --git a/src/game/save_file.h b/src/game/save_file.h index 26a0e476d2..2d79d00be9 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -126,7 +126,11 @@ void save_file_erase(s32 fileIndex); BAD_RETURN(s32) save_file_copy(s32 srcFileIndex, s32 destFileIndex); void save_file_load_all(void); void save_file_reload(void); +#ifndef QOL_FIXES void save_file_collect_star_or_key(s16 coinScore, s16 starIndex); +#else +void save_file_collect_star_or_key(u64 coinScore, s16 starIndex); +#endif s32 save_file_exists(s32 fileIndex); u32 save_file_get_max_coin_score(s32 courseIndex); s32 save_file_get_course_star_count(s32 fileIndex, s32 courseIndex); diff --git a/src/game/shadow.c b/src/game/shadow.c index 324400e5c3..1fdb318bdb 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -190,6 +190,9 @@ f32 get_water_level_below_shadow(struct Shadow *s) { } //! @bug Missing return statement. This compiles to return `waterLevel` //! incidentally. + #ifdef QOL_FIXES + return waterLevel; + #endif } /** @@ -211,11 +214,18 @@ s8 init_shadow(struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, s->floorHeight = find_floor_height_and_data(s->parentX, s->parentY, s->parentZ, &floorGeometry); + // This can lead to waterLevel being undefined if gEnvironmentRegions is 0, + // so this fix will be made for QOL_FIXES to compensate for this + #ifndef QOL_FIXES if (gEnvironmentRegions != 0) { waterLevel = get_water_level_below_shadow(s); } + #else + waterLevel = get_water_level_below_shadow(s); + #endif if (gShadowAboveWaterOrLava) { //! @bug Use of potentially undefined variable `waterLevel` + // fixed when using QOL_FIXES s->floorHeight = waterLevel; // Assume that the water is flat. diff --git a/src/game/skybox.c b/src/game/skybox.c index 09deeaf050..89ef530292 100644 --- a/src/game/skybox.c +++ b/src/game/skybox.c @@ -139,7 +139,12 @@ f32 calculate_skybox_scaled_x(s8 player, f32 fov) { f32 yaw = sSkyBoxInfo[player].yaw; //! double literals are used instead of floats + // fixed in QOL_FIXES + #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/goddard/debug_utils.c b/src/goddard/debug_utils.c index 10984bbbb2..3e67a9d4da 100644 --- a/src/goddard/debug_utils.c +++ b/src/goddard/debug_utils.c @@ -411,7 +411,11 @@ void fatal_printf(const char *fmt, ...) { gd_printf("%s", va_arg(vl, char *)); break; case 'c': + #ifndef QOL_FIXES gd_printf("%c", va_arg(vl, char)); + #else + gd_printf("%c", va_arg(vl, int)); + #endif break; case 'x': gd_printf("%x", va_arg(vl, s32)); diff --git a/src/goddard/dynlist_proc.c b/src/goddard/dynlist_proc.c index 7621f0e085..193c00cbe2 100644 --- a/src/goddard/dynlist_proc.c +++ b/src/goddard/dynlist_proc.c @@ -664,6 +664,7 @@ struct GdObj *d_makeobj(enum DObjTypes type, DynId id) { //! @bug When making a `D_LABEL`, the call to `make_label()` //! compiles incorrectly due to Goddard only declaring //! the functions, not prototyping the functions + // Fix is planned for QOL_FIXES dobj = &make_label(NULL, NULL, 8, 0, 0, 0)->header; break; case D_VIEW: @@ -1023,6 +1024,7 @@ void chk_shapegen(struct ObjShape *shape) { //! @bug Call to `make_face_with_colour()` compiles incorrectly //! due to Goddard only declaring the functions, //! not prototyping the functions + // Fix is planned for QOL_FIXES face = make_face_with_colour(1.0, 1.0, 1.0); face->mtlId = (s32) facedata->data[i][0]; add_3_vtx_to_face(face, vtxbuf[facedata->data[i][1]], vtxbuf[facedata->data[i][2]], @@ -2952,7 +2954,10 @@ 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 + // Fixed in QOL_FIXES + #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/particles.c b/src/goddard/particles.c index aa353b9b93..9a12880fcf 100644 --- a/src/goddard/particles.c +++ b/src/goddard/particles.c @@ -247,7 +247,12 @@ struct Connection *func_801825FC(struct ObjVertex *vtx1, struct ObjVertex *vtx2) sp34->unk24 = gd_vec3f_magnitude(&sp28); // Duplicate conditional. Possibly should've checked `vtx2`; // Also, this shouldn't be called with particle types... + // fixed in QOL_FIXES + #ifndef QOL_FIXES if (vtx1->header.type == OBJ_TYPE_PARTICLES && vtx1->header.type == OBJ_TYPE_PARTICLES) { + #else + if (vtx1->header.type == OBJ_TYPE_PARTICLES && vtx2->header.type == OBJ_TYPE_PARTICLES) { + #endif if ((((struct ObjParticle *) vtx1)->unk54 & 4) && (((struct ObjParticle *) vtx2)->unk54 & 4)) { sp34->unk28 |= 1; } diff --git a/src/goddard/renderer.c b/src/goddard/renderer.c index 3d2a8356d2..987c53fcec 100644 --- a/src/goddard/renderer.c +++ b/src/goddard/renderer.c @@ -492,7 +492,7 @@ 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. ALIGNED8 static u8 gd_texture_sparkle_5[] = { #include "textures/intro_raw/sparkle_5.rgba16.inc.c" }; @@ -569,7 +569,7 @@ static Gfx gd_dl_red_sparkle_4[] = { gsSPBranchList(gd_dl_sparkle), }; -#ifndef TEXTURE_FIX +#ifndef QOL_FIXES static Gfx gd_dl_red_sparkle_4_dup[] ={ gsDPPipeSync(), gsSPDisplayList(gd_dl_sparkle_red_color), @@ -621,7 +621,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 +649,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 +669,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 @@ -931,7 +931,10 @@ void gd_printf(const char *format, ...) { csr++; *csr = '\0'; break; + // two breaks here? Why? QOL_FIXES removes this one + #ifndef QOL_FIXES break; // needed to match + #endif case 'f': val.f = (f32) va_arg(args, double); csr = sprint_val_withspecifiers(csr, val, spec); @@ -941,7 +944,12 @@ void gd_printf(const char *format, ...) { break; case 'c': //! @bug formatter 'c' uses `s32` for va_arg instead of `char` + // Fixed in QOL_FIXES (`int` is actually supposed to be used instead of `char`) + #ifndef QOL_FIXES *csr = va_arg(args, s32); + #else + *csr = va_arg(args, int); + #endif csr++; *csr = '\0'; break; @@ -1323,8 +1331,11 @@ 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 + // Potential fix in QOL_FIXES + #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 +1365,11 @@ 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 + // Potential fix in QOL_FIXES + #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; @@ -2781,6 +2795,7 @@ void func_801A43DC(UNUSED struct GdObj *obj) { /* 252BC0 -> 252BE0 */ void *func_801A43F0(UNUSED const char *menufmt, ...) { //! @bug no return; function was stubbed + // Not really a bug anyway since this is a void } /* 252BE0 -> 252BF0 */ diff --git a/src/menu/level_select_menu.c b/src/menu/level_select_menu.c index b48478d3ef..7e5c3482b8 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,7 @@ int run_press_start_demo_timer(s32 timer) { timer = (s8)((struct DemoInput *) gDemo.targetAnim)->timer; gCurrSaveFileNum = 1; gCurrActNum = 1; + playMarioGreeting = 1; } } else { // activity was detected, so reset the demo countdown. gDemoCountdown = 0; @@ -69,7 +70,11 @@ int run_press_start_demo_timer(s32 timer) { return timer; } +#ifndef QOL_FIXES extern int gDemoInputListID_2; +#else +extern unsigned int gDemoInputListID_2; +#endif extern int gPressedStart; int start_demo(int timer) @@ -162,9 +167,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 +182,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 08b988e657..2094bfc80a 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -141,9 +141,12 @@ 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. + // Because of this, let that code do the work in QOL_FIXES instead + #ifndef QOL_FIXES if (sObtainedStars == 0) { sInitSelectedActNum = 1; } + #endif // Render star selector objects for (i = 0; i < sVisibleStars; i++) { diff --git a/src/pc/audio/audio_null.c b/src/pc/audio/audio_null.c index 4d0dd92347..e54e0f033e 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 73b507dcfc..a426bd5ce3 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/discord/discordrpc.c b/src/pc/discord/discordrpc.c index e2f5aa7d38..2b91c36690 100644 --- a/src/pc/discord/discordrpc.c +++ b/src/pc/discord/discordrpc.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -221,16 +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(largeImageKey), "%d", lastActNum) < 0) { + abort(); + }; + } else { smallImageKey[0] = '\0'; + } */ discordRichPresence.largeImageKey = largeImageKey; diff --git a/src/pc/gfx/gfx_opengl.c b/src/pc/gfx/gfx_opengl.c index 324f082ed9..33a5e032aa 100644 --- a/src/pc/gfx/gfx_opengl.c +++ b/src/pc/gfx/gfx_opengl.c @@ -390,11 +390,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,11 +524,11 @@ 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) { @@ -595,7 +597,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 a78f2ffdde..1e39ad82a9 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 @@ -201,15 +203,19 @@ static unsigned long get_time(void) { 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 } } @@ -619,7 +625,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 +666,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 } @@ -1130,14 +1140,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 +1159,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 +1178,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 +1212,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 +1414,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 +1494,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 +1514,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; @@ -1782,21 +1792,25 @@ 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; return; } 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/pc_main.c b/src/pc/pc_main.c index 923e7ea84f..17e748f9bd 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;*/ + #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 fba15c161c..12dbfce121 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/tools/Makefile b/tools/Makefile index d663fb0a2b..aa20022ad6 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,6 +1,6 @@ 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 @@ -25,11 +25,11 @@ 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_CFLAGS := -Iaudiofile tabledesign_LDFLAGS := -Laudiofile -laudiofile -lstdc++ -lm 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 diff --git a/tools/patch_libultra_math.c b/tools/patch_libultra_math.c index e6bdcc0cfd..e6987ba9b9 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 b97991bee6..7a32ecfb98 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 22acdd7686..dc6688e0c8 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 95d445972d..8148b89a8a 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 0fd3a11f56..899c571f20 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,19 @@ 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 + // Fixed below + 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 +202,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 +221,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 +254,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 +433,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 +454,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 +471,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/vpredictor.c b/tools/sdk-tools/adpcm/vpredictor.c index 3c35e2fcb2..5af107ebb7 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 a06d70af3e..a3f1740a95 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 da2b4e88bc..210ec12d73 100644 --- a/tools/sdk-tools/tabledesign/estimate.c +++ b/tools/sdk-tools/tabledesign/estimate.c @@ -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;