Merge branch 'switch' into splitscreen

This commit is contained in:
Isaac0-dev 2025-12-22 12:27:27 +10:00 committed by GitHub
commit 7b6f6360c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
129 changed files with 3928 additions and 767 deletions

View file

@ -3,7 +3,7 @@ name: Build coop
on:
workflow_dispatch:
push:
branches: [ dev ]
branches: [ dev, nx-support ]
jobs:
build-linux:
@ -241,3 +241,28 @@ jobs:
with:
name: sm64coopdx-macos-intel
path: ./build/us_pc/sm64coopdx_macOS_Intel.zip
build-switch:
if: ${{ contains(github.event.head_commit.message, '[build]') || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
container: devkitpro/devkita64:latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y build-essential bsdmainutils git python3
- name: Build the game
run: |
export DEVKITA64=${DEVKITPRO}/devkitA64
export PATH=${DEVKITPRO}/tools/bin:${DEVKITA64}/bin:$PATH
make TARGET_NX=1 BUILD_NRO=1 CONTROLLER_API=SWITCH -j$(nproc)
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: sm64coopdx-switch
path: ./build/us_nx/sm64coopdx.nro

273
Makefile
View file

@ -31,6 +31,9 @@ TARGET_RPI ?= 0
# Build and optimize for RK3588 processor
TARGET_RK3588 ?= 0
# Build and optimize for the Nintendo Switch
TARGET_NX ?= 0
# Makeflag to enable OSX fixes
OSX_BUILD ?= 0
@ -71,7 +74,7 @@ else
MIN_MACOS_VERSION ?= 10.15
endif
# Make some small adjustments for handheld devices
HANDHELD ?= 0
HANDHELD ?= $(TARGET_NX)
# Various workarounds for weird toolchains
NO_BZERO_BCOPY ?= 0
@ -85,7 +88,7 @@ RENDER_API ?= GL
WINDOW_API ?= SDL2
# Audio backends: SDL1, SDL2, DUMMY
AUDIO_API ?= SDL2
# Controller backends (can have multiple, space separated): SDL2, SDL1
# Controller backends (can have multiple, space separated): SDL2, SDL1, SWITCH
CONTROLLER_API ?= SDL2
# Automatic settings for PC port(s)
@ -94,6 +97,11 @@ WINDOWS_BUILD ?= 0
WINDOWS_AUTO_BUILDER ?= 0
# Switch Only Settings
ifeq ($(TARGET_NX), 1)
BUILD_NRO ?= 0
endif
# Setup extra cflags
EXTRA_CFLAGS ?=
EXTRA_CPP_FLAGS ?=
@ -119,7 +127,9 @@ else
endif
ifeq ($(HOST_OS),Windows)
WINDOWS_BUILD := 1
ifneq ($(TARGET_NX),1)
WINDOWS_BUILD := 1
endif
endif
ifeq ($(HOST_OS),Darwin)
@ -208,6 +218,7 @@ $(eval $(call validate-option,VERSION,us))
# Graphics microcode used
GRUCODE ?= f3dex2e
ifeq ($(VERSION),jp)
DEFINES += VERSION_JP=1
#GRUCODE ?= f3d_old
@ -286,8 +297,8 @@ else
endif
ifeq ($(TARGET_RPI),1)
$(info Compiling for Raspberry Pi)
DISCORD_SDK := 0
$(info Compiling for Raspberry Pi)
DISCORD_SDK := 0
# Raspberry Pi B+, Zero, etc
ifneq (,$(findstring armv6l,$(machine)))
@ -296,7 +307,7 @@ ifeq ($(TARGET_RPI),1)
# Raspberry Pi 2 and 3 in ARM 32bit mode
ifneq (,$(findstring armv7l,$(machine)))
$(info ARM 32bit mode)
$(info ARM 32bit mode)
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
@ -308,7 +319,7 @@ ifeq ($(TARGET_RPI),1)
# 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)))
$(info ARM64 mode)
$(info ARM64 mode)
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
@ -316,9 +327,43 @@ ifeq ($(TARGET_RPI),1)
OPT_FLAGS := -march=armv8-a+crc+simd -mtune=cortex-a72 -O3
endif
endif
endif
else ifeq ($(TARGET_NX),1) # Nintendo Switch
$(info Compiling for Nintendo Switch)
RENDER_API := GL
WINDOW_API := SDL2
AUDIO_API := SDL2
DISCORD_SDK := 0
ifeq ($(TARGET_RK3588),1)
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
export PATH := $(DEVKITPRO)/tools/bin:$(DEVKITPRO)/devkitA64/bin:$(PATH)
include $(DEVKITPRO)/devkitA64/base_tools
NXPATH := $(DEVKITPRO)/portlibs/switch/bin
PORTLIBS := $(DEVKITPRO)/portlibs/switch
LIBNX ?= $(DEVKITPRO)/libnx
CROSS ?= aarch64-none-elf-
SDLCROSS := $(NXPATH)/
CC := $(CROSS)gcc
CXX := $(CROSS)g++
STRIP := $(CROSS)strip
OPT_FLAGS := -ffunction-sections -fdata-sections -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -ftls-model=local-exec -fwrapv -fPIC
DEFINES += __SWITCH__=1 __CONSOLE__=1 USE_GLES=1
ifeq ($(BUILD_NRO),1)
DEFINES += BUILD_NRO=1
endif
APP_TITLE := SM64 Coop DX
APP_AUTHOR := The Coop DX Team
APP_VERSION := 1.0.0
APP_ICON := res/icon_AmericanEnglish.jpg
APP_TITLEID := 0100534d36344350
APP_JSON := res/npdm.json
ICON := res/icon_AmericanEnglish.dat
else ifeq ($(TARGET_RK3588),1)
$(info Compiling for RK3588)
DISCORD_SDK := 0
COOPNET := 0
@ -330,7 +375,9 @@ ifeq ($(TARGET_RK3588),1)
endif
# Set BITS (32/64) to compile for
OPT_FLAGS += $(BITS)
ifeq ($(TARGET_NX),0)
OPT_FLAGS += $(BITS)
endif
TARGET := sm64.$(VERSION)
@ -486,23 +533,35 @@ _ := $(shell $(PYTHON) $(TOOLS_DIR)/copy_extended_sounds.py)
BUILD_DIR_BASE := build
# BUILD_DIR is the location where all build artifacts are placed
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
ifeq ($(WINDOWS_BUILD),1)
EXE := $(BUILD_DIR)/sm64coopdx.exe
else # Linux builds/binary namer
ifeq ($(TARGET_RPI),1)
EXE := $(BUILD_DIR)/sm64coopdx.arm
else
EXE := $(BUILD_DIR)/sm64coopdx
endif
ifeq ($(TARGET_RPI),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_rpi
EXE := $(BUILD_DIR)/sm64coopdx.arm
else ifeq ($(TARGET_NX),1) # Nintendo Switch
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_nx
ELF := $(BUILD_DIR)/sm64coopdx.elf
ifeq ($(BUILD_NRO),1)
EXE := $(BUILD_DIR)/sm64coopdx.nro
else
EXE := $(BUILD_DIR)/sm64coopdx.nsp
endif
else ifeq ($(TARGET_RK3588),1)
EXE := $(BUILD_DIR)/sm64coopdx.arm
else ifeq ($(TARGET_N64),1) # Nintendo 64 (Unused)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)
ELF := $(BUILD_DIR)/sm64coopdx.elf
EXE := $(BUILD_DIR)/sm64coopdx.n64
else ifeq ($(WINDOWS_BUILD),1)
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
EXE := $(BUILD_DIR)/sm64coopdx.exe
else
BUILD_DIR := $(BUILD_DIR_BASE)/$(VERSION)_pc
EXE := $(BUILD_DIR)/sm64coopdx
endif
ifeq ($(TARGET_RK3588),1)
EXE := $(BUILD_DIR)/sm64coopdx.arm
endif
MAP := $(BUILD_DIR)/sm64coopdx.map
ELF := $(BUILD_DIR)/$(TARGET).elf
LIBULTRA := $(BUILD_DIR)/libultra.a
LD_SCRIPT := sm64.ld
MIO0_DIR := $(BUILD_DIR)/bin
@ -617,6 +676,16 @@ ifeq ($(DISCORD_SDK), 1)
endif
endif
ifeq ($(TARGET_NX),1)
ROMFS_DIR := romfs
# Remove old romfs dir
_ := $(shell rm -rf ./$(BUILD_DIR)/$(ROMFS_DIR))
endif
LANG_DIR := lang
# Remove old lang dir
@ -654,10 +723,14 @@ endif
# Compiler Options #
#==============================================================================#
AS := $(CROSS)as
SDLCROSS ?= $(CROSS)
ifeq ($(OSX_BUILD),1)
AS := i686-w64-mingw32-as
else ifeq ($(TARGET_NX),1) # Nintendo Switch
AS := aarch64-none-elf-as
else
AS := $(CROSS)as
endif
ifeq ($(WINDOWS_AUTO_BUILDER),1)
@ -690,11 +763,7 @@ else
endif
endif
ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL
CPP := cpp -P
OBJCOPY := objcopy
OBJDUMP := $(CROSS)objdump
else ifeq ($(OSX_BUILD),1)
ifeq ($(OSX_BUILD),1)
OSX_GCC_VER = $(shell find $(BREW_PREFIX)/bin/gcc* | grep -oE '[[:digit:]]+' | sort -n | uniq | tail -1)
# if we couldn't find a gcc ver, default to 9
ifeq ($(OSX_GCC_VER),)
@ -707,6 +776,10 @@ else ifeq ($(TARGET_N64),0) # Linux & other builds
CPP := $(CROSS)cpp -P
OBJCOPY := $(CROSS)objcopy
OBJDUMP := $(CROSS)objdump
else ifeq ($(WINDOWS_BUILD),1) # fixes compilation in MXE on Linux and WSL
CPP := cpp -P
OBJCOPY := objcopy
OBJDUMP := $(CROSS)objdump
else
# Prefer gcc's cpp if installed on the system
ifneq (,$(call find-command,cpp-10))
@ -755,11 +828,14 @@ ifeq ($(TARGET_N64),1)
INCLUDE_DIRS += include/libc
else
INCLUDE_DIRS += sound lib/lua/include lib/coopnet/include $(EXTRA_INCLUDES)
ifeq ($(TARGET_NX),1)
INCLUDE_DIRS += ${PORTLIBS}/include system ${DEVKITPRO}/libnx/include
endif
endif
# Connfigure backend flags
SDLCONFIG := $(CROSS)sdl2-config
SDLCONFIG := $(SDLCROSS)sdl2-config
BACKEND_CFLAGS := -DRAPI_$(RENDER_API)=1 -DWAPI_$(WINDOW_API)=1 -DAAPI_$(AUDIO_API)=1
# can have multiple controller APIs
@ -781,12 +857,15 @@ else ifeq ($(findstring SDL,$(WINDOW_API)),SDL)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(TARGET_RK3588),1)
BACKEND_LDFLAGS += -lGLESv2
else ifeq ($(TARGET_NX),1) # Nintendo Switch
BACKEND_LDFLAGS += -lGLESv2
EXTRA_CPP_FLAGS += -std=gnu++17 -fsanitize=builtin -fstack-protector
else ifeq ($(OSX_BUILD),1)
BACKEND_LDFLAGS += -framework OpenGL `pkg-config --libs glew` -mmacosx-version-min=$(MIN_MACOS_VERSION)
EXTRA_CPP_FLAGS += -stdlib=libc++ -std=c++17 -mmacosx-version-min=$(MIN_MACOS_VERSION)
else
BACKEND_LDFLAGS += -lGL
endif
endif
endif
ifeq ($(WINDOW_API),DUMMY)
@ -810,10 +889,10 @@ endif
# SDL can be used by different systems, so we consolidate all of that shit into this
ifeq ($(SDL2_USED),1)
SDLCONFIG := $(CROSS)sdl2-config
SDLCONFIG := $(SDLCROSS)sdl2-config
BACKEND_CFLAGS += -DHAVE_SDL2=1
else ifeq ($(SDL1_USED),1)
SDLCONFIG := $(CROSS)sdl-config
SDLCONFIG := $(SDLCROSS)sdl-config
BACKEND_CFLAGS += -DHAVE_SDL1=1
endif
@ -826,7 +905,9 @@ ifneq ($(SDL1_USED)$(SDL2_USED),00)
BACKEND_CFLAGS += `$(SDLCONFIG) --cflags`
endif
ifeq ($(WINDOWS_BUILD),1)
ifeq ($(TARGET_NX),1) # Nintendo Switch
BACKEND_LDFLAGS += `$(SDLCONFIG) --libs`
else ifeq ($(WINDOWS_BUILD),1)
BACKEND_LDFLAGS += `$(SDLCONFIG) --static-libs` -lsetupapi -luser32 -limm32 -lole32 -loleaut32 -lshell32 -lshlwapi -lwinmm -lversion
else
BACKEND_LDFLAGS += `$(SDLCONFIG) --libs`
@ -839,17 +920,7 @@ DEF_INC_CFLAGS := $(foreach i,$(INCLUDE_DIRS),-I$(i)) $(C_DEFINES)
# Check code syntax with host compiler
CC_CHECK := $(CC)
ifeq ($(WINDOWS_BUILD),1)
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -Wall -Wextra $(TARGET_CFLAGS) -DWINSOCK
CFLAGS := $(OPT_FLAGS) $(DEF_INC_CFLAGS) $(BACKEND_CFLAGS) $(TARGET_CFLAGS) -fno-strict-aliasing -fwrapv -DWINSOCK
ifeq ($(TARGET_BITS), 32)
BACKEND_LDFLAGS += -ldbghelp
endif
else ifeq ($(TARGET_N64),0) # Linux / Other builds below
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -Wall -Wextra $(TARGET_CFLAGS)
CFLAGS := $(OPT_FLAGS) $(DEF_INC_CFLAGS) $(BACKEND_CFLAGS) $(TARGET_CFLAGS) -fno-strict-aliasing -fwrapv
else # C compiler options for N64
ifeq ($(TARGET_N64),1) # C compiler options for N64
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(CC_CFLAGS) $(TARGET_CFLAGS) -std=gnu90 -Wall -Wextra -Wno-main -DNON_MATCHING -DAVOID_UB $(DEF_INC_CFLAGS)
CFLAGS = -G 0 $(OPT_FLAGS) $(TARGET_CFLAGS) $(MIPSISET) $(DEF_INC_CFLAGS)
ifeq ($(COMPILER),gcc)
@ -857,6 +928,19 @@ else # C compiler options for N64
else
CFLAGS += -non_shared -Wab,-r4300_mul -Xcpluscomm -Xfullwarn -signed -32
endif
else ifeq ($(TARGET_NX),1) # Nintendo Switch
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -Wall -Wextra $(TARGET_CFLAGS)
CFLAGS := $(OPT_FLAGS) $(DEF_INC_CFLAGS) $(BACKEND_CFLAGS) $(TARGET_CFLAGS) -fno-strict-aliasing -fwrapv -std=gnu17
else ifeq ($(WINDOWS_BUILD),1)
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -Wall -Wextra $(TARGET_CFLAGS) -DWINSOCK
CFLAGS := $(OPT_FLAGS) $(DEF_INC_CFLAGS) $(BACKEND_CFLAGS) $(TARGET_CFLAGS) -fno-strict-aliasing -fwrapv -DWINSOCK
ifeq ($(TARGET_BITS), 32)
BACKEND_LDFLAGS += -ldbghelp
endif
else # Linux / Other builds below
CC_CHECK_CFLAGS := -fsyntax-only -fsigned-char $(BACKEND_CFLAGS) $(DEF_INC_CFLAGS) -Wall -Wextra $(TARGET_CFLAGS)
CFLAGS := $(OPT_FLAGS) $(DEF_INC_CFLAGS) $(BACKEND_CFLAGS) $(TARGET_CFLAGS) -fno-strict-aliasing -fwrapv
endif
ifeq ($(TARGET_N64),1)
@ -887,9 +971,11 @@ ifeq ($(WINDOWS_BUILD),1)
endif
LDFLAGS += -T windows.ld
else ifeq ($(TARGET_RPI),1)
LDFLAGS := $(OPT_FLAGS) -lm $(BACKEND_LDFLAGS) -no-pie
LDFLAGS := $(OPT_FLAGS) $(BACKEND_LDFLAGS) -no-pie
else ifeq ($(TARGET_RK3588),1)
LDFLAGS := $(OPT_FLAGS) -lm $(BACKEND_LDFLAGS) -no-pie
else ifeq ($(TARGET_NX),1) # Nintendo Switch
LDFLAGS := -specs=$(LIBNX)/switch.specs $(OPT_FLAGS) -L$(LIBNX)/lib -L$(PORTLIBS)/lib $(BACKEND_LDFLAGS)
else ifeq ($(OSX_BUILD),1)
LDFLAGS := -lm $(BACKEND_LDFLAGS) -lpthread
else
@ -898,7 +984,11 @@ endif
# used by crash handler and loading screen on linux
ifeq ($(WINDOWS_BUILD),0)
LDFLAGS += -rdynamic -ldl -pthread
ifeq ($(TARGET_NX),1)
LDFLAGS += -pthread
else
LDFLAGS += -rdynamic -ldl -pthread
endif
endif
# icon
@ -954,13 +1044,15 @@ else ifeq ($(OSX_BUILD),1)
LDFLAGS += -L./lib/lua/mac_intel/ -l lua53
endif
else ifeq ($(TARGET_RPI),1)
ifneq (,$(findstring aarch64,$(machine)))
ifneq (,$(findstring aarch64,$(machine)))
LDFLAGS += -Llib/lua/linux -l:liblua53-arm64.a
else
LDFLAGS += -Llib/lua/linux -l:liblua53-arm.a
endif
else ifeq ($(TARGET_RK3588),1)
LDFLAGS += -Llib/lua/linux -l:liblua53-arm64.a
else ifeq ($(TARGET_NX),1)
LDFLAGS += -Llib/lua/nx -l:liblua53.a
else
LDFLAGS += -Llib/lua/linux -l:liblua53.a -ldl
endif
@ -992,6 +1084,8 @@ ifeq ($(COOPNET),1)
endif
else ifeq ($(TARGET_RK3588),1)
LDFLAGS += -Llib/coopnet/linux -l:libcoopnet-arm64.a -l:libjuice.a
else ifeq ($(TARGET_NX),1)
LDFLAGS += -Llib/coopnet/nx -l:libcoopnet.a -l:libjuice.a
else
LDFLAGS += -Llib/coopnet/linux -l:libcoopnet.a -l:libjuice.a
endif
@ -1026,11 +1120,18 @@ endif
# Enable ASLR
CFLAGS += -fPIE
# Generate a map file
ifeq ($(OSX_BUILD),0)
LDFLAGS += -Wl,-Map $(MAP)
endif
# Prevent a crash with -sopt
export LANG := C
ifeq ($(OSX_BUILD),0)
LDFLAGS += -latomic
ifeq ($(TARGET_NX),0)
ifeq ($(OSX_BUILD),0)
LDFLAGS += -latomic
endif
endif
#==============================================================================#
@ -1217,14 +1318,25 @@ $(BUILD_DIR)/$(DISCORD_SDK_LIBS):
$(BUILD_DIR)/$(COOPNET_LIBS):
@$(CP) -f $(COOPNET_LIBS) $(BUILD_DIR)
ifeq ($(TARGET_NX),1)
$(BUILD_DIR)/$(ROMFS_DIR):
@mkdir -p $(BUILD_DIR)/$(ROMFS_DIR)
$(BUILD_DIR)/$(LANG_DIR): $(BUILD_DIR)/$(ROMFS_DIR)
@$(CP) -f -r $(LANG_DIR) $(BUILD_DIR)/$(ROMFS_DIR)/$(LANG_DIR)/
$(BUILD_DIR)/$(PALETTES_DIR): $(BUILD_DIR)/$(ROMFS_DIR)
@$(CP) -f -r $(PALETTES_DIR) $(BUILD_DIR)/$(ROMFS_DIR)/$(PALETTES_DIR)/
else
$(BUILD_DIR)/$(LANG_DIR):
@$(CP) -f -r $(LANG_DIR) $(BUILD_DIR)
$(BUILD_DIR)/$(MOD_DIR):
$(CP) -f -r $(MOD_DIR) $(BUILD_DIR)
$(BUILD_DIR)/$(PALETTES_DIR):
@$(CP) -f -r $(PALETTES_DIR) $(BUILD_DIR)
endif
$(BUILD_DIR)/$(MOD_DIR):
$(CP) -f -r $(MOD_DIR) $(BUILD_DIR)
# Extra object file dependencies
@ -1342,6 +1454,57 @@ $(BUILD_DIR)/%.mio0.o: $(BUILD_DIR)/%.mio0
endif
#==============================================================================#
# Nintendo Switch App Generation #
#==============================================================================#
ifeq ($(TARGET_NX),1)
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(APP_ICON),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(BUILD_DIR)/$(ROMFS_DIR)
endif
define make_pfs0
$(V)mkdir -p $(BUILD_DIR)/exefs
$(V)[ $(BUILD_EXEFS_SRC) ] && [ -d $(BUILD_EXEFS_SRC) ] && cp -R $(BUILD_EXEFS_SRC)/* $(BUILD_DIR)/exefs || echo > /dev/null
$(V)cp $*.nso $(BUILD_DIR)/exefs/main
$(V)[ $(APP_JSON) ] && cp $*.npdm $(BUILD_DIR)/exefs/main.npdm || echo > /dev/null
$(V)build_pfs0 $(BUILD_DIR)/exefs $@
endef
%.nacp: $(MAKEFILE_LIST)
$(V)nacptool --create "$(APP_TITLE)" "$(APP_AUTHOR)" "$(APP_VERSION)" $@ $(NACPFLAGS)
@$(PRINT) "$(GREEN)Built NACP: $(BLUE)$(notdir $@) $(NO_COL)\n"
%.nro: %.elf %.nacp
$(V)elf2nro $< $@ --nacp=$(BUILD_DIR)/sm64coopdx.nacp $(NROFLAGS)
@$(PRINT) "$(GREEN)Built NRO: $(BLUE)$(notdir $@) $(NO_COL)\n"
%.nso: %.elf
$(V)elf2nso $< $@
@$(PRINT) "$(GREEN)Built NSO: $(BLUE)$(notdir $@) $(NO_COL)\n"
%.npdm: $(APP_JSON)
$(V)npdmtool $< $@
@$(PRINT) "$(GREEN)Built NPDM: $(BLUE)$(notdir $@) $(NO_COL)\n"
%.pfs0: %.nso %.npdm
$(make_pfs0)
@$(PRINT) "$(GREEN)Built PFS0: $(BLUE)$(notdir $@) $(NO_COL)\n"
%.nsp: %.nso %.npdm %.nacp
$(make_pfs0)
@$(PRINT) "$(GREEN)Built NSP: $(BLUE)$(notdir $@) $(NO_COL)\n"
endif
#==============================================================================#
# Sound File Generation #
@ -1564,6 +1727,10 @@ ifeq ($(TARGET_N64),1)
$(BUILD_DIR)/$(TARGET).objdump: $(ELF)
$(OBJDUMP) -D $< > $@
else ifeq ($(TARGET_NX),1) # Nintendo Switch
$(ELF): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS) $(BUILD_DIR)/$(DISCORD_SDK_LIBS) $(BUILD_DIR)/$(COOPNET_LIBS) $(BUILD_DIR)/$(LANG_DIR) $(BUILD_DIR)/$(MOD_DIR) $(BUILD_DIR)/$(PALETTES_DIR)
@$(PRINT) "$(GREEN)Linking executable: $(BLUE)$@ $(NO_COL)\n"
$(V)$(LD) $(PROF_FLAGS) -L $(BUILD_DIR) -o $@ $(O_FILES) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(LDFLAGS) -lnx -lm
else
$(EXE): $(O_FILES) $(MIO0_FILES:.mio0=.o) $(ULTRA_O_FILES) $(GODDARD_O_FILES) $(BUILD_DIR)/$(RPC_LIBS) $(BUILD_DIR)/$(DISCORD_SDK_LIBS) $(BUILD_DIR)/$(COOPNET_LIBS) $(BUILD_DIR)/$(LANG_DIR) $(BUILD_DIR)/$(MOD_DIR) $(BUILD_DIR)/$(PALETTES_DIR)
@$(PRINT) "$(GREEN)Linking executable: $(BLUE)$@ $(NO_COL)\n"

View file

@ -735,23 +735,23 @@ void Print(const char *aFmt, Args... aArgs) {
}
template <typename... Args>
void PrintConsole(enum ConsoleMessageLevel level, const char *aFmt, Args... aArgs) {
void DynOS_PrintConsole(enum ConsoleMessageLevel level, const char *aFmt, Args... aArgs) {
snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, aFmt, aArgs...);
sys_swap_backslashes(gDjuiConsoleTmpBuffer);
djui_console_message_create(gDjuiConsoleTmpBuffer, level);
}
template <typename... Args>
void PrintError(const char *aFmt, Args... aArgs) {
void DynOS_PrintError(const char *aFmt, Args... aArgs) {
printf(aFmt, aArgs...);
printf("\r\n");
fflush(stdout);
PrintConsole(CONSOLE_MESSAGE_ERROR, aFmt, aArgs...);
DynOS_PrintConsole(CONSOLE_MESSAGE_ERROR, aFmt, aArgs...);
}
#define PrintDataError(...) { \
#define DynOS_PrintDataError(...) { \
if (aGfxData->mErrorCount == 0) Print(" ERROR!"); \
Print(__VA_ARGS__); \
PrintConsole(CONSOLE_MESSAGE_ERROR, __VA_ARGS__); \
DynOS_PrintConsole(CONSOLE_MESSAGE_ERROR, __VA_ARGS__); \
aGfxData->mErrorCount++; \
}

View file

@ -16,7 +16,7 @@ void ClearGfxDataNodes(DataNodes<T> &aDataNodes) {
static bool DynOS_Actor_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
BinFile *_File = BinFile::OpenW(aOutputFilename.c_str());
if (!_File) {
PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
@ -188,7 +188,7 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array<Pair<u64, Str
// Parse data
PrintNoNewLine("%s.bin: Model identifier: %X - Processing... ", _GeoRootName.begin(), _GfxData->mModelIdentifier);
PrintConsole(CONSOLE_MESSAGE_INFO, "%s.bin: Model identifier: %X - Processing... ", _GeoRootName.begin(), _GfxData->mModelIdentifier);
DynOS_PrintConsole(CONSOLE_MESSAGE_INFO, "%s.bin: Model identifier: %X - Processing... ", _GeoRootName.begin(), _GfxData->mModelIdentifier);
DynOS_Geo_Parse(_GfxData, _GeoNode, true);
// Init animation data
@ -222,7 +222,7 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, Array<Pair<u64, Str
if (_GfxData->mErrorCount == 0) {
DynOS_Actor_WriteBinary(_BinFilename, _GfxData);
} else {
PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
DynOS_PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
}
// Clear data pointers
ClearGfxDataNodes(_GfxData->mLights);

View file

@ -9,7 +9,7 @@ DataNode<Ambient_t>* DynOS_AmbientT_Parse(GfxData* aGfxData, DataNode<Ambient_t>
// Check tokens count
if (aNode->mTokens.Count() < 8) {
PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
DynOS_PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}

View file

@ -7,7 +7,7 @@
static void ScanAnimationDataFile(GfxData *aGfxData, const SysPath &aFilename) {
FILE *_File = fopen(aFilename.c_str(), "rb");
if (!_File) {
PrintDataError(" ERROR: Unable to open file \"%s\"", aFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to open file \"%s\"", aFilename.c_str());
}
// Load file into a buffer while removing all comments
@ -70,7 +70,7 @@ static void ScanAnimationDataFile(GfxData *aGfxData, const SysPath &aFilename) {
case DATA_TYPE_ANIMATION: {
if (_Data.Count() < 10) {
PrintDataError(" ERROR: %s: Not enough data", _DataName.begin());
DynOS_PrintDataError(" ERROR: %s: Not enough data", _DataName.begin());
break;
}
@ -104,7 +104,7 @@ static void ScanAnimationDataFile(GfxData *aGfxData, const SysPath &aFilename) {
static void ScanAnimationTableFile(GfxData *aGfxData, const SysPath &aFilename) {
FILE *_File = fopen(aFilename.c_str(), "rb");
if (!_File) {
PrintDataError(" ERROR: Unable to open file \"%s\"", aFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to open file \"%s\"", aFilename.c_str());
}
// Load file into a buffer while removing all comments

View file

@ -1985,7 +1985,7 @@ static BehaviorScript ParseBehaviorScriptSymbolArg(GfxData *aGfxData, DataNode<B
BehaviorScript value = ParseBehaviorScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &found);
if (!found) {
const String &_Arg = aNode->mTokens[aTokenIndex - 1];
PrintDataError(" ERROR: Unknown bhv arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown bhv arg: %s", _Arg.begin());
}
return value;
}
@ -2274,7 +2274,7 @@ static void ParseBehaviorScriptSymbol(GfxData *aGfxData, DataNode<BehaviorScript
//BehaviorScript _Bs[] = { LOAD_ANIMATIONS_EXT(field, animIndex) };
//memcpy(aHead, _Bs, sizeof(_Bs));
//aHead += (sizeof(_Bs) / sizeof(_Bs[0]));
PrintDataError(" ERROR: : Custom external animations are currently not supported. Skipping LOAD_ANIMATIONS_EXT.");
DynOS_PrintDataError(" ERROR: : Custom external animations are currently not supported. Skipping LOAD_ANIMATIONS_EXT.");
}
return;
}
@ -2415,7 +2415,7 @@ static void ParseBehaviorScriptSymbol(GfxData *aGfxData, DataNode<BehaviorScript
}
// Unknown
PrintDataError(" ERROR: Unknown behavior symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown behavior symbol: %s", _Symbol.begin());
}
DataNode<BehaviorScript> *DynOS_Bhv_Parse(GfxData *aGfxData, DataNode<BehaviorScript> *aNode, bool aDisplayPercent) {
@ -2478,7 +2478,7 @@ static void DynOS_Bhv_Write(BinFile* aFile, GfxData* aGfxData, DataNode<Behavior
static bool DynOS_Bhv_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
BinFile *_File = BinFile::OpenW(aOutputFilename.c_str());
if (!_File) {
PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
@ -2502,7 +2502,7 @@ static DataNode<BehaviorScript> *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat
// Sanity check the files size. The minimum valid size is 9 bytes.
// 1 byte for the type, 1 bytes for the name length, 3 bytes for the version, And 4 bytes for the behaviors size.
if (aFile->Size() < 9) {
PrintDataError(" ERROR: Behavior file is smaller then it should be, Rejecting '%s'.", aFile->GetFilename());
DynOS_PrintDataError(" ERROR: Behavior file is smaller then it should be, Rejecting '%s'.", aFile->GetFilename());
// We have nothing to return, So return NULL.
return NULL;
}
@ -2524,7 +2524,7 @@ static DataNode<BehaviorScript> *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat
// we can't read it no matter what. If it's just minor or patch. We might have
// code to support it.
if (majorVersion != BEHAVIOR_MIN_MAJOR_VER || (minorVersion < BEHAVIOR_MIN_MINOR_VER || patchVersion < BEHAVIOR_MIN_PATCH_VER)) {
PrintDataError(" ERROR: Behavior file is version %u.%u.%u, which is not supported! Rejecting '%s'.", majorVersion, minorVersion, patchVersion, aFile->GetFilename());
DynOS_PrintDataError(" ERROR: Behavior file is version %u.%u.%u, which is not supported! Rejecting '%s'.", majorVersion, minorVersion, patchVersion, aFile->GetFilename());
// We don't return this since we failed to read the behavior.
Delete(_Node);
// We have nothing to return, So return NULL.
@ -2535,7 +2535,7 @@ static DataNode<BehaviorScript> *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat
// We also check if the specified behavior size is valid for the file.
u32 dataSize = aFile->Read<u32>();
if (dataSize == 0 || (dataSize > (aFile->Size() - aFile->Offset()))) {
PrintDataError(" ERROR: Behavior file has a invalid behavior in it! Rejecting '%s'.", aFile->GetFilename());
DynOS_PrintDataError(" ERROR: Behavior file has a invalid behavior in it! Rejecting '%s'.", aFile->GetFilename());
// We don't return this since we failed to read the behavior.
Delete(_Node);
// We have nothing to return, So return NULL.
@ -2549,7 +2549,7 @@ static DataNode<BehaviorScript> *DynOS_Bhv_Load(BinFile *aFile, GfxData *aGfxDat
// Read it
for (u32 i = 0; i != _Node->mSize; ++i) {
if (aFile->EoF()) {
PrintDataError(" ERROR: Reached EOF when reading file! Expected %llx bytes!", _Node->mSize * sizeof(u32));
DynOS_PrintDataError(" ERROR: Reached EOF when reading file! Expected %llx bytes!", _Node->mSize * sizeof(u32));
break;
}
u32 _Value = aFile->Read<u32>();
@ -2638,14 +2638,14 @@ static void DynOS_Bhv_Generate(const SysPath &aPackFolder, Array<Pair<u64, Strin
// Parse data
PrintNoNewLine("%s.bhv: Behavior identifier: %X - Processing... ", _BhvRootName.begin(), _GfxData->mModelIdentifier);
PrintConsole(CONSOLE_MESSAGE_INFO, "%s.bhv: Behavior identifier: %X - Processing... ", _BhvRootName.begin(), _GfxData->mModelIdentifier);
DynOS_PrintConsole(CONSOLE_MESSAGE_INFO, "%s.bhv: Behavior identifier: %X - Processing... ", _BhvRootName.begin(), _GfxData->mModelIdentifier);
DynOS_Bhv_Parse(_GfxData, _BhvNode, true);
// Write if no error
if (_GfxData->mErrorCount == 0) {
DynOS_Bhv_WriteBinary(_BinFilename, _GfxData);
} else {
PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
DynOS_PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
}
// Clear data pointers

View file

@ -42,21 +42,21 @@ struct CollisionValidationData {
static void ValidateColSectionChange(GfxData* aGfxData, struct CollisionValidationData& aColValData, u8 section) {
if (aColValData.section == COL_SECTION_END) {
PrintDataError("Found new col section after COL_END");
DynOS_PrintDataError("Found new col section after COL_END");
}
if (aColValData.section != section) {
if (aColValData.vtxAlloc != aColValData.vtxCount) {
PrintDataError("Improper vtx count found in section. Allocated: %u, Defined: %u", aColValData.vtxAlloc, aColValData.vtxCount);
DynOS_PrintDataError("Improper vtx count found in section. Allocated: %u, Defined: %u", aColValData.vtxAlloc, aColValData.vtxCount);
}
if (aColValData.triAlloc != aColValData.triCount) {
PrintDataError("Improper triangle count found in section. Allocated: %u, Defined: %u", aColValData.triAlloc, aColValData.triCount);
DynOS_PrintDataError("Improper triangle count found in section. Allocated: %u, Defined: %u", aColValData.triAlloc, aColValData.triCount);
}
if (aColValData.specialAlloc != aColValData.specialCount) {
PrintDataError("Improper special count found in section. Allocated: %u, Defined: %u", aColValData.triAlloc, aColValData.triCount);
DynOS_PrintDataError("Improper special count found in section. Allocated: %u, Defined: %u", aColValData.triAlloc, aColValData.triCount);
}
if (aColValData.waterBoxAlloc != aColValData.waterBoxCount) {
PrintDataError("Improper water box count found in section. Allocated: %u, Defined: %u", aColValData.waterBoxAlloc, aColValData.waterBoxCount);
DynOS_PrintDataError("Improper water box count found in section. Allocated: %u, Defined: %u", aColValData.waterBoxAlloc, aColValData.waterBoxCount);
}
}
@ -65,17 +65,17 @@ static void ValidateColSectionChange(GfxData* aGfxData, struct CollisionValidati
static void ValidateColInit(GfxData* aGfxData, struct CollisionValidationData& aColValData) {
if (aColValData.tokenIndex != 0) {
PrintDataError("COL_INIT found after the first token");
DynOS_PrintDataError("COL_INIT found after the first token");
}
ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_VTX);
}
static void ValidateColVertexInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) {
if (strcmp(aColValData.lastSymbol, "COL_INIT") != 0) {
PrintDataError("COL_VERTEX_INIT found outside of vertex section");
DynOS_PrintDataError("COL_VERTEX_INIT found outside of vertex section");
}
if (arg0 < 0) {
PrintDataError("COL_VERTEX_INIT with a negative count: %d", arg0);
DynOS_PrintDataError("COL_VERTEX_INIT with a negative count: %d", arg0);
}
aColValData.vtxAlloc = arg0;
aColValData.vtxCount = 0;
@ -83,14 +83,14 @@ static void ValidateColVertexInit(GfxData* aGfxData, struct CollisionValidationD
static void ValidateColVertex(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2) {
if (aColValData.section != COL_SECTION_VTX) {
PrintDataError("COL_VERTEX found outside of vertex section");
DynOS_PrintDataError("COL_VERTEX found outside of vertex section");
}
aColValData.vtxCount++;
}
static void ValidateColTriInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1) {
if (arg1 < 0) {
PrintDataError("COL_TRI_INIT with a negative count: %d", arg1);
DynOS_PrintDataError("COL_TRI_INIT with a negative count: %d", arg1);
}
ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_TRI);
aColValData.triAlloc = arg1;
@ -99,16 +99,16 @@ static void ValidateColTriInit(GfxData* aGfxData, struct CollisionValidationData
static void ValidateColTri(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2) {
if (aColValData.section != COL_SECTION_TRI) {
PrintDataError("COL_TRI found outside of triangle section");
DynOS_PrintDataError("COL_TRI found outside of triangle section");
}
if (arg0 < 0 || arg0 > aColValData.vtxCount) {
PrintDataError("COL_TRI used vertex outside of known range for first param: %d", arg0);
DynOS_PrintDataError("COL_TRI used vertex outside of known range for first param: %d", arg0);
}
if (arg1 < 0 || arg1 > aColValData.vtxCount) {
PrintDataError("COL_TRI used vertex outside of known range for second param: %d", arg1);
DynOS_PrintDataError("COL_TRI used vertex outside of known range for second param: %d", arg1);
}
if (arg2 < 0 || arg2 > aColValData.vtxCount) {
PrintDataError("COL_TRI used vertex outside of known range for third param: %d", arg2);
DynOS_PrintDataError("COL_TRI used vertex outside of known range for third param: %d", arg2);
}
aColValData.triCount++;
}
@ -127,7 +127,7 @@ static void ValidateColEnd(GfxData* aGfxData, struct CollisionValidationData& aC
static void ValidateColSpecialInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) {
if (arg0 < 0) {
PrintDataError("COL_SPECIAL_INIT with a negative count: %d", arg0);
DynOS_PrintDataError("COL_SPECIAL_INIT with a negative count: %d", arg0);
}
ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_SPECIAL);
aColValData.specialAlloc = arg0;
@ -136,7 +136,7 @@ static void ValidateColSpecialInit(GfxData* aGfxData, struct CollisionValidation
static void ValidateColWaterBoxInit(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0) {
if (arg0 < 0) {
PrintDataError("COL_WATER_BOX_INIT with a negative count: %d", arg0);
DynOS_PrintDataError("COL_WATER_BOX_INIT with a negative count: %d", arg0);
}
ValidateColSectionChange(aGfxData, aColValData, COL_SECTION_WATER_BOX);
aColValData.waterBoxAlloc = arg0;
@ -145,28 +145,28 @@ static void ValidateColWaterBoxInit(GfxData* aGfxData, struct CollisionValidatio
static void ValidateColWaterBox(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4, s16 arg5) {
if (aColValData.section != COL_SECTION_WATER_BOX) {
PrintDataError("COL_WATER_BOX found outside of water box section");
DynOS_PrintDataError("COL_WATER_BOX found outside of water box section");
}
aColValData.waterBoxCount++;
}
static void ValidateColSpecialObject(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3) {
if (aColValData.section != COL_SECTION_SPECIAL) {
PrintDataError("SPECIAL_OBJECT found outside of special section");
DynOS_PrintDataError("SPECIAL_OBJECT found outside of special section");
}
aColValData.specialCount++;
}
static void ValidateColSpecialObjectWithYaw(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4) {
if (aColValData.section != COL_SECTION_SPECIAL) {
PrintDataError("SPECIAL_OBJECT_WITH_YAW found outside of special section");
DynOS_PrintDataError("SPECIAL_OBJECT_WITH_YAW found outside of special section");
}
aColValData.specialCount++;
}
static void ValidateColSpecialObjectWithYawAndParam(GfxData* aGfxData, struct CollisionValidationData& aColValData, s16 arg0, s16 arg1, s16 arg2, s16 arg3, s16 arg4, s16 arg5) {
if (aColValData.section != COL_SECTION_SPECIAL) {
PrintDataError("SPECIAL_OBJECT_WITH_YAW_AND_PARAM found outside of special section");
DynOS_PrintDataError("SPECIAL_OBJECT_WITH_YAW_AND_PARAM found outside of special section");
}
aColValData.specialCount++;
}
@ -458,7 +458,7 @@ static s16 ParseColSymbolArg(GfxData* aGfxData, DataNode<Collision>* aNode, u64&
}
// Unknown
PrintDataError(" ERROR: Unknown col arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown col arg: %s", _Arg.begin());
return 0;
}
@ -575,7 +575,7 @@ static void ParseCollisionSymbol(GfxData* aGfxData, DataNode<Collision>* aNode,
col_symbol_6(SPECIAL_OBJECT_WITH_YAW_AND_PARAM, ValidateColSpecialObjectWithYawAndParam);
// Unknown
PrintDataError(" ERROR: Unknown col symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown col symbol: %s", _Symbol.begin());
}
DataNode<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNode, bool aDisplayPercent) {
@ -595,7 +595,7 @@ DataNode<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNo
}
if (colValData.section != COL_SECTION_END) {
PrintDataError("Collision did not end with COL_END");
DynOS_PrintDataError("Collision did not end with COL_END");
}
if (aDisplayPercent && aGfxData->mErrorCount == 0) { Print("100%%"); }
@ -603,7 +603,7 @@ DataNode<Collision>* DynOS_Col_Parse(GfxData* aGfxData, DataNode<Collision>* aNo
aNode->mLoadIndex = aGfxData->mLoadIndex++;
if (aGfxData->mErrorCount > 0) {
PrintDataError("Failed to parse collision: '%s'", aNode->mName.begin());
DynOS_PrintDataError("Failed to parse collision: '%s'", aNode->mName.begin());
}
return aNode;
@ -630,7 +630,7 @@ void DynOS_Col_Write(BinFile* aFile, GfxData* aGfxData, DataNode<Collision> *aNo
static bool DynOS_Col_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData, DataNode<Collision>* _Node) {
BinFile *_File = BinFile::OpenW(aOutputFilename.c_str());
if (!_File) {
PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
@ -706,14 +706,14 @@ void DynOS_Col_Generate(const SysPath &aPackFolder, Array<Pair<u64, String>> _Ac
// Parse data
PrintNoNewLine("%s.col: Collision identifier: %X - Processing... ", _ColRootName.begin(), _GfxData->mModelIdentifier);
PrintConsole(CONSOLE_MESSAGE_INFO, "%s.col: Collision identifier: %X - Processing... ", _ColRootName.begin(), _GfxData->mModelIdentifier);
DynOS_PrintConsole(CONSOLE_MESSAGE_INFO, "%s.col: Collision identifier: %X - Processing... ", _ColRootName.begin(), _GfxData->mModelIdentifier);
DynOS_Col_Parse(_GfxData, _ColNode, true);
// Write if no error
if (_GfxData->mErrorCount == 0) {
DynOS_Col_WriteBinary(_ColFilename, _GfxData, _ColNode);
} else {
PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
DynOS_PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
}
// Clear data pointers

View file

@ -29,7 +29,7 @@ static inline void DynOS_Bin_Compress_Free() {
static inline bool DynOS_Bin_Compress_Check(bool condition, const char *function, const char *filename, const char *message) {
if (!condition) {
PrintError("ERROR: %s: File \"%s\": %s", function, filename, message);
DynOS_PrintError("ERROR: %s: File \"%s\": %s", function, filename, message);
DynOS_Bin_Compress_Free();
return false;
}
@ -223,7 +223,7 @@ BinFile *DynOS_Bin_Decompress(const SysPath &aFilename) {
uncompressRc == Z_OK,
__FUNCTION__, aFilename.c_str(), "Cannot uncompress data"
)) {
PrintError("ERROR: uncompress rc: %d, length uncompressed: %lu, length compressed: %lu, length header: %lu", uncompressRc, sLengthUncompressed, sLengthCompressed, _LengthHeader);
DynOS_PrintError("ERROR: uncompress rc: %d, length uncompressed: %lu, length compressed: %lu, length header: %lu", uncompressRc, sLengthUncompressed, sLengthCompressed, _LengthHeader);
return NULL;
}
Print("uncompress rc: %d, length uncompressed: %lu, length compressed: %lu, length header: %lu", uncompressRc, sLengthUncompressed, sLengthCompressed, _LengthHeader);

View file

@ -148,7 +148,7 @@ static s64 ParseGeoSymbolArg(GfxData* aGfxData, DataNode<GeoLayout>* aNode, u64&
}
// Unknown
PrintDataError(" ERROR: Unknown geo arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown geo arg: %s", _Arg.begin());
return 0;
}
@ -433,7 +433,7 @@ static void ParseGeoSymbol(GfxData* aGfxData, DataNode<GeoLayout>* aNode, GeoLay
}
// Unknown
PrintDataError(" ERROR: Unknown geo symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown geo symbol: %s", _Symbol.begin());
}
DataNode<GeoLayout>* DynOS_Geo_Parse(GfxData* aGfxData, DataNode<GeoLayout>* aNode, bool aDisplayPercent) {

View file

@ -12,18 +12,18 @@ static std::map<std::string, std::pair<Gfx *, u32>> sGfxCommandCache;
static char *sGfxCommandErrorMsg = NULL;
static u32 sGfxCommandErrorSize = 0;
#define PrintDataErrorGfx(...) { \
#define DynOS_PrintDataErrorGfx(...) { \
if (sGfxCommandErrorMsg) { \
snprintf(sGfxCommandErrorMsg, sGfxCommandErrorSize, __VA_ARGS__); \
aGfxData->mErrorCount++; \
} else { \
PrintDataError(__VA_ARGS__); \
DynOS_PrintDataError(__VA_ARGS__); \
} \
}
#define CHECK_TOKEN_INDEX(tokenIndex, returnValue) { \
if (tokenIndex >= aNode->mTokens.Count()) { \
PrintDataErrorGfx(" ERROR: Invalid token index: %llu, tokens count is: %d", tokenIndex, aNode->mTokens.Count()); \
DynOS_PrintDataErrorGfx(" ERROR: Invalid token index: %llu, tokens count is: %d", tokenIndex, aNode->mTokens.Count()); \
return returnValue; \
} \
}
@ -570,7 +570,7 @@ static s64 ParseGfxSymbolArg(GfxData* aGfxData, DataNode<Gfx>* aNode, u64* pToke
}
// Unknown
PrintDataErrorGfx(" ERROR: Unknown gfx arg: %s", _Arg.begin());
DynOS_PrintDataErrorGfx(" ERROR: Unknown gfx arg: %s", _Arg.begin());
return 0;
}
@ -764,7 +764,7 @@ static String ConvertSetCombineModeArgToString(GfxData *aGfxData, const String&
gfx_set_combine_mode_arg(G_CC_HILITERGBA2);
gfx_set_combine_mode_arg(G_CC_HILITERGBDECALA2);
gfx_set_combine_mode_arg(G_CC_HILITERGBPASSA2);
PrintDataErrorGfx(" ERROR: Unknown gfx gsDPSetCombineMode arg: %s", _Arg.begin());
DynOS_PrintDataErrorGfx(" ERROR: Unknown gfx gsDPSetCombineMode arg: %s", _Arg.begin());
return "";
}
@ -785,7 +785,7 @@ static Array<s64> ParseGfxSetCombineMode(GfxData* aGfxData, DataNode<Gfx>* aNode
}
}
if (_Args.Count() < 8) {
PrintDataErrorGfx(" ERROR: gsDPSetCombineMode %s: Not enough arguments", _Buffer.begin());
DynOS_PrintDataErrorGfx(" ERROR: gsDPSetCombineMode %s: Not enough arguments", _Buffer.begin());
}
return _Args;
}
@ -1115,7 +1115,7 @@ static void ParseGfxSymbol(GfxData* aGfxData, DataNode<Gfx>* aNode, Gfx*& aHead,
}
// Unknown
PrintDataErrorGfx(" ERROR: Unknown gfx symbol: %s", _Symbol.begin());
DynOS_PrintDataErrorGfx(" ERROR: Unknown gfx symbol: %s", _Symbol.begin());
}
DataNode<Gfx>* DynOS_Gfx_Parse(GfxData* aGfxData, DataNode<Gfx>* aNode) {
@ -1217,7 +1217,7 @@ template <typename T, typename SmluaToFunc, typename ReturnFunc>
static String ConvertParam(lua_State *L, GfxData *aGfxData, u32 paramIndex, const char *typeName, const SmluaToFunc &smluaToFunc, const ReturnFunc &returnFunc) {
T value = smluaToFunc(L, paramIndex);
if (!gSmLuaConvertSuccess) {
PrintDataErrorGfx(" ERROR: Failed to convert parameter %u to %s", paramIndex, typeName);
DynOS_PrintDataErrorGfx(" ERROR: Failed to convert parameter %u to %s", paramIndex, typeName);
return "";
}
return returnFunc(value);
@ -1266,7 +1266,7 @@ static String ResolveParam(lua_State *L, GfxData *aGfxData, u32 paramIndex, char
[&aGfxData] (Gfx *gfx) { return CreateRawPointerDataNode(aGfxData, gfx); }
);
}
PrintDataErrorGfx(" ERROR: Unknown parameter type: '%c'", paramType);
DynOS_PrintDataErrorGfx(" ERROR: Unknown parameter type: '%c'", paramType);
return "";
}
@ -1353,7 +1353,7 @@ static bool CheckGfxLength(GfxData *aGfxData, Gfx *gfx, u32 lengthToWrite) {
if (lengthToWrite > 1) {
u32 gfxLength = gfx_get_length(gfx);
if (gfxLength < lengthToWrite) {
PrintDataErrorGfx(" ERROR: Cannot write %u commands to display list of length: %u", lengthToWrite, gfxLength);
DynOS_PrintDataErrorGfx(" ERROR: Cannot write %u commands to display list of length: %u", lengthToWrite, gfxLength);
return false;
}
}

View file

@ -9,13 +9,13 @@ DataNode<Lights0>* DynOS_Light0_Parse(GfxData* aGfxData, DataNode<Lights0>* aNod
// Check tokens count
if (aNode->mTokens.Count() < 4) {
PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
DynOS_PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}
// Parse def token
if (aNode->mTokens[0] != "gdSPDefLights0") {
PrintDataError(" ERROR: Invalid def token: should be gdSPDefLights0, is %s", aNode->mTokens[0].begin());
DynOS_PrintDataError(" ERROR: Invalid def token: should be gdSPDefLights0, is %s", aNode->mTokens[0].begin());
return aNode;
}

View file

@ -9,7 +9,7 @@ DataNode<Light_t>* DynOS_LightT_Parse(GfxData* aGfxData, DataNode<Light_t>* aNod
// Check tokens count
if (aNode->mTokens.Count() < 12) {
PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
DynOS_PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}

View file

@ -9,13 +9,13 @@ DataNode<Lights1>* DynOS_Lights_Parse(GfxData* aGfxData, DataNode<Lights1>* aNod
// Check tokens count
if (aNode->mTokens.Count() < 10) {
PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
DynOS_PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}
// Parse def token
if (aNode->mTokens[0] != "gdSPDefLights1") {
PrintDataError(" ERROR: Invalid def token: should be gdSPDefLights1, is %s", aNode->mTokens[0].begin());
DynOS_PrintDataError(" ERROR: Invalid def token: should be gdSPDefLights1, is %s", aNode->mTokens[0].begin());
return aNode;
}

View file

@ -529,7 +529,7 @@ static LevelScript ParseLevelScriptSymbolArg(GfxData* aGfxData, DataNode<LevelSc
LevelScript value = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &found);
if (!found) {
const String& _Arg = aNode->mTokens[aTokenIndex - 1];
PrintDataError(" ERROR: Unknown lvl arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown lvl arg: %s", _Arg.begin());
}
return value;
}
@ -881,7 +881,7 @@ static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode<LevelScript>* aNo
}
// Unknown
PrintDataError(" ERROR: Unknown lvl symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown lvl symbol: %s", _Symbol.begin());
}
DataNode<LevelScript>* DynOS_Lvl_Parse(GfxData* aGfxData, DataNode<LevelScript>* aNode, bool aDisplayPercent) {
@ -938,7 +938,7 @@ static void DynOS_Lvl_Write(BinFile* aFile, GfxData* aGfxData, DataNode<LevelScr
static bool DynOS_Lvl_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
BinFile *_File = BinFile::OpenW(aOutputFilename.c_str());
if (!_File) {
PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
@ -1058,12 +1058,12 @@ static DataNode<LevelScript>* DynOS_Lvl_Load(BinFile *aFile, GfxData *aGfxData)
void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value, &_Node->mFlags);
if (_Ptr) {
if (!requirePointer) {
PrintError("Didn't expect a pointer while reading level script: %s, %u", _Node->mName.begin(), _Value);
DynOS_PrintError("Didn't expect a pointer while reading level script: %s, %u", _Node->mName.begin(), _Value);
}
_Node->mData[i] = (uintptr_t) _Ptr;
} else {
if (requirePointer) {
PrintError("Expected a pointer while reading level script: %s, %u", _Node->mName.begin(), _Value);
DynOS_PrintError("Expected a pointer while reading level script: %s, %u", _Node->mName.begin(), _Value);
_Node->mData[i] = 0;
} else {
_Node->mData[i] = (uintptr_t) _Value;
@ -1151,7 +1151,7 @@ static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pa
// Parse data
PrintNoNewLine("%s.lvl: Level identifier: %X - Processing... ", _LvlRootName.begin(), _GfxData->mModelIdentifier);
PrintConsole(CONSOLE_MESSAGE_INFO, "%s.lvl: Level identifier: %X - Processing... ", _LvlRootName.begin(), _GfxData->mModelIdentifier);
DynOS_PrintConsole(CONSOLE_MESSAGE_INFO, "%s.lvl: Level identifier: %X - Processing... ", _LvlRootName.begin(), _GfxData->mModelIdentifier);
DynOS_Lvl_Parse(_GfxData, _LvlRoot, true);
// Force all of the movtexs, collisions, and trajectories into the compiled lvl
@ -1176,7 +1176,7 @@ static bool DynOS_Lvl_GeneratePack_Internal(const SysPath &aPackFolder, Array<Pa
if (_GfxData->mErrorCount == 0) {
DynOS_Lvl_WriteBinary(_LvlFilename, _GfxData);
} else {
PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
DynOS_PrintError(" %u error(s): Unable to parse data", _GfxData->mErrorCount);
}
// Clear data pointers

View file

@ -404,7 +404,7 @@ static s64 ParseMacroObjectSymbolArg(GfxData* aGfxData, DataNode<MacroObject>* a
}
// Unknown
PrintDataError(" ERROR: Unknown macro object arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown macro object arg: %s", _Arg.begin());
return 0;
}
@ -451,7 +451,7 @@ static void ParseMacroObjectSymbol(GfxData* aGfxData, DataNode<MacroObject>* aNo
macro_object_symbol_0(MACRO_OBJECT_END);
// Unknown
PrintDataError(" ERROR: Unknown macro object symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown macro object symbol: %s", _Symbol.begin());
}
DataNode<MacroObject>* DynOS_MacroObject_Parse(GfxData* aGfxData, DataNode<MacroObject>* aNode, bool aDisplayPercent) {

View file

@ -40,7 +40,7 @@ static s64 ParseMovtexSymbolArg(GfxData* aGfxData, DataNode<Movtex>* aNode, u64&
movtex_constant(NULL);
// Unknown
PrintDataError(" ERROR: Unknown movtex arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown movtex arg: %s", _Arg.begin());
return 0;
}
@ -143,7 +143,7 @@ static void ParseMovtexSymbol(GfxData* aGfxData, DataNode<Movtex>* aNode, Movtex
}
// Unknown
PrintDataError(" ERROR: Unknown movtex symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown movtex symbol: %s", _Symbol.begin());
}
DataNode<Movtex>* DynOS_Movtex_Parse(GfxData* aGfxData, DataNode<Movtex>* aNode, bool aDisplayPercent) {

View file

@ -27,7 +27,7 @@ static Movtex* ParseMovtexQCSymbolArg(GfxData* aGfxData, DataNode<MovtexQC>* aNo
}
// Unknown
PrintDataError(" ERROR: Unknown movtexqc arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown movtexqc arg: %s", _Arg.begin());
return NULL;
}

View file

@ -199,7 +199,7 @@ static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
}
}
PrintDataError("Unable to find pointer %x!", aPtr);
DynOS_PrintDataError("Unable to find pointer %x!", aPtr);
return { "", 0 };
}

View file

@ -226,7 +226,7 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
} else if (_Buffer == "BehaviorScript") {
_DataType = DATA_TYPE_BEHAVIOR_SCRIPT;
} else {
PrintDataError(" ERROR: Unknown type name: %s", _Buffer.begin());
DynOS_PrintDataError(" ERROR: Unknown type name: %s", _Buffer.begin());
}
_Buffer.Clear();
}
@ -277,7 +277,7 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) {
if (*c == '=') {
pDataStart = c + 1;
} else if (*c == ';') {
PrintDataError(" ERROR: %s: Unexpected end of data", pDataName->begin());
DynOS_PrintDataError(" ERROR: %s: Unexpected end of data", pDataName->begin());
}
}

View file

@ -52,7 +52,7 @@ static TexData* LoadTextureFromFile(GfxData *aGfxData, const char* aFile) {
// The file does not exist in either spot!
if (!_File) {
PrintDataError(" ERROR: Unable to open file at \"%s\" or \"%s\"", _Filename.c_str(), _ActorFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to open file at \"%s\" or \"%s\"", _Filename.c_str(), _ActorFilename.c_str());
return NULL;
}
}
@ -72,7 +72,7 @@ void DynOS_Tex_ConvertTextureDataToPng(GfxData *aGfxData, TexData* aTexture) {
const u8 *_Palette = (aGfxData->mGfxContext.mCurrentPalette ? aGfxData->mGfxContext.mCurrentPalette->mData->mRawData.begin() : NULL);
u8 *_Buffer = DynOS_Tex_ConvertToRGBA32(aTexture->mRawData.begin(), aTexture->mRawData.Count(), aTexture->mRawFormat, aTexture->mRawSize, _Palette);
if (_Buffer == NULL) {
PrintDataError(" ERROR: Unknown texture format");
DynOS_PrintDataError(" ERROR: Unknown texture format");
return;
}
@ -80,7 +80,7 @@ void DynOS_Tex_ConvertTextureDataToPng(GfxData *aGfxData, TexData* aTexture) {
s32 _PngLength = 0;
u8 *_PngData = stbi_write_png_to_mem(_Buffer, 0, aTexture->mRawWidth, aTexture->mRawHeight, 4, &_PngLength);
if (!_PngData || !_PngLength) {
PrintDataError(" ERROR: Cannot convert texture to PNG");
DynOS_PrintDataError(" ERROR: Cannot convert texture to PNG");
return;
}
@ -97,7 +97,7 @@ DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode)
// Check tokens Count
if (aNode->mTokens.Count() < 1) {
PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
DynOS_PrintDataError(" ERROR: %s: not enough data", aNode->mName.begin());
return aNode;
}
@ -107,7 +107,7 @@ DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode)
s32 i1 = aNode->mTokens[0].Find(".inc.c");
if (i1 == -1) {
if (strstr(aNode->mName.begin(), "_pal_") == NULL) {
PrintDataError(" ERROR: %s: missing .inc.c in String %s", aNode->mName.begin(), aNode->mTokens[0].begin());
DynOS_PrintDataError(" ERROR: %s: missing .inc.c in String %s", aNode->mName.begin(), aNode->mTokens[0].begin());
} else {
// hack for pal textures to be "found"
TexData* _Texture = New<TexData>();
@ -129,7 +129,7 @@ DataNode<TexData>* DynOS_Tex_Parse(GfxData* aGfxData, DataNode<TexData>* aNode)
if (dq0 != -1) {
s32 dq1 = aNode->mTokens[0].Find('\"', dq0 + 1);
if (dq1 == -1) {
PrintDataError(" ERROR: %s: missing second quote in String %s", aNode->mName.begin(), aNode->mTokens[0].begin());
DynOS_PrintDataError(" ERROR: %s: missing second quote in String %s", aNode->mName.begin(), aNode->mTokens[0].begin());
return aNode;
}
@ -188,7 +188,7 @@ void DynOS_Tex_Write(BinFile* aFile, GfxData* aGfxData, DataNode<TexData> *aNode
static bool DynOS_Tex_WriteBinary(GfxData* aGfxData, const SysPath &aOutputFilename, String& aName, TexData* aTexData, bool aRawTexture) {
BinFile *_File = BinFile::OpenW(aOutputFilename.c_str());
if (!_File) {
PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
DynOS_PrintDataError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
@ -429,7 +429,7 @@ static void DynOS_Tex_GeneratePack_Recursive(const SysPath &aPackFolder, SysPath
aGfxData->mModelIdentifier++;
TexData* _TexData = LoadTextureFromFile(aGfxData, _Path.c_str());
if (_TexData == NULL) {
PrintDataError("Error reading texture from file: %s", _Path.c_str());
DynOS_PrintDataError("Error reading texture from file: %s", _Path.c_str());
continue;
}

View file

@ -13,7 +13,7 @@ static TexData* ParseTexListSymbol(GfxData* aGfxData, DataNode<TexData*>* aNode,
}
// Unknown
PrintDataError(" ERROR: Unknown texlist arg: %s", aToken.begin());
DynOS_PrintDataError(" ERROR: Unknown texlist arg: %s", aToken.begin());
return NULL;
}
@ -56,7 +56,7 @@ void DynOS_TexList_Write(BinFile* aFile, GfxData* aGfxData, DataNode<TexData*> *
}
}
if (!found) {
PrintDataError("Could not write texture in texlist");
DynOS_PrintDataError("Could not write texture in texlist");
}
}
}
@ -78,7 +78,7 @@ DataNode<TexData*>* DynOS_TexList_Load(BinFile *aFile, GfxData *aGfxData) {
u32 _Value = aFile->Read<u32>();
void *_Ptr = DynOS_Pointer_Load(aFile, aGfxData, _Value, &_Node->mFlags);
if (_Ptr == NULL) {
PrintDataError("Could not read texture in texlist");
DynOS_PrintDataError("Could not read texture in texlist");
} else {
_Node->mData[i] = ((DataNode<TexData>*)_Ptr)->mData;
}

View file

@ -28,7 +28,7 @@ static s64 ParseTrajectorySymbolArg(GfxData* aGfxData, DataNode<Trajectory>* aNo
trajectory_constant(NULL);
// Unknown
PrintDataError(" ERROR: Unknown trajectory arg: %s", _Arg.begin());
DynOS_PrintDataError(" ERROR: Unknown trajectory arg: %s", _Arg.begin());
return 0;
}
@ -59,7 +59,7 @@ static void ParseTrajectorySymbol(GfxData* aGfxData, DataNode<Trajectory>* aNode
trajectory_symbol_0(TRAJECTORY_END);
// Unknown
PrintDataError(" ERROR: Unknown trajectory symbol: %s", _Symbol.begin());
DynOS_PrintDataError(" ERROR: Unknown trajectory symbol: %s", _Symbol.begin());
}
DataNode<Trajectory>* DynOS_Trajectory_Parse(GfxData* aGfxData, DataNode<Trajectory>* aNode, bool aDisplayPercent) {

View file

@ -40,7 +40,7 @@ void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *
GfxData *_GfxData = DynOS_Actor_LoadFromBinary(aFilename, actorName, aFilename, false);
if (!_GfxData) {
PrintError(" ERROR: Couldn't load Actor Binary \"%s\" from \"%s\"", actorName, aFilename.c_str());
DynOS_PrintError(" ERROR: Couldn't load Actor Binary \"%s\" from \"%s\"", actorName, aFilename.c_str());
free(actorName);
return;
}
@ -48,7 +48,7 @@ void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *
void* geoLayout = (*(_GfxData->mGeoLayouts.end() - 1))->mData;
if (!geoLayout) {
PrintError(" ERROR: Couldn't load geo layout for \"%s\"", actorName);
DynOS_PrintError(" ERROR: Couldn't load geo layout for \"%s\"", actorName);
free(actorName);
return;
}
@ -60,7 +60,7 @@ void DynOS_Actor_AddCustom(s32 aModIndex, const SysPath &aFilename, const char *
actorGfx.mPackIndex = MOD_PACK_INDEX;
actorGfx.mGraphNode = (GraphNode *) DynOS_Model_LoadGeo(&id, MODEL_POOL_SESSION, geoLayout, true);
if (!actorGfx.mGraphNode) {
PrintError(" ERROR: Couldn't load graph node for \"%s\"", actorName);
DynOS_PrintError(" ERROR: Couldn't load graph node for \"%s\"", actorName);
free(actorName);
return;
}

View file

@ -105,7 +105,7 @@ void DynOS_Bhv_HookAllCustomBehaviors() {
// Theres currently no better place but to do this here.
if (smlua_hook_custom_bhv(script, scriptName) == 0) {
PrintDataError(" ERROR: Failed to add custom behavior '%s'!", scriptName);
DynOS_PrintDataError(" ERROR: Failed to add custom behavior '%s'!", scriptName);
}
}
}

View file

@ -85,7 +85,7 @@ void DynOS_Lvl_Activate(s32 modIndex, const SysPath &aFilename, const char *aLev
// Override vanilla script
auto& newScripts = _Node->mLevelScripts;
if (newScripts.Count() <= 0) {
PrintError("Could not find level scripts: '%s'", aLevelName);
DynOS_PrintError("Could not find level scripts: '%s'", aLevelName);
return;
}
@ -161,7 +161,7 @@ void DynOS_Lvl_LoadBackground(void *aPtr) {
double_break:
if (foundList == NULL) {
PrintError("Could not find custom background");
DynOS_PrintError("Could not find custom background");
return;
}

View file

@ -474,7 +474,7 @@ bool DynOS_Tex_Get(const char* aTexName, struct TextureInfo* aOutTexInfo) {
u8 *_RawData = stbi_load_from_memory(_Data->mPngData.begin(), _Data->mPngData.Count(), &_Data->mRawWidth, &_Data->mRawHeight, NULL, 4);
// texture data is corrupted
if (_RawData == NULL) {
PrintError("Attempted to load corrupted tex file: %s", aTexName);
DynOS_PrintError("Attempted to load corrupted tex file: %s", aTexName);
return false;
}
_Data->mRawFormat = G_IM_FMT_RGBA;

View file

@ -8,6 +8,9 @@
#define TRUE 1
#define FALSE 0
#ifdef __SWITCH__
#include <switch.h>
#else
typedef signed char s8;
typedef unsigned char u8;
typedef signed short int s16;
@ -25,6 +28,7 @@ typedef volatile s8 vs8;
typedef volatile s16 vs16;
typedef volatile s32 vs32;
typedef volatile s64 vs64;
#endif
typedef float f32;
typedef double f64;

View file

@ -19,6 +19,10 @@
#define BAD_RETURN(cmd) cmd
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
struct Controller
{
// For optimization reasons, See MarioState

BIN
lib/coopnet/nx/libcoopnet.a Normal file

Binary file not shown.

BIN
lib/coopnet/nx/libjuice.a Normal file

Binary file not shown.

View file

@ -47,10 +47,13 @@
/*
** By default, Lua on Windows use (some) specific Windows features
*/
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SWITCH__)
#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
#endif
#if defined(__SWITCH__)
#define LUA_USE_C89
#endif
#if defined(LUA_USE_WINDOWS)
#define LUA_DL_DLL /* enable support for DLL */

BIN
lib/lua/nx/liblua53.a Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

167
res/npdm.json Normal file
View file

@ -0,0 +1,167 @@
{
"name": "SM64 Coop DX",
"program_id": "0x0100534d36344350",
"program_id_range_min": "0x0100534d36344350",
"program_id_range_max": "0x0100534d36344350",
"main_thread_stack_size": "0x100000",
"main_thread_priority": 44,
"default_cpu_id": 0,
"process_category": 0,
"pool_partition": 0,
"is_64_bit": true,
"address_space_type": 1,
"optimize_memory_allocation": true,
"disable_device_address_space_merge": false,
"prevent_code_reads": false,
"signature_key_generation": 1,
"is_retail": true,
"filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF"
},
"service_host": [
"*"
],
"service_access": [
"*"
],
"kernel_capabilities": [
{
"type": "kernel_flags",
"value": {
"highest_thread_priority": 59,
"lowest_thread_priority": 28,
"highest_cpu_id": 2,
"lowest_cpu_id": 0
}
},
{
"type": "syscalls",
"value": {
"svcUnknown00": "0x00",
"svcSetHeapSize": "0x01",
"svcSetMemoryPermission": "0x02",
"svcSetMemoryAttribute": "0x03",
"svcMapMemory": "0x04",
"svcUnmapMemory": "0x05",
"svcQueryMemory": "0x06",
"svcExitProcess": "0x07",
"svcCreateThread": "0x08",
"svcStartThread": "0x09",
"svcExitThread": "0x0A",
"svcSleepThread": "0x0B",
"svcGetThreadPriority": "0x0C",
"svcSetThreadPriority": "0x0D",
"svcGetThreadCoreMask": "0x0E",
"svcSetThreadCoreMask": "0x0F",
"svcGetCurrentProcessorNumber": "0x10",
"svcSignalEvent": "0x11",
"svcClearEvent": "0x12",
"svcMapSharedMemory": "0x13",
"svcUnmapSharedMemory": "0x14",
"svcCreateTransferMemory": "0x15",
"svcCloseHandle": "0x16",
"svcResetSignal": "0x17",
"svcWaitSynchronization": "0x18",
"svcCancelSynchronization": "0x19",
"svcArbitrateLock": "0x1A",
"svcArbitrateUnlock": "0x1B",
"svcWaitProcessWideKeyAtomic": "0x1C",
"svcSignalProcessWideKey": "0x1D",
"svcGetSystemTick": "0x1E",
"svcConnectToNamedPort": "0x1F",
"svcSendSyncRequestLight": "0x20",
"svcSendSyncRequest": "0x21",
"svcSendSyncRequestWithUserBuffer": "0x22",
"svcSendAsyncRequestWithUserBuffer": "0x23",
"svcGetProcessId": "0x24",
"svcGetThreadId": "0x25",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcReturnFromException": "0x28",
"svcGetInfo": "0x29",
"svcFlushEntireDataCache": "0x2A",
"svcFlushDataCache": "0x2B",
"svcMapPhysicalMemory": "0x2C",
"svcUnmapPhysicalMemory": "0x2D",
"svcGetFutureThreadInfo": "0x2E",
"svcGetLastThreadInfo": "0x2F",
"svcGetResourceLimitLimitValue": "0x30",
"svcGetResourceLimitCurrentValue": "0x31",
"svcSetThreadActivity": "0x32",
"svcGetThreadContext3": "0x33",
"svcWaitForAddress": "0x34",
"svcSignalToAddress": "0x35",
"svcUnknown36": "0x36",
"svcUnknown37": "0x37",
"svcUnknown38": "0x38",
"svcUnknown39": "0x39",
"svcUnknown3a": "0x3A",
"svcUnknown3b": "0x3B",
"svcDumpInfo": "0x3C",
"svcDumpInfoNew": "0x3D",
"svcUnknown3e": "0x3E",
"svcUnknown3f": "0x3F",
"svcCreateSession": "0x40",
"svcAcceptSession": "0x41",
"svcReplyAndReceiveLight": "0x42",
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcUnknown46": "0x46",
"svcUnknown47": "0x47",
"svcMapPhysicalMemoryUnsafe": "0x48",
"svcUnmapPhysicalMemoryUnsafe": "0x49",
"svcSetUnsafeLimit": "0x4A",
"svcCreateCodeMemory": "0x4B",
"svcControlCodeMemory": "0x4C",
"svcSleepSystem": "0x4D",
"svcReadWriteRegister": "0x4E",
"svcSetProcessActivity": "0x4F",
"svcCreateSharedMemory": "0x50",
"svcMapTransferMemory": "0x51",
"svcUnmapTransferMemory": "0x52",
"svcDebugActiveProcess": "0x60",
"svcBreakDebugProcess": "0x61",
"svcTerminateDebugProcess": "0x62",
"svcGetDebugEvent": "0x63",
"svcContinueDebugEvent": "0x64",
"svcGetProcessList": "0x65",
"svcGetThreadList": "0x66",
"svcGetDebugThreadContext": "0x67",
"svcSetDebugThreadContext": "0x68",
"svcQueryDebugProcessMemory": "0x69",
"svcReadDebugProcessMemory": "0x6A",
"svcWriteDebugProcessMemory": "0x6B",
"svcSetHardwareBreakPoint": "0x6C",
"svcGetDebugThreadParam": "0x6D",
"svcConnectToPort": "0x72",
"svcSetProcessMemoryPermission": "0x73",
"svcMapProcessMemory": "0x74",
"svcUnmapProcessMemory": "0x75",
"svcQueryProcessMemory": "0x76",
"svcMapProcessCodeMemory": "0x77",
"svcUnmapProcessCodeMemory": "0x78"
}
},
{
"type": "application_type",
"value": 1
},
{
"type": "min_kernel_version",
"value": "0x30"
},
{
"type": "handle_table_size",
"value": 512
},
{
"type": "debug_flags",
"value": {
"allow_debug": false,
"force_debug_prod": false,
"force_debug": true
}
}
]
}

View file

@ -8,7 +8,7 @@
#include <math.h>
#include "engine/math_util.h"
#include "game/scroll_targets.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/utils/misc.h"
static inline void shift_UV_JUMP(struct ScrollTarget *scroll, u16 vertcount, s16 speed, u16 bhv, u16 cycle) {

View file

@ -34,7 +34,7 @@
#include "levels/wf/header.h"
#include "levels/wmotr/header.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
extern Trajectory sThiHugeMetalBallTraj[];
extern Trajectory sThiTinyMetalBallTraj[];

View file

@ -36,7 +36,7 @@
#include "game/interaction.h"
#include "menu/intro_geo.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/cliopts.h"
#include "pc/configfile.h"
#include "pc/network/network.h"

View file

@ -31,7 +31,7 @@
#include "hardcoded.h"
#include "libc/stdlib.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/configfile.h"
#include "pc/network/network.h"
#include "pc/lua/smlua.h"

View file

@ -1,6 +1,6 @@
#include "cliopts.h"
#include "configfile.h"
#include "pc_main.h"
#include "game_main.h"
#include "platform.h"
#include "macros.h"
@ -10,6 +10,8 @@
#include <stdio.h>
#include <string.h>
#include "string_utils.h"
struct CLIOptions gCLIOpts;
static void print_help(void) {

View file

@ -21,7 +21,8 @@
#include "djui/djui_hud_utils.h"
#include "game/save_file.h"
#include "pc/network/network_player.h"
#include "pc/pc_main.h"
#include "string_utils.h"
#include "pc/game_main.h"
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
@ -84,7 +85,11 @@ ConfigStick configStick = { 0 };
// display settings
unsigned int configFiltering = 2; // 0 = Nearest, 1 = Bilinear, 2 = Trilinear
bool configShowFPS = false;
#if defined(__SWITCH__)
bool configUncappedFramerate = false;
#else
bool configUncappedFramerate = true;
#endif
unsigned int configFrameLimit = 60;
unsigned int configInterpolationMode = 1;
unsigned int configDrawDistance = 4;

View file

@ -12,7 +12,7 @@
#include "controller_api.h"
#include "controller_sdl.h"
#if defined(CAPI_SDL1) || defined(CAPI_SDL2)
#if defined(CAPI_SDL1) || defined(CAPI_SDL2) || defined(CAPI_SWITCH)
static int inverted_scancode_table[512];
static SDL_Scancode bind_to_sdl_scancode[512] = { 0 };

View file

@ -1,7 +1,7 @@
#ifndef CONTROLLER_BIND_MAPPING_H
#define CONTROLLER_BIND_MAPPING_H
#if defined(CAPI_SDL1) || defined(CAPI_SDL2)
#if defined(CAPI_SDL1) || defined(CAPI_SDL2) || defined(CAPI_SWITCH)
void controller_bind_init(void);
int translate_sdl_scancode(int scancode);
const char* translate_bind_to_name(int bind);

View file

@ -9,6 +9,7 @@
#include "controller_keyboard.h"
#include "controller_sdl.h"
#include "controller_system.h"
#include "controller_switch.h"
// Analog camera movement by Pathétique (github.com/vrmiguel), y0shin and Mors
// Contribute or communicate bugs at github.com/vrmiguel/sm64-analog-camera
@ -16,10 +17,14 @@
// moved these from sdl controller implementations
static struct ControllerAPI *controller_implementations[] = {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
&controller_sdl,
#if defined(CAPI_SWITCH)
&controller_switch,
#else
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
&controller_sdl,
#endif
&controller_keyboard,
#endif
&controller_keyboard,
};
s32 osContInit(UNUSED OSMesgQueue *mq, u8 *controllerBits, UNUSED OSContStatus *status) {

View file

@ -9,7 +9,7 @@
#include "controller_keyboard.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "engine/math_util.h"
#include "menu/file_select.h"
#include "pc/djui/djui.h"

View file

@ -17,7 +17,7 @@
#include "controller_sdl.h"
#include "controller_mouse.h"
#include "controller_system.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/configfile.h"
#include "pc/platform.h"
#include "pc/fs/fs.h"
@ -122,6 +122,7 @@ static void controller_sdl_init(void) {
haptics_enabled = (SDL_InitSubSystem(SDL_INIT_HAPTIC) == 0);
#ifndef __SWITCH__
// try loading an external gamecontroller mapping file
uint64_t gcsize = 0;
void *gcdata = fs_load_file("gamecontrollerdb.txt", &gcsize);
@ -134,6 +135,7 @@ static void controller_sdl_init(void) {
}
free(gcdata);
}
#endif
if (gNewCamera.isMouse) { controller_mouse_enter_relative(); }
controller_mouse_read_relative();
@ -182,7 +184,7 @@ extern s16 gMenuMode;
static void controller_sdl_read(OSContPad *pad) {
if (!init_ok) { return; }
if ((gNewCamera.isMouse || get_first_person_enabled() || gDjuiHudLockMouse) && !is_game_paused() && !gDjuiPanelPauseCreated && !gDjuiInMainMenu && !gDjuiChatBoxFocus && !gDjuiConsoleFocus && WAPI.has_focus()) {
if ((gNewCamera.isMouse || get_first_person_enabled() || gDjuiHudLockMouse) && !is_game_paused() && !gDjuiPanelPauseCreated && !gDjuiInMainMenu && !gDjuiChatBoxFocus && !gDjuiConsoleFocus && wm_api->has_focus()) {
controller_mouse_enter_relative();
} else {
controller_mouse_leave_relative();

View file

@ -0,0 +1,298 @@
#ifdef CAPI_SWITCH
#include <stdlib.h>
#include <ultra64.h>
#include <switch.h>
#include <sm64.h>
#include "../../game/level_update.h"
#include "controller_switch.h"
#include "pc/djui/djui.h"
#include "pc/djui/djui_base.h"
#include "pc/djui/djui_interactable.h"
#include "pc/djui/djui_panel_pause.h"
// Buttons & Sticks
static HidAnalogStickState stickStates[2] = { 0 };
static PadState padState = { 0 };
static u64 padBtnsPressed = 0;
static u64 padBtnsDown = 0;
static u64 padBtnsUp = 0;
// Motion Controls
static bool isSixAxis = false;
static HidSixAxisSensorHandle sixAxisHandles[4] = { 0 };
// Rumble
static HidVibrationDeviceHandle VibrationDeviceHandles[2][2] = { 0 };
// Switch Keyboard
static bool kbdInited = false;
static bool kbdShown = false;
static SwkbdInline kbd = { 0 };
static SwkbdAppearArg kbdAppearArg = { 0 };
static void enter_cb(const char *str, SwkbdDecidedEnterArg *arg) {
djui_interactable_on_text_input((char *)str);
djui_interactable_set_input_focus(NULL);
}
static void cancel_cb(void) {
djui_interactable_set_input_focus(NULL);
}
static void changed_string(const char *str, SwkbdChangedStringArg *arg) {
djui_interactable_on_text_editing((char *)str, arg->cursorPos);
}
static void moved_cursor(const char *str, SwkbdMovedCursorArg *arg) {
djui_interactable_on_text_editing((char *)str, arg->cursorPos);
}
static void start_swkb(void) {
if (kbdInited) { return; }
Result rc = swkbdInlineCreate(&kbd);
if (!R_SUCCEEDED(rc)) { return; }
rc = swkbdInlineLaunchForLibraryApplet(&kbd, SwkbdInlineMode_AppletDisplay, 0);
if (!R_SUCCEEDED(rc)) { return; }
swkbdInlineSetDecidedEnterCallback(&kbd, enter_cb);
swkbdInlineSetDecidedCancelCallback(&kbd, cancel_cb);
swkbdInlineSetChangedStringCallback(&kbd, changed_string);
swkbdInlineSetMovedCursorCallback(&kbd, moved_cursor);
swkbdInlineMakeAppearArg(&kbdAppearArg, SwkbdType_All);
swkbdInlineAppearArgSetOkButtonText(&kbdAppearArg, "Submit");
kbdAppearArg.dicFlag = 1;
kbdAppearArg.returnButtonFlag = 1;
kbdInited = true;
}
void show_swkb(char *text) {
if (!kbdInited) { return; }
swkbdInlineSetInputText(&kbd, text);
swkbdInlineSetCursorPos(&kbd, strlen(text));
swkbdInlineAppear(&kbd, &kbdAppearArg);
kbdShown = true;
djui_interactable_on_text_editing("\0", 0);
}
void hide_swkb(void) {
if (!kbdInited) { return; }
swkbdInlineDisappear(&kbd);
kbdShown = false;
}
void poll_swkb(void) {
if (!kbdInited) { return; }
swkbdInlineUpdate(&kbd, NULL);
}
static void quit_swkb(void) {
if (!kbdInited) { return; }
swkbdInlineClose(&kbd);
kbdInited = false;
}
static void start_six_axis() {
isSixAxis = true;
for (int i = 0; i < 4; i++) {
hidStartSixAxisSensor(sixAxisHandles[i]);
}
}
static void stop_six_axis() {
isSixAxis = false;
for (int i = 0; i < 4; i++) {
hidStopSixAxisSensor(sixAxisHandles[i]);
}
}
static s32 gyro_to_stick(float f) {
s32 tmp = f * -255;
if (tmp < -80) tmp = -80;
else if (tmp > 80) tmp = 80;
return tmp;
}
static void update_button_djui(u8 flag, u64 hid) {
bool down = padBtnsDown & hid;
bool up = padBtnsUp & hid;
bool held = (padBtnsPressed & hid) && (!down && !up);
if (down) {
djui_interactable_on_button_down(flag);
}
if (up) {
djui_interactable_on_button_up(flag);
}
if (held) {
djui_interactable_on_button_held(flag);
}
}
static void update_button_game(OSContPad *pad, u32 button, u64 hid) {
if (padBtnsPressed & hid) {
pad->button |= button;
}
}
static void update_button(OSContPad *pad, u32 button, u8 flag, u64 hid) {
update_button_djui(flag, hid);
update_button_game(pad, button, hid);
}
static void update_buttons(OSContPad *pad) {
update_button_game(pad, START_BUTTON, HidNpadButton_Plus);
update_button_djui(DJUI_BTN_SELECT, HidNpadButton_Minus);
update_button_game(pad, B_BUTTON, HidNpadButton_B);
update_button_game(pad, A_BUTTON, HidNpadButton_A);
update_button_game(pad, Y_BUTTON, HidNpadButton_Y);
update_button_game(pad, X_BUTTON, HidNpadButton_X);
update_button_game(pad, L_TRIG, HidNpadButton_L);
update_button_game(pad, R_TRIG, HidNpadButton_ZL);
update_button_game(pad, R_TRIG, HidNpadButton_R);
update_button_game(pad, Z_TRIG, HidNpadButton_ZR);
update_button_game(pad, U_JPAD, HidNpadButton_Up);
update_button_game(pad, L_JPAD, HidNpadButton_Left);
update_button_game(pad, D_JPAD, HidNpadButton_Down);
update_button_game(pad, R_JPAD, HidNpadButton_Right);
// Bind the C stick to the C buttons.
update_button(pad, R_CBUTTONS, DJUI_BTN_CRIGHT, HidNpadButton_StickRRight);
update_button(pad, L_CBUTTONS, DJUI_BTN_CLEFT, HidNpadButton_StickRLeft);
update_button(pad, U_CBUTTONS, DJUI_BTN_CUP, HidNpadButton_StickRUp);
update_button(pad, D_CBUTTONS, DJUI_BTN_CDOWN, HidNpadButton_StickRDown);
}
static void update_sticks(OSContPad *pad) {
s32 leftX = stickStates[0].x / 409;
s32 leftY = stickStates[0].y / 409;
s32 rightX = stickStates[1].x / 409;
s32 rightY = stickStates[1].y / 409;
if (isSixAxis && abs(leftX) < 20 && abs(leftY) < 20) {
HidSixAxisSensorState sixAxis;
u64 style_set = padGetStyleSet(&padState);
if (style_set & HidNpadStyleTag_NpadHandheld) {
hidGetSixAxisSensorStates(sixAxisHandles[0], &sixAxis, 1);
} else if (style_set & HidNpadStyleTag_NpadFullKey) {
hidGetSixAxisSensorStates(sixAxisHandles[1], &sixAxis, 1);
} else if (style_set & HidNpadStyleTag_NpadJoyDual) {
// For JoyDual, read from either the Left or Right Joy-Con depending on which is/are connected
u64 attrib = padGetAttributes(&padState);
if (attrib & HidNpadAttribute_IsRightConnected) {
hidGetSixAxisSensorStates(sixAxisHandles[3], &sixAxis, 1);
} else if (attrib & HidNpadAttribute_IsLeftConnected) {
hidGetSixAxisSensorStates(sixAxisHandles[2], &sixAxis, 1);
}
}
leftX = gyro_to_stick(sixAxis.angular_velocity.y); //Gyroscope Y-Axis (Controller X)
leftY = gyro_to_stick(sixAxis.angular_velocity.x); //Gyroscope X-Axis (Controller Y)
}
pad->stick_x = leftX;
pad->stick_y = leftY;
pad->ext_stick_x = rightX;
pad->ext_stick_y = rightY;
}
static void controller_switch_nx_init(void) {
padConfigureInput(1, HidNpadStyleSet_NpadFullCtrl);
padInitializeDefault(&padState);
hidInitializeVibrationDevices(VibrationDeviceHandles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
hidInitializeVibrationDevices(VibrationDeviceHandles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
//Initiating the SixAxis, needs to be done for all options; Obviously no GC Controller.
hidGetSixAxisSensorHandles(&sixAxisHandles[0], 1, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
hidGetSixAxisSensorHandles(&sixAxisHandles[1], 1, HidNpadIdType_No1, HidNpadStyleTag_NpadFullKey);
hidGetSixAxisSensorHandles(&sixAxisHandles[2], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
djui_interactable_set_buttons_only(true);
start_swkb();
}
static void controller_switch_nx_read(OSContPad *pad) {
switch (gMarioState->action) {
case ACT_IN_CANNON:
case ACT_FIRST_PERSON:
if (!isSixAxis) start_six_axis();
break;
default:
if (isSixAxis) stop_six_axis();
}
padUpdate(&padState);
padBtnsPressed = padGetButtons(&padState);
padBtnsDown = padGetButtonsDown(&padState);
padBtnsUp = padGetButtonsUp(&padState);
stickStates[0] = padGetStickPos(&padState, 0);
stickStates[1] = padGetStickPos(&padState, 1);
update_buttons(pad);
update_sticks(pad);
poll_swkb();
}
static u32 controller_switch_nx_rawkey(void) {
return VK_INVALID;
}
static void controller_switch_nx_rumble_play(f32 strength, UNUSED f32 length) {
HidVibrationValue VibrationValues[2];
HidVibrationValue VibrationValue = {0};
VibrationValue.freq_high = VibrationValue.freq_low = strength * 1.26f;
VibrationValue.amp_high = VibrationValue.amp_low = 1.0f;
memcpy(&VibrationValues[0], &VibrationValue, sizeof(HidVibrationValue));
memcpy(&VibrationValues[1], &VibrationValue, sizeof(HidVibrationValue));
padUpdate(&padState);
u32 target_device = padIsHandheld(&padState) ? 0 : 1;
hidSendVibrationValues(VibrationDeviceHandles[target_device], VibrationValues, 2);
}
static void controller_switch_nx_rumble_stop(void) {
HidVibrationValue VibrationValues[2];
HidVibrationValue VibrationValue_stop = {0};
VibrationValue_stop.freq_low = 160.0f;
VibrationValue_stop.freq_high = 320.0f;
memcpy(&VibrationValues[0], &VibrationValue_stop, sizeof(HidVibrationValue));
memcpy(&VibrationValues[1], &VibrationValue_stop, sizeof(HidVibrationValue));
hidSendVibrationValues(VibrationDeviceHandles[0], VibrationValues, 2);
hidSendVibrationValues(VibrationDeviceHandles[1], VibrationValues, 2);
}
static void controller_switch_nx_shutdown(void) {
djui_interactable_set_buttons_only(false);
quit_swkb();
}
struct ControllerAPI controller_switch = {
VK_INVALID,
controller_switch_nx_init,
controller_switch_nx_read,
controller_switch_nx_rawkey,
controller_switch_nx_rumble_play,
controller_switch_nx_rumble_stop,
NULL, // no rebinding
controller_switch_nx_shutdown
};
#endif

View file

@ -0,0 +1,12 @@
#ifndef CONTROLLER_SWITCH_H
#define CONTROLLER_SWITCH_H
#include "controller_api.h"
extern struct ControllerAPI controller_switch;
void show_swkb(char *text);
void hide_swkb(void);
void poll_swkb(void);
#endif

View file

@ -27,10 +27,14 @@ char gLastRemoteBhv[256] = "";
#include "pc/gfx/gfx_rendering_api.h"
#include "pc/mods/mods.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "controller/controller_keyboard.h"
#include "controller/controller_mouse.h"
#ifndef __SWITCH__
#include "pc/pc_main.h"
#endif
typedef struct {
s32 x, y;
u8 r, g, b;

View file

@ -1,5 +1,5 @@
#include "discord.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/djui/djui.h"
#include "pc/mods/mods.h"
#include "pc/debuglog.h"

View file

@ -2,8 +2,9 @@
#include <string.h>
#include "djui.h"
#include "djui_console.h"
#include "pc/pc_main.h"
#include "engine/math_util.h"
#include "pc/game_main.h"
#include "pc/string_utils.h"
#define MAX_CONSOLE_MESSAGES 500

View file

@ -1,7 +1,7 @@
#include "djui_ctx_display.h"
#include "djui.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/debug_context.h"
#ifdef DEVELOPMENT

View file

@ -2,7 +2,7 @@
#include "djui_panel.h"
#include "pc/controller/controller_mouse.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
extern ALIGNED8 u8 gd_texture_hand_open[];
extern ALIGNED8 u8 gd_texture_hand_closed[];
@ -112,7 +112,7 @@ void djui_cursor_move(s8 xDir, s8 yDir) {
}
void djui_cursor_update(void) {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
#if defined(CAPI_SDL2) || defined(CAPI_SDL1) || defined(CAPI_SWITCH)
if (djui_interactable_is_binding()) { return; }
if (sMouseCursor == NULL) { return; }
if (!djui_panel_is_active()) { return; }

View file

@ -1,5 +1,5 @@
#include "djui.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
struct DjuiFpsDisplay {
struct DjuiText *text;

View file

@ -3,7 +3,7 @@
#include "djui.h"
#include "game/ingame_menu.h"
#include "game/segment2.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "gfx_dimensions.h"
#include "djui_gfx.h"

View file

@ -6,7 +6,7 @@
#include "pc/controller/controller_mouse.h"
#include "pc/gfx/gfx_pc.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/utils/misc.h"
#include "djui_gfx.h"

View file

@ -3,10 +3,13 @@
#include "djui.h"
#include "djui_unicode.h"
#include "djui_hud_utils.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "game/segment2.h"
#include "engine/math_util.h"
#include "pc/controller/controller_keyboard.h"
#include "pc/controller/controller_switch.h"
#include "pc/game_main.h"
#include "pc/gfx/gfx_window_manager_api.h"
#define DJUI_INPUTBOX_YOFF (-3)
#define DJUI_INPUTBOX_MAX_BLINK 50
@ -326,23 +329,58 @@ void djui_inputbox_on_key_up(UNUSED struct DjuiBase *base, int scancode) {
}
void djui_inputbox_on_focus_begin(UNUSED struct DjuiBase* base) {
#ifndef __SWITCH__
gDjuiInputHeldShift = 0;
gDjuiInputHeldControl = 0;
gDjuiInputHeldAlt = 0;
wm_api->start_text_input();
#else
struct DjuiInputbox *inputbox = (struct DjuiInputbox *)base;
show_swkb(inputbox->buffer);
#endif
}
void djui_inputbox_on_focus_end(UNUSED struct DjuiBase* base) {
#ifndef __SWITCH__
wm_api->stop_text_input();
#else
hide_swkb();
#endif
}
void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
char* msg = inputbox->buffer;
int msgLen = strlen(msg);
char *msg = inputbox->buffer;
int textLen = strlen(text);
// make sure we're not just printing garbage characters
#ifdef __SWITCH__
// Sanitize
char *t = text;
while (*t != '\0') {
if (*t == '\n') { *t = ' '; }
else if (*t == '\r') { *t = ' '; }
else if (djui_unicode_valid_char(t)) { ; }
t = djui_unicode_next_char(t);
}
// Truncate
if (textLen >= inputbox->bufferSize) {
text[inputbox->bufferSize] = '\0';
textLen = inputbox->bufferSize - 1;
}
snprintf(msg, textLen + 1, "%s", text);
msg[textLen] = '\0';
djui_unicode_cleanup_end(msg);
// Adjust cursor
inputbox->selection[0] = djui_unicode_len(msg);
inputbox->selection[1] = inputbox->selection[0];
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
#else
// Make sure we're not just printing garbage characters
bool containsValidAscii = false;
char* tinput = text;
while (*tinput != '\0') {
@ -355,21 +393,18 @@ void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
if (!containsValidAscii) {
return;
}
// truncate
int msgLen = strlen(msg);
// Truncate
if (textLen + msgLen >= inputbox->bufferSize) {
int space = (inputbox->bufferSize - msgLen);
if (space <= 1) { return; }
text[space - 1] = '\0';
textLen = space - 1;
}
// erase selection
if (inputbox->selection[0] != inputbox->selection[1]) {
djui_inputbox_delete_selection(inputbox);
}
// sanitize
// Sanitize
char *t = text;
while (*t != '\0') {
if (*t == '\n') { *t = ' '; }
@ -378,25 +413,26 @@ void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
t = djui_unicode_next_char(t);
}
// back up current message
// Back up current message
char* sMsg = calloc(inputbox->bufferSize, sizeof(char));
memcpy(sMsg, msg, inputbox->bufferSize);
// insert text
// Insert text
size_t sel = djui_unicode_at_index(inputbox->buffer, inputbox->selection[0]) - inputbox->buffer;
snprintf(&msg[sel], (inputbox->bufferSize - sel), "%s%s", text, &sMsg[sel]);
free(sMsg);
djui_unicode_cleanup_end(msg);
// adjust cursor
// Adjust cursor
inputbox->selection[0] += djui_unicode_len(text);
s32 ulen = djui_unicode_len(msg);
if (inputbox->selection[0] > ulen) { inputbox->selection[0] = ulen; }
inputbox->selection[1] = inputbox->selection[0];
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
#endif
inputbox->imePos = 0;
if (inputbox->imeBuffer != NULL) {
@ -413,14 +449,20 @@ void djui_inputbox_on_text_editing(struct DjuiBase *base, char* text, int cursor
if (*text == '\0') {
inputbox->imeBuffer = NULL;
}
else {
} else {
size_t size = strlen(text);
char* copy = malloc(size + 1);
strcpy(copy,text);
strcpy(copy, text);
inputbox->imeBuffer = copy;
#ifdef __SWITCH__
// Adjust cursor
inputbox->selection[0] = djui_unicode_len(text);
inputbox->selection[1] = inputbox->selection[0];
sCursorBlink = 0;
#endif
}
djui_inputbox_on_change(inputbox);
}
@ -455,6 +497,38 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
selection[0] = fmin(inputbox->selection[0], inputbox->selection[1]);
selection[1] = fmax(inputbox->selection[0], inputbox->selection[1]);
#ifdef __SWITCH__
sCursorBlink = (sCursorBlink + 1) % DJUI_INPUTBOX_MAX_BLINK;
f32 x = 0;
f32 width = 0;
f32 renderX = 0;
if (inputbox->imeBuffer != NULL) {
char *ime = inputbox->imeBuffer;
s32 imeBufferSize = strlen(ime);
for (s32 i = 0; i < imeBufferSize; i++) {
char *dc = inputbox->passwordChar[0] ? inputbox->passwordChar : ime;
if (i < selection[1]) {
x += font->char_width(dc);
} else {
width += font->char_width(dc);
}
ime = djui_unicode_next_char(ime);
}
} else {
char *c = inputbox->buffer;
for (u16 i = 0; i < selection[1]; i++) {
char *dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c;
if (i < selection[0]) {
x += font->char_width(dc);
} else {
width += font->char_width(dc);
}
c = djui_unicode_next_char(c);
}
}
renderX = x;
#else
char* c = inputbox->buffer;
f32 x = 0;
f32 width = 0;
@ -480,6 +554,7 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
ime = djui_unicode_next_char(ime);
}
}
#endif
// render only cursor when there is no selection width
if (selection[0] == selection[1]) {
@ -525,23 +600,39 @@ static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
static void djui_inputbox_keep_selection_in_view(struct DjuiInputbox* inputbox) {
const struct DjuiFont* font = gDjuiFonts[configDjuiThemeFont == 0 ? FONT_NORMAL : FONT_ALIASED];
// calculate where our cursor is
f32 cursorX = inputbox->viewX;
char* c = inputbox->buffer;
// Calculate where our cursor is.
#ifdef __SWITCH__
char *c = inputbox->imeBuffer != NULL ? inputbox->imeBuffer : inputbox->buffer;
#else
char *c = inputbox->buffer;
#endif
f32 selSize = 0;
for (u16 i = 0; i < inputbox->selection[0]; i++) {
if (*c == '\0') { break; }
char* dc = inputbox->passwordChar[0] ? inputbox->passwordChar : c;
cursorX += font->char_width(dc) * font->defaultFontScale;
selSize += font->char_width(dc) * font->defaultFontScale;
c = djui_unicode_next_char(c);
}
f32 cursorX = inputbox->viewX + selSize;
// shift viewing window
// Shift viewing window
#ifdef __SWITCH__
if (selSize > 0 && selSize <= inputbox->base.comp.width) {
inputbox->viewX = 0;
} else if (cursorX > inputbox->base.comp.width) {
inputbox->viewX -= cursorX - inputbox->base.comp.width;
} else if (cursorX < 0) {
inputbox->viewX -= cursorX;
}
#else
if (cursorX > inputbox->base.comp.width) {
inputbox->viewX -= cursorX - inputbox->base.comp.width;
} else if (cursorX < 0) {
inputbox->viewX -= cursorX;
}
#endif
}
static bool djui_inputbox_render(struct DjuiBase* base) {
@ -584,6 +675,33 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
selection[0] = fmin(inputbox->selection[0], inputbox->selection[1]);
selection[1] = fmax(inputbox->selection[0], inputbox->selection[1]);
#ifdef __SWITCH__
// On Nintendo Switch, We need to handle this differently.
// We need to render only the ime or the original text.
// But not both.
f32 drawX = inputbox->viewX;
f32 additionalShift = 0;
bool wasInsideSelection = false;
char *c = inputbox->imeBuffer != NULL ? inputbox->imeBuffer : inputbox->buffer;
s32 bufferSize = inputbox->imeBuffer != NULL ? strlen(c) : inputbox->bufferSize;
for (s32 i = 0; i < bufferSize; i++) {
if (*c == '\0') { break; }
// Deal with seleciton color
if (selection[0] != selection[1]) {
bool insideSelection = (i >= selection[0]) && (i < selection[1]);
if (insideSelection && !wasInsideSelection) {
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
} else if (!insideSelection && wasInsideSelection) {
gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a);
}
wasInsideSelection = insideSelection;
}
djui_inputbox_render_char(inputbox, c, &drawX, &additionalShift);
c = djui_unicode_next_char(c);
}
#else
// render text
char* c = inputbox->buffer;
f32 drawX = inputbox->viewX;
@ -617,6 +735,7 @@ static bool djui_inputbox_render(struct DjuiBase* base) {
djui_inputbox_render_char(inputbox, c, &drawX, &additionalShift);
c = djui_unicode_next_char(c);
}
#endif
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);

View file

@ -28,6 +28,7 @@ struct DjuiBase* gDjuiCursorDownOn = NULL;
struct DjuiBase* gInteractableFocus = NULL;
struct DjuiBase* gInteractableBinding = NULL;
struct DjuiBase* gInteractableMouseDown = NULL;
bool gIsUsingButtonsOnly = false;
bool gInteractableOverridePad = false;
OSContPad gInteractablePad = { 0 };
static OSContPad sLastInteractablePad = { 0 };
@ -193,6 +194,14 @@ bool djui_interactable_is_input_focus(struct DjuiBase* base) {
return gInteractableFocus == base;
}
void djui_interactable_set_buttons_only(bool enabled) {
gIsUsingButtonsOnly = enabled;
}
bool djui_interactable_is_buttons_only(void) {
return gIsUsingButtonsOnly;
}
bool djui_interactable_on_key_down(int scancode) {
if (gInteractableBinding != NULL) {
return true;
@ -311,7 +320,7 @@ void djui_interactable_on_key_up(int scancode) {
return;
}
OSContPad* pad = &gInteractablePad;
OSContPad *pad = &gInteractablePad;
switch (scancode) {
case SCANCODE_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
case SCANCODE_DOWN: if (sKeyboardHoldDirection == PAD_HOLD_DIR_DOWN) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
@ -321,6 +330,50 @@ void djui_interactable_on_key_up(int scancode) {
}
}
bool djui_interactable_on_button_down(u8 code) {
if (gInteractableBinding != NULL) {
return true;
}
bool keyFocused = (gInteractableFocus != NULL) && (gInteractableFocus->interactable != NULL);
if (keyFocused) {
sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
sKeyboardButtons = 0;
return true;
}
if (code == DJUI_BTN_SELECT && djui_panel_is_active()) {
// Pressed select on controller.
djui_panel_back();
return true;
}
return false;
}
void djui_interactable_on_button_up(u8 code) {
OSContPad *pad = &gInteractablePad;
switch (code) {
case DJUI_BTN_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
case DJUI_BTN_DOWN: if (sKeyboardHoldDirection == PAD_HOLD_DIR_DOWN) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
case DJUI_BTN_LEFT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_LEFT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
case DJUI_BTN_RIGHT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_RIGHT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
}
}
void djui_interactable_on_button_held(u8 code) {
OSContPad *pad = &gInteractablePad;
if (gDjuiChatBoxFocus || djui_panel_is_active()) {
switch (code) {
case DJUI_BTN_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; break;
case DJUI_BTN_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; break;
case DJUI_BTN_LEFT: sKeyboardHoldDirection = PAD_HOLD_DIR_LEFT; break;
case DJUI_BTN_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; break;
}
}
}
void djui_interactable_on_text_input(char* text) {
if (gInteractableFocus == NULL) { return; }
if (gInteractableFocus->interactable == NULL) { return; }
@ -369,7 +422,7 @@ void djui_interactable_update_pad(void) {
case PAD_HOLD_DIR_DOWN: pad->stick_x = 0; pad->stick_y = 64; break;
case PAD_HOLD_DIR_LEFT: pad->stick_x = -64; pad->stick_y = 0; break;
case PAD_HOLD_DIR_RIGHT: pad->stick_x = 64; pad->stick_y = 0; break;
default: break;
default: pad->stick_x = 0; pad->stick_y = 0; break;
}
} else if (pad->stick_x == 0 && pad->stick_y == 0) {
padHoldDirection = PAD_HOLD_DIR_NONE;
@ -427,7 +480,7 @@ void djui_interactable_update(void) {
if (!gDjuiChatBoxFocus) {
djui_interactable_set_input_focus(NULL);
}
} else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
} else if (!gIsUsingButtonsOnly && (padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
// pressed main face button
if (!gDjuiChatBoxFocus) {
djui_interactable_set_input_focus(NULL);
@ -436,7 +489,7 @@ void djui_interactable_update(void) {
djui_interactable_on_focus(gInteractableFocus);
}
} else if ((padButtons & PAD_BUTTON_B) && !(sLastInteractablePad.button & PAD_BUTTON_B)) {
// pressed back button on controller
// pressed back button on controller
djui_panel_back();
sLastInteractablePad = gInteractablePad;
@ -449,7 +502,7 @@ void djui_interactable_update(void) {
if (gInteractableBinding != NULL) {
djui_interactable_on_bind(gInteractableBinding);
} else if ((padButtons & PAD_BUTTON_A) || (mouseButtons & MOUSE_BUTTON_1)) {
} else if (!(gIsUsingButtonsOnly && gInteractableFocus) && ((padButtons & PAD_BUTTON_A) || (mouseButtons & MOUSE_BUTTON_1))) {
// cursor down events
if (gDjuiHovered != NULL) {
gInteractableMouseDown = gDjuiHovered;

View file

@ -23,6 +23,30 @@
#define SCANCODE_LSHIFT 42
#define SCANCODE_RSHIFT 54
#define DJUI_BTN_BAD 0
#define DJUI_BTN_A 1
#define DJUI_BTN_B 2
#define DJUI_BTN_X 3
#define DJUI_BTN_Y 4
#define DJUI_BTN_L 5
#define DJUI_BTN_R 6
#define DJUI_BTN_ZL 7
#define DJUI_BTN_ZR 8
#define DJUI_BTN_PADUP 9
#define DJUI_BTN_PADLEFT 10
#define DJUI_BTN_PADDOWN 11
#define DJUI_BTN_PADRIGHT 12
#define DJUI_BTN_UP 13
#define DJUI_BTN_LEFT 14
#define DJUI_BTN_DOWN 15
#define DJUI_BTN_RIGHT 16
#define DJUI_BTN_CUP 17
#define DJUI_BTN_CLEFT 18
#define DJUI_BTN_CDOWN 19
#define DJUI_BTN_CRIGHT 20
#define DJUI_BTN_START 21
#define DJUI_BTN_SELECT 22
struct DjuiInteractable {
bool enabled;
void (*update_style)(struct DjuiBase*);
@ -59,8 +83,13 @@ bool djui_interactable_is_binding(void);
void djui_interactable_set_binding(struct DjuiBase* base);
void djui_interactable_set_input_focus(struct DjuiBase* base);
bool djui_interactable_is_input_focus(struct DjuiBase* base);
void djui_interactable_set_buttons_only(bool enabled);
bool djui_interactable_is_buttons_only(void);
bool djui_interactable_on_key_down(int scancode);
void djui_interactable_on_key_up(int scancode);
bool djui_interactable_on_button_down(u8 code);
void djui_interactable_on_button_up(u8 code);
void djui_interactable_on_button_held(u8 code);
void djui_interactable_on_text_input(char *text);
void djui_interactable_on_text_editing(char* text, int cursorPos);
void djui_interactable_on_scroll(float x, float y);

View file

@ -2,6 +2,7 @@
#include <string.h>
#include "djui.h"
#include "djui_lobby_entry.h"
#include "pc/string_utils.h"
#define VK_ESCAPE 1

View file

@ -1,7 +1,7 @@
#include "djui_lua_profiler.h"
#include "djui.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/mods/mod.h"
#include "pc/mods/mods.h"

View file

@ -132,6 +132,11 @@ void djui_panel_back(void) {
// play a sound
play_sound(SOUND_MENU_CLICK_FILE_SELECT, NULL);
#if defined(CAPI_SWITCH)
// Reselect the default element.
djui_cursor_input_controlled_center(sPanelList->defaultElementBase);
#endif
gDjuiPanelJoinMessageVisible = false;
}

View file

@ -8,6 +8,7 @@
#include "pc/controller/controller_api.h"
#include "pc/controller/controller_sdl.h"
#include "pc/controller/controller_system.h"
#include "pc/string_utils.h"
void djui_panel_controls_value_change(UNUSED struct DjuiBase* caller) {
controller_reconfigure();
@ -34,14 +35,19 @@ void djui_panel_controls_create(struct DjuiBase* caller) {
struct DjuiThreePanel* panel = djui_panel_menu_create(DLANG(CONTROLS, CONTROLS), false);
struct DjuiBase* body = djui_three_panel_get_body(panel);
{
djui_button_create(body, DLANG(CONTROLS, N64_BINDS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_n64_create);
djui_button_create(body, DLANG(CONTROLS, EXTRA_BINDS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_extra_create);
djui_button_create(body, DLANG(CONTROLS, ANALOG_STICK_OPTIONS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_analog_stick_options_create);
djui_checkbox_create(body, DLANG(CONTROLS, BACKGROUND_GAMEPAD), &configBackgroundGamepad, NULL);
#ifndef HANDHELD
djui_checkbox_create(body, DLANG(CONTROLS, DISABLE_GAMEPADS), &configDisableGamepads, NULL);
struct DjuiButton *binds = djui_button_create(body, DLANG(CONTROLS, N64_BINDS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_n64_create);
struct DjuiButton *extra_binds = djui_button_create(body, DLANG(CONTROLS, EXTRA_BINDS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_extra_create);
struct DjuiButton *analog_stick_controls = djui_button_create(body, DLANG(CONTROLS, ANALOG_STICK_OPTIONS), DJUI_BUTTON_STYLE_NORMAL, djui_panel_controls_analog_stick_options_create);
struct DjuiCheckbox *background_gamepad = djui_checkbox_create(body, DLANG(CONTROLS, BACKGROUND_GAMEPAD), &configBackgroundGamepad, NULL);
struct DjuiCheckbox *disable_gamepads = djui_checkbox_create(body, DLANG(CONTROLS, DISABLE_GAMEPADS), &configDisableGamepads, NULL);
struct DjuiCheckbox *chat_keybinds = djui_checkbox_create(body, DLANG(MISC, USE_STANDARD_KEY_BINDINGS_CHAT), &configUseStandardKeyBindingsChat, NULL);
#ifdef __SWITCH__
djui_base_set_enabled(&binds->base, false);
djui_base_set_enabled(&extra_binds->base, false);
djui_base_set_enabled(&background_gamepad->base, false);
djui_base_set_enabled(&chat_keybinds->base, false);
#endif
djui_checkbox_create(body, DLANG(MISC, USE_STANDARD_KEY_BINDINGS_CHAT), &configUseStandardKeyBindingsChat, NULL);
#ifdef HAVE_SDL2
controller_update_gamepad_choices();

View file

@ -2,7 +2,7 @@
#include "djui_panel.h"
#include "djui_panel_menu.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
@ -23,6 +23,16 @@ static void djui_panel_display_uncapped_change(UNUSED struct DjuiBase* caller) {
djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate)));
}
#if defined(__SWITCH__)
static u32 sFramerateSelection = 0;
static void djui_panel_display_frame_limit_change(UNUSED struct DjuiBase* caller) {
switch (sFramerateSelection) {
case 1: configFrameLimit = 60; break;
default: configFrameLimit = 30; break;
}
}
#else
static void djui_panel_display_frame_limit_text_change(struct DjuiBase* caller) {
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
s32 frameLimit = atoi(inputbox1->buffer);
@ -34,6 +44,7 @@ static void djui_panel_display_frame_limit_text_change(struct DjuiBase* caller)
}
djui_base_set_enabled(&sInterpolationSelectionBox->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate)));
}
#endif
static void djui_panel_display_msaa_change(UNUSED struct DjuiBase* caller) {
switch (sMsaaSelection) {
@ -60,16 +71,22 @@ void djui_panel_display_create(struct DjuiBase* caller) {
if (sMsaaOriginal == MSAA_ORIGINAL_UNSET) { sMsaaOriginal = configWindow.msaa; }
{
djui_checkbox_create(body, DLANG(DISPLAY, FULLSCREEN), &configWindow.fullscreen, djui_panel_display_apply);
djui_checkbox_create(body, DLANG(DISPLAY, FORCE_4BY3), &configForce4By3, djui_panel_display_apply);
djui_checkbox_create(body, DLANG(DISPLAY, SHOW_FPS), &configShowFPS, NULL);
djui_checkbox_create(body, DLANG(DISPLAY, FORCE_4BY3), &configForce4By3, djui_panel_display_apply);
#if !defined(__SWITCH__)
djui_checkbox_create(body, DLANG(DISPLAY, FULLSCREEN), &configWindow.fullscreen, djui_panel_display_apply);
djui_checkbox_create(body, DLANG(DISPLAY, VSYNC), &configWindow.vsync, djui_panel_display_apply);
djui_checkbox_create(body, DLANG(DISPLAY, UNCAPPED_FRAMERATE), &configUncappedFramerate, djui_panel_display_uncapped_change);
#endif
struct DjuiRect* rect1 = djui_rect_container_create(body, 32);
{
if (configFrameLimit < 30) { configFrameLimit = 30; }
if (configFrameLimit > 3000) { configFrameLimit = 3000; }
#if defined(__SWITCH__)
char *framerateChoices[3] = { "30", "60", NULL };
struct DjuiSelectionbox *framerate = djui_selectionbox_create(body, DLANG(DISPLAY, FRAME_LIMIT), framerateChoices, 2, &sFramerateSelection, djui_panel_display_frame_limit_change);
#else
struct DjuiText* text1 = djui_text_create(&rect1->base, DLANG(DISPLAY, FRAME_LIMIT));
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_color(&text1->base, 220, 220, 220, 255);
@ -87,6 +104,7 @@ void djui_panel_display_create(struct DjuiBase* caller) {
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_display_frame_limit_text_change);
djui_base_set_enabled(&inputbox1->base, !configUncappedFramerate);
sFrameLimitInput = inputbox1;
#endif
}
char* interpChoices[2] = { DLANG(DISPLAY, FAST), DLANG(DISPLAY, ACCURATE) };
@ -94,7 +112,7 @@ void djui_panel_display_create(struct DjuiBase* caller) {
djui_base_set_enabled(&selectionbox1->base, (configFrameLimit > 30 || (configFrameLimit <= 30 && configUncappedFramerate)));
sInterpolationSelectionBox = selectionbox1;
char* filterChoices[3] = { DLANG(DISPLAY, NEAREST), DLANG(DISPLAY, LINEAR), DLANG(DISPLAY, TRIPOINT) };
char* filterChoices[4] = { DLANG(DISPLAY, NEAREST), DLANG(DISPLAY, LINEAR), DLANG(DISPLAY, TRIPOINT), NULL };
djui_selectionbox_create(body, DLANG(DISPLAY, FILTERING), filterChoices, 3, &configFiltering, NULL);
int maxMsaa = wm_api->get_max_msaa();
@ -110,7 +128,7 @@ void djui_panel_display_create(struct DjuiBase* caller) {
else if (maxMsaa >= 8) { choiceCount = 4; }
else if (maxMsaa >= 4) { choiceCount = 3; }
char* msaaChoices[5] = { DLANG(DISPLAY, OFF), "2x", "4x", "8x", "16x" };
char* msaaChoices[6] = { DLANG(DISPLAY, OFF), "2x", "4x", "8x", "16x", NULL };
msaa = djui_selectionbox_create(body, DLANG(DISPLAY, ANTIALIASING), msaaChoices, choiceCount, &sMsaaSelection, djui_panel_display_msaa_change);
}

View file

@ -12,6 +12,7 @@
#include "pc/configfile.h"
#include "pc/debuglog.h"
#include "macros.h"
#include "pc/string_utils.h"
#ifdef COOPNET

View file

@ -62,6 +62,8 @@ static void djui_panel_language_destroy(UNUSED struct DjuiBase* caller) {
djui_panel_playerlist_create(NULL);
djui_panel_modlist_create(NULL);
djui_panel_main_create(NULL);
djui_panel_options_create(NULL);
djui_panel_misc_create(NULL);
} else if (gDjuiInMainMenu) {
djui_panel_shutdown();
gDjuiInMainMenu = true;

View file

@ -6,7 +6,7 @@
#include "djui_panel_menu.h"
#include "djui_panel_confirm.h"
#include "pc/controller/controller_sdl.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/update_checker.h"
extern ALIGNED8 u8 texture_coopdx_logo[];

View file

@ -4,6 +4,7 @@
#include "djui_panel_menu.h"
#include "pc/lua/smlua_hooks.h"
#include "pc/mods/mods.h"
#include "pc/string_utils.h"
static char* to_uppercase(char* str) {
char* buffer = strdup(str);

View file

@ -10,7 +10,7 @@
#include "djui_panel_dynos.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
static void djui_panel_options_back(struct DjuiBase* caller) {
configfile_save(configfile_name());

View file

@ -8,7 +8,7 @@
#include "djui_panel_menu.h"
#include "djui_panel_confirm.h"
#include "djui_panel_mod_menu.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/network/network.h"
#include "pc/lua/smlua_hooks.h"
#include "game/object_helpers.h"

View file

@ -1,5 +1,5 @@
#include "djui.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/gfx/gfx_window_manager_api.h"
static bool djui_root_render(struct DjuiBase* base) {

View file

@ -53,8 +53,9 @@ bool fs_init(const char *writepath) {
#endif
// we shall not progress any further if the path is inaccessible
if (('\0' == fs_writepath[0]) || !fs_sys_dir_exists(fs_writepath)) {
sys_fatal("Could not access the User Preferences directory.");
if (('\0' == fs_writepath[0]) || (!fs_sys_dir_exists(fs_writepath) && !fs_sys_mkdir(fs_writepath))) {
printf("FS: Could not access the User Preferences directory.");
return false;
}
fs_mount(fs_writepath);

421
src/pc/game_main.c Normal file
View file

@ -0,0 +1,421 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <unistd.h>
#include "sm64.h"
#include "pc/lua/smlua.h"
#include "pc/lua/utils/smlua_text_utils.h"
#include "game/memory.h"
#include "audio/data.h"
#include "audio/external.h"
#include "network/network.h"
#include "lua/smlua.h"
#include "audio/audio_api.h"
#include "audio/audio_sdl.h"
#include "audio/audio_null.h"
#include "rom_assets.h"
#include "rom_checker.h"
#include "game_main.h"
#ifdef __SWITCH__
#include "nx_main.h"
#else
#include "pc_main.h"
#endif
#include "loading.h"
#include "configfile.h"
#include "thread.h"
#include "controller/controller_api.h"
#include "controller/controller_keyboard.h"
#include "fs/fs.h"
#include "game/display.h" // for gGlobalTimer
#include "game/game_init.h"
#include "game/main.h"
#include "game/rumble_init.h"
#include "pc/lua/utils/smlua_audio_utils.h"
#include "pc/network/version.h"
#include "pc/network/socket/socket.h"
#include "pc/network/network_player.h"
#include "pc/update_checker.h"
#include "pc/djui/djui.h"
#include "pc/djui/djui_unicode.h"
#include "pc/djui/djui_panel.h"
#include "pc/djui/djui_panel_modlist.h"
#include "pc/djui/djui_ctx_display.h"
#include "pc/djui/djui_fps_display.h"
#include "pc/djui/djui_lua_profiler.h"
#include "pc/debuglog.h"
#include "pc/gfx/gfx_dummy.h"
#include "pc/utils/misc.h"
#include "pc/mods/mods.h"
#include "debug_context.h"
#include "menu/intro_geo.h"
#include "gfx_dimensions.h"
#include "game/segment2.h"
#ifndef __SWITCH__
#include "pc/mumble/mumble.h"
#endif
extern Vp D_8032CF00;
OSMesg D_80339BEC;
OSMesgQueue gSIEventMesgQueue;
s8 gResetTimer;
s8 D_8032C648;
s8 gDebugLevelSelect;
s8 gShowProfiler;
s8 gShowDebugText;
s32 gRumblePakPfs;
u32 gNumVblanks = 0;
u8 gRenderingInterpolated = 0;
f32 gRenderingDelta = 0;
#define FRAMERATE 30
static const f64 sFrameTime = (1.0 / ((double)FRAMERATE));
static f64 sFpsTimeLast = 0;
static f64 sFrameTimeStart = 0;
static u32 sDrawnFrames = 0;
bool gGameInited = false;
bool gGfxInited = false;
f32 gMasterVolume = 100.0f;
u8 gLuaVolumeMaster = 127;
u8 gLuaVolumeLevel = 127;
u8 gLuaVolumeSfx = 127;
u8 gLuaVolumeEnv = 127;
extern struct AudioAPI *audio_api;
extern struct GfxWindowManagerAPI *wm_api;
extern void gfx_run(Gfx *commands);
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(UNUSED struct SPTask *spTask) {}
void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) {}
void send_display_list(struct SPTask *spTask) {
if (!gGameInited) { return; }
gfx_run((Gfx *)spTask->task.t.data_ptr);
}
#ifdef VERSION_EU
#define SAMPLES_HIGH 560 // gAudioBufferParameters.maxAiBufferLength
#define SAMPLES_LOW 528 // gAudioBufferParameters.minAiBufferLength
#else
#define SAMPLES_HIGH 544
#define SAMPLES_LOW 528
#endif
extern void patch_mtx_before(void);
extern void patch_screen_transition_before(void);
extern void patch_title_screen_before(void);
extern void patch_dialog_before(void);
extern void patch_hud_before(void);
extern void patch_paintings_before(void);
extern void patch_bubble_particles_before(void);
extern void patch_snow_particles_before(void);
extern void patch_djui_before(void);
extern void patch_djui_hud_before(void);
extern void patch_scroll_targets_before(void);
extern void patch_mtx_interpolated(f32 delta);
extern void patch_screen_transition_interpolated(f32 delta);
extern void patch_title_screen_interpolated(f32 delta);
extern void patch_dialog_interpolated(f32 delta);
extern void patch_hud_interpolated(f32 delta);
extern void patch_paintings_interpolated(f32 delta);
extern void patch_bubble_particles_interpolated(f32 delta);
extern void patch_snow_particles_interpolated(f32 delta);
extern void patch_djui_interpolated(f32 delta);
extern void patch_djui_hud(f32 delta);
extern void patch_scroll_targets_interpolated(f32 delta);
static void patch_interpolations_before(void) {
patch_mtx_before();
patch_screen_transition_before();
patch_title_screen_before();
patch_dialog_before();
patch_hud_before();
patch_paintings_before();
patch_bubble_particles_before();
patch_snow_particles_before();
patch_djui_before();
patch_djui_hud_before();
patch_scroll_targets_before();
}
static inline void patch_interpolations(f32 delta) {
patch_mtx_interpolated(delta);
patch_screen_transition_interpolated(delta);
patch_title_screen_interpolated(delta);
patch_dialog_interpolated(delta);
patch_hud_interpolated(delta);
patch_paintings_interpolated(delta);
patch_bubble_particles_interpolated(delta);
patch_snow_particles_interpolated(delta);
patch_djui_interpolated(delta);
patch_djui_hud(delta);
patch_scroll_targets_interpolated(delta);
}
static void compute_fps(f64 curTime) {
u32 fps = round((f64) sDrawnFrames / MAX(0.001, curTime - sFpsTimeLast));
djui_fps_display_update(fps);
sFpsTimeLast = curTime;
sDrawnFrames = 0;
}
static s32 get_num_frames_to_draw(f64 t) {
if (configFrameLimit % FRAMERATE == 0) {
return configFrameLimit / FRAMERATE;
}
s64 numFramesCurr = (s64) (t * (f64) configFrameLimit);
s64 numFramesNext = (s64) ((t + sFrameTime) * (f64) configFrameLimit);
return (s32) MAX(1, numFramesNext - numFramesCurr);
}
void produce_interpolation_frames_and_delay(void) {
bool is30Fps = (!configUncappedFramerate && configFrameLimit == FRAMERATE);
gRenderingInterpolated = true;
f64 curTime = clock_elapsed_f64();
f64 targetTime = sFrameTimeStart + sFrameTime;
s32 numFramesToDraw = get_num_frames_to_draw(sFrameTimeStart);
f64 loopStartTime = curTime;
f64 expectedTime = 0;
// interpolate and render
// make sure to draw at least one frame to prevent the game from freezing completely
// (including inputs and window events) if the game update duration is greater than 33ms
do {
f32 delta = (
is30Fps ?
1.0f :
MIN(MAX((curTime - sFrameTimeStart) / sFrameTime, 0.f), 1.f)
);
gRenderingDelta = delta;
gfx_start_frame();
if (!gSkipInterpolationTitleScreen) { patch_interpolations(delta); }
send_display_list(gGfxSPTask);
gfx_end_frame();
sDrawnFrames++;
if (!is30Fps && configUncappedFramerate) { continue; }
// delay if our framerate is capped
f64 now = clock_elapsed_f64();
f64 elapsedTime = now - loopStartTime;
expectedTime += (targetTime - curTime) / (f64) numFramesToDraw;
f64 delay = (expectedTime - elapsedTime) * 1000.0;
if (delay > 0.0) {
wm_api->delay((u32)delay);
}
numFramesToDraw--;
} while ((curTime = clock_elapsed_f64()) < targetTime && numFramesToDraw > 0);
// compute and update the frame rate every second
if ((curTime = clock_elapsed_f64()) >= sFpsTimeLast + 1.0) {
compute_fps(curTime);
}
// advance frame start time
if (curTime > sFrameTimeStart + 2 * sFrameTime) {
sFrameTimeStart = curTime;
} else {
sFrameTimeStart += sFrameTime;
}
gRenderingInterpolated = false;
}
void produce_one_frame(void) {
CTX_EXTENT(CTX_NETWORK, network_update);
CTX_EXTENT(CTX_INTERP, patch_interpolations_before);
CTX_EXTENT(CTX_GAME_LOOP, game_loop_one_iteration);
CTX_EXTENT(CTX_SMLUA, smlua_update);
// If we aren't threaded
if (gAudioThread.state == INVALID) {
CTX_EXTENT(CTX_AUDIO, buffer_audio);
}
CTX_EXTENT(CTX_RENDER, produce_interpolation_frames_and_delay);
}
// used for rendering 2D scenes fullscreen like the loading or crash screens
void produce_one_dummy_frame(void (*callback)(), u8 clearColorR, u8 clearColorG, u8 clearColorB) {
// start frame
gfx_start_frame();
config_gfx_pool();
init_render_image();
create_dl_ortho_matrix();
djui_gfx_displaylist_begin();
// fix scaling issues
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&D_8032CF00));
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, BORDER_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT - BORDER_HEIGHT);
// clear screen
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.f, 0.f);
create_dl_scale_matrix(MENU_MTX_NOPUSH, (GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT) / 130.f, 3.f, 1.f);
gDPSetEnvColor(gDisplayListHead++, clearColorR, clearColorG, clearColorB, 0xFF);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
// call the callback
callback();
// render frame
djui_gfx_displaylist_end();
end_master_display_list();
alloc_display_list(0);
gfx_run((Gfx*) gGfxSPTask->task.t.data_ptr); // send_display_list
display_and_vsync();
gfx_end_frame();
}
// It's just better to have this off the stack, Because the size isn't small.
// It also may help static analysis and bug catching.
static s16 sAudioBuffer[SAMPLES_HIGH * 2 * 2] = { 0 };
void buffer_audio(void) {
bool shouldMute = (configMuteFocusLoss && !wm_api->has_focus()) || (gMasterVolume == 0);
if (!shouldMute) {
set_sequence_player_volume(SEQ_PLAYER_LEVEL, (f32)configMusicVolume / 127.0f * (f32)gLuaVolumeLevel / 127.0f);
set_sequence_player_volume(SEQ_PLAYER_SFX, (f32)configSfxVolume / 127.0f * (f32)gLuaVolumeSfx / 127.0f);
set_sequence_player_volume(SEQ_PLAYER_ENV, (f32)configEnvVolume / 127.0f * (f32)gLuaVolumeEnv / 127.0f);
}
int samplesLeft = audio_api->buffered();
u32 numAudioSamples = samplesLeft < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
for (s32 i = 0; i < 2; i++) {
create_next_audio_buffer(sAudioBuffer + i * (numAudioSamples * 2), numAudioSamples);
}
if (!shouldMute) {
for (u16 i = 0; i < ARRAY_COUNT(sAudioBuffer); i++) {
sAudioBuffer[i] *= gMasterVolume;
}
audio_api->play((u8 *)sAudioBuffer, 2 * numAudioSamples * 4);
}
}
void *audio_thread(UNUSED void *arg) {
// As long as we have an audio api and that we're threaded, Loop.
while (audio_api) {
f64 curTime = clock_elapsed_f64();
// Buffer the audio.
lock_mutex(&gAudioThread);
buffer_audio();
unlock_mutex(&gAudioThread);
// Delay till the next frame for smooth audio at the correct speed.
// delay
f64 targetDelta = 1.0 / (f64)FRAMERATE;
f64 now = clock_elapsed_f64();
f64 actualDelta = now - curTime;
if (actualDelta < targetDelta) {
f64 delay = ((targetDelta - actualDelta) * 1000.0);
wm_api->delay((u32)delay);
}
}
// Exit the thread if our loop breaks.
exit_thread();
return NULL;
}
void audio_shutdown(void) {
audio_custom_shutdown();
if (audio_api) {
if (audio_api->shutdown) audio_api->shutdown();
audio_api = NULL;
}
}
void game_deinit(void) {
if (gGameInited) { configfile_save(configfile_name()); }
controller_shutdown();
audio_custom_shutdown();
audio_shutdown();
network_shutdown(true, true, false, false);
smlua_text_utils_shutdown();
smlua_shutdown();
smlua_audio_custom_deinit();
mods_shutdown();
djui_shutdown();
gfx_shutdown();
#ifdef __SWITCH__
nx_cleanup();
#endif
gGameInited = false;
}
void game_exit(void) {
LOG_INFO("exiting cleanly");
game_deinit();
exit(0);
}
void* main_game_init(UNUSED void* dummy) {
// load language
if (!djui_language_init(configLanguage)) { snprintf(configLanguage, MAX_CONFIG_STRING, "%s", ""); }
LOADING_SCREEN_MUTEX(loading_screen_set_segment_text("Loading"));
dynos_gfx_init();
enable_queued_dynos_packs();
sync_objects_init_system();
if (gCLIOpts.network != NT_SERVER && !gCLIOpts.skipUpdateCheck) {
check_for_updates();
}
LOADING_SCREEN_MUTEX(loading_screen_set_segment_text("Loading ROM Assets"));
rom_assets_load();
smlua_text_utils_init();
mods_init();
enable_queued_mods();
LOADING_SCREEN_MUTEX(
gCurrLoadingSegment.percentage = 0;
loading_screen_set_segment_text("Starting Game");
);
audio_init();
sound_init();
network_player_init();
#ifndef __SWITCH__
mumble_init();
#endif
gGameInited = true;
}

46
src/pc/game_main.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef _GAME_MAIN_H
#define _GAME_MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
#include "sm64.h"
#include "audio/audio_api.h"
#include "gfx/gfx_dummy.h"
#define AT_STARTUP __attribute__((constructor))
#ifdef GIT_HASH
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "%s %s, [%s]", WINDOW_NAME, get_version(), GIT_HASH); title; })
#else
#define TITLE ({ char title[96] = ""; snprintf(title, 96, "%s %s", WINDOW_NAME, get_version()); title; })
#endif
extern bool gGameInited;
extern bool gGfxInited;
extern f32 gMasterVolume;
extern u8 gLuaVolumeMaster;
extern u8 gLuaVolumeLevel;
extern u8 gLuaVolumeSfx;
extern u8 gLuaVolumeEnv;
void buffer_audio(void);
void produce_one_frame(void);
void produce_one_dummy_frame(void (*callback)(), u8 clearColorR, u8 clearColorG, u8 clearColorB);
void game_deinit(void);
void game_exit(void);
void *main_game_init(UNUSED void *dummy);
extern struct AudioAPI *audio_api;
extern struct GfxWindowManagerAPI *wm_api;
#ifdef __cplusplus
}
#endif
#endif // _GAME_MAIN_H

View file

@ -14,7 +14,7 @@
#include "gfx_window_manager_api.h"
#include "gfx_rendering_api.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/utils/misc.h"
#include "pc/debuglog.h"
@ -29,7 +29,7 @@ static void sleep_ms(int milliseconds) { // cross-platform sleep function
// from StackOverflow user Bernardo Ramos: https://stackoverflow.com/a/28827188
#ifdef WIN32
Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
#elif _POSIX_C_SOURCE >= 199309L || defined(__SWITCH__)
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;

View file

@ -31,7 +31,7 @@ extern "C" {
#include "pc/configfile.h"
}
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "gfx_window_manager_api.h"
#include "gfx_rendering_api.h"

View file

@ -3,12 +3,16 @@
#include <stdint.h>
#include <stdbool.h>
#ifdef __SWITCH__
#include <switch.h>
#endif
#ifndef _LANGUAGE_C
# define _LANGUAGE_C
#endif
#include <PR/gbi.h>
#ifdef __MINGW32__
#if defined(__MINGW32__) && !defined(__SWITCH__)
# define FOR_WINDOWS 1
#else
# define FOR_WINDOWS 0
@ -23,13 +27,16 @@
#ifdef WAPI_SDL2
# include <SDL2/SDL.h>
# ifdef USE_GLES
# if defined(USE_GLES)
# define USE_FRAMEBUFFER 0
# include <SDL2/SDL_opengles2.h>
# else
# define USE_FRAMEBUFFER 0
# include <SDL2/SDL_opengl.h>
# endif
#elif defined(WAPI_SDL1)
# include <SDL/SDL.h>
# define USE_FRAMEBUFFER 0
# ifndef GLEW_STATIC
# include <SDL/SDL_opengl.h>
# endif
@ -41,8 +48,37 @@
#include "gfx_rendering_api.h"
#include "gfx_pc.h"
#define FRAMEBUFFER_WIDTH 320
#define FRAMEBUFFER_HEIGHT 240
#define TEX_CACHE_STEP 512
static const char *rt_vertex_shader =
#ifdef USE_GLES
"#version 100\n"
#else
"#version 120\n"
#endif
"attribute vec2 a_position;\n"
"attribute vec2 a_uv;\n"
"varying vec2 v_uv;\n"
"void main() {\n"
" gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);\n"
" v_uv = a_uv;\n"
"}\n";
static const char *rt_fragment_shader =
#ifdef USE_GLES
"#version 100\n"
"precision mediump float;\n"
#else
"#version 120\n"
#endif
"varying vec2 v_uv;\n"
"uniform sampler2D u_texture;"
"void main() {\n"
" gl_FragColor = vec4(texture2D(u_texture, v_uv).rgb, 1);\n"
"}\n";
struct ShaderProgram {
uint64_t hash;
GLuint opengl_program_id;
@ -63,7 +99,30 @@ struct GLTexture {
bool filter;
};
struct RenderTarget {
GLuint framebuffer_id;
GLuint color_texture_id;
GLuint depth_renderbuffer_id;
uint32_t width;
uint32_t height;
};
static struct {
int32_t viewport_x, viewport_y, viewport_width, viewport_height;
int32_t scissor_x, scissor_y, scissor_width, scissor_height;
int8_t depth_test, depth_mask;
int8_t zmode_decal;
uint8_t active_texture;
GLuint bound_framebuffer;
} gl_state = { 0 };
static struct RenderTarget main_rt;
static struct RenderTarget framebuffer_rt;
static struct ShaderProgram shader_program_pool[CC_MAX_SHADERS];
static struct ShaderProgram *current_shader_program = NULL;
static uint8_t shader_program_pool_size = 0;
static uint8_t shader_program_pool_index = 0;
static GLuint opengl_vbo;
@ -73,12 +132,155 @@ static int tex_cache_size = 0;
static int num_textures = 0;
static struct GLTexture *tex_cache = NULL;
static struct ShaderProgram *opengl_prg = NULL;
static struct ShaderProgram rt_shader_program;
static struct GLTexture *opengl_tex[2];
static int opengl_curtex = 0;
static uint32_t current_width;
static uint32_t current_height;
static int8_t current_depth_test, current_depth_mask;
static int8_t current_zmode_decal;
static int32_t current_viewport_x, current_viewport_y, current_viewport_width, current_viewport_height;
static int32_t current_scissor_x, current_scissor_y, current_scissor_width, current_scissor_height;
static uint32_t frame_count;
static void gfx_opengl_set_depth_test(bool depth_test);
static void gfx_opengl_set_depth_mask(bool z_upd);
static void gfx_opengl_set_zmode_decal(bool zmode_decal);
static void gfx_opengl_set_viewport(int32_t x, int32_t y, int32_t width, int32_t height);
static void gfx_opengl_set_scissor(int32_t x, int32_t y, int32_t width, int32_t height);
static void gfx_opengl_set_active_texture(uint8_t active_texture) {
if (gl_state.active_texture == active_texture) {
return;
}
gl_state.active_texture = active_texture;
glActiveTexture(GL_TEXTURE0 + active_texture);
}
static void gfx_opengl_set_vertex_buffer(float buffer[], size_t buffer_length) {
glBufferData(GL_ARRAY_BUFFER, buffer_length, buffer, GL_STREAM_DRAW);
}
static void gfx_opengl_bind_render_target(const struct RenderTarget *render_target) {
GLuint id = render_target == NULL ? 0 : render_target->framebuffer_id;
if (gl_state.bound_framebuffer != id) {
gl_state.bound_framebuffer = id;
glBindFramebuffer(GL_FRAMEBUFFER, id);
}
}
static void gfx_opengl_create_render_target(uint32_t width, uint32_t height, bool is_resizing, bool has_depth_buffer, struct RenderTarget *render_target) {
// Create color texture and buffers
if (!is_resizing) {
glGenTextures(1, &render_target->color_texture_id);
if (has_depth_buffer) {
glGenRenderbuffers(1, &render_target->depth_renderbuffer_id);
}
glGenFramebuffers(1, &render_target->framebuffer_id);
}
// Configure color texture
glBindTexture(GL_TEXTURE_2D, render_target->color_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Configure the depth buffer
if (has_depth_buffer) {
glBindRenderbuffer(GL_RENDERBUFFER, render_target->depth_renderbuffer_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
}
// Bind color and depth to the framebuffer
if (!is_resizing) {
gfx_opengl_bind_render_target(render_target);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_target->color_texture_id, 0);
if (has_depth_buffer) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_target->depth_renderbuffer_id);
}
}
render_target->width = width;
render_target->height = height;
}
// function only used when USE_FRAMEBUFFER is defined
static void gfx_opengl_draw_render_target(const struct RenderTarget *dst_render_target, const struct RenderTarget *src_render_target, bool clear_before_drawing) {
// Set render target
uint32_t dst_width, dst_height;
gfx_opengl_bind_render_target(dst_render_target);
if (dst_render_target == NULL) {
dst_width = current_width;
dst_height = current_height;
} else {
dst_width = dst_render_target->width;
dst_height = dst_render_target->height;
}
// Set some states and clear after that
gfx_opengl_set_depth_test(false);
gfx_opengl_set_depth_mask(false);
gfx_opengl_set_zmode_decal(false);
gfx_opengl_set_viewport(0, 0, dst_width, dst_height);
gfx_opengl_set_scissor(0, 0, dst_width, dst_height);
if (clear_before_drawing) {
glClear(GL_COLOR_BUFFER_BIT);
}
// Set color texture
gfx_opengl_set_active_texture(0);
glBindTexture(GL_TEXTURE_2D, src_render_target->color_texture_id);
// Set vertex buffer data
float dst_aspect = (float) dst_width / (float) dst_height;
float src_aspect = (float) src_render_target->width / (float) src_render_target->height;
float w = src_aspect / dst_aspect;
float buf_vbo[] = {
-w, +1.0, 0.0, 1.0,
-w, -1.0, 0.0, 0.0,
+w, +1.0, 1.0, 1.0,
+w, -1.0, 1.0, 0.0
};
uint32_t stride = 2 * 2 * sizeof(float);
gfx_opengl_set_vertex_buffer(buf_vbo, 4 * stride);
// Draw the quad
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
static void gfx_opengl_create_render_target_views(bool is_resize) {
if (!is_resize) {
// Initialize the framebuffer only the first time.
gfx_opengl_create_render_target(FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, false, false, &framebuffer_rt);
}
// Create the main render target where contents will be rendered.
gfx_opengl_create_render_target(current_width, current_height, is_resize, true, &main_rt);
}
static bool gfx_opengl_z_is_from_0_to_1(void) {
return false;
}
@ -107,19 +309,71 @@ static inline void gfx_opengl_set_texture_uniforms(struct ShaderProgram *prg, co
}
}
static GLuint gfx_opengl_compile_shader(const char *vertex_shader_raw, const char *fragment_shader_raw) {
GLint success;
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
if (!vertex_shader) {
fprintf(stderr, "Failed to create vertex shader!\n");
return -1;
}
glShaderSource(vertex_shader, 1, &vertex_shader_raw, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLint max_length = 0;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
fprintf(stderr, "Vertex shader compilation failed\n");
glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]);
fprintf(stderr, "%s\n", &error_log[0]);
sys_fatal("vertex shader compilation failed (see terminal)");
}
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
if (!fragment_shader) {
fprintf(stderr, "Failed to create fragment shader!\n");
return -1;
}
glShaderSource(fragment_shader, 1, &fragment_shader_raw, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLint max_length = 0;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
fprintf(stderr, "Fragment shader compilation failed\n");
glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]);
fprintf(stderr, "%s\n", &error_log[0]);
sys_fatal("fragment shader compilation failed (see terminal)");
}
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
glDetachShader(shader_program, vertex_shader);
glDetachShader(shader_program, fragment_shader);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return shader_program;
}
static void gfx_opengl_unload_shader(struct ShaderProgram *old_prg) {
if (old_prg != NULL) {
for (int i = 0; i < old_prg->num_attribs; i++)
glDisableVertexAttribArray(old_prg->attrib_locations[i]);
if (old_prg == opengl_prg)
opengl_prg = NULL;
if (old_prg == current_shader_program)
current_shader_program = NULL;
} else {
opengl_prg = NULL;
current_shader_program = NULL;
}
}
static void gfx_opengl_load_shader(struct ShaderProgram *new_prg) {
opengl_prg = new_prg;
current_shader_program = new_prg;
glUseProgram(new_prg->opengl_program_id);
gfx_opengl_vertex_array_set_attribs(new_prg);
gfx_opengl_set_shader_uniforms(new_prg);
@ -255,7 +509,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(struct ColorC
bool opt_2cycle = cc->cm.use_2cycle;
bool opt_light_map = cc->cm.light_map;
#ifdef USE_GLES
#if defined(USE_GLES)
bool opt_dither = false;
#else
bool opt_dither = cc->cm.use_dither;
@ -268,7 +522,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(struct ColorC
size_t num_floats = 4;
// Vertex shader
#ifdef USE_GLES
#if defined(USE_GLES)
append_line(vs_buf, &vs_len, "#version 100");
#else
append_line(vs_buf, &vs_len, "#version 120");
@ -311,7 +565,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(struct ColorC
append_line(vs_buf, &vs_len, "}");
// Fragment shader
#ifdef USE_GLES
#if defined(USE_GLES)
append_line(fs_buf, &fs_len, "#version 100");
append_line(fs_buf, &fs_len, "precision mediump float;");
#else
@ -367,7 +621,11 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(struct ColorC
append_line(fs_buf, &fs_len, "float random(in vec3 value) {");
append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));");
#ifdef USE_GLES
append_line(fs_buf, &fs_len, " return fract(sin(random) * 143.7585453);");
#else
append_line(fs_buf, &fs_len, " return fract(sin(random) * 143758.5453);");
#endif
append_line(fs_buf, &fs_len, "}");
}
@ -449,42 +707,7 @@ static struct ShaderProgram *gfx_opengl_create_and_load_new_shader(struct ColorC
puts(fs_buf);
puts("End");*/
const GLchar *sources[2] = { vs_buf, fs_buf };
const GLint lengths[2] = { vs_len, fs_len };
GLint success;
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &sources[0], &lengths[0]);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLint max_length = 0;
glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
fprintf(stderr, "Vertex shader compilation failed\n");
glGetShaderInfoLog(vertex_shader, max_length, &max_length, &error_log[0]);
fprintf(stderr, "%s\n", &error_log[0]);
sys_fatal("vertex shader compilation failed (see terminal)");
}
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &sources[1], &lengths[1]);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLint max_length = 0;
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
char error_log[1024];
fprintf(stderr, "Fragment shader compilation failed\n");
glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]);
fprintf(stderr, "%s\n", &error_log[0]);
sys_fatal("fragment shader compilation failed (see terminal)");
}
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
GLuint shader_program = gfx_opengl_compile_shader(vs_buf, fs_buf);
size_t cnt = 0;
@ -597,7 +820,7 @@ static void gfx_opengl_select_texture(int tile, GLuint 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);
gfx_opengl_set_texture_uniforms(current_shader_program, tile);
}
static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, int width, int height) {
@ -623,11 +846,17 @@ static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint
opengl_curtex = tile;
if (opengl_tex[tile]) {
opengl_tex[tile]->filter = linear_filter;
gfx_opengl_set_texture_uniforms(opengl_prg, tile);
gfx_opengl_set_texture_uniforms(current_shader_program, tile);
}
}
static void gfx_opengl_set_depth_test(bool depth_test) {
if (gl_state.depth_test == depth_test) {
return;
}
gl_state.depth_test = depth_test;
if (depth_test) {
glEnable(GL_DEPTH_TEST);
} else {
@ -636,10 +865,22 @@ static void gfx_opengl_set_depth_test(bool depth_test) {
}
static void gfx_opengl_set_depth_mask(bool z_upd) {
if (gl_state.depth_mask == z_upd) {
return;
}
gl_state.depth_mask = z_upd;
glDepthMask(z_upd ? GL_TRUE : GL_FALSE);
}
static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
if (gl_state.zmode_decal == zmode_decal) {
return;
}
gl_state.zmode_decal = zmode_decal;
if (zmode_decal) {
glPolygonOffset(-2, -2);
glEnable(GL_POLYGON_OFFSET_FILL);
@ -648,12 +889,29 @@ static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
glDisable(GL_POLYGON_OFFSET_FILL);
}
}
static void gfx_opengl_set_viewport(int32_t x, int32_t y, int32_t width, int32_t height) {
if (gl_state.viewport_x == x && gl_state.viewport_y == y && gl_state.viewport_width == width && gl_state.viewport_height == height) {
return;
}
gl_state.viewport_x = x;
gl_state.viewport_y = y;
gl_state.viewport_width = width;
gl_state.viewport_height = height;
static void gfx_opengl_set_viewport(int x, int y, int width, int height) {
glViewport(x, y, width, height);
}
static void gfx_opengl_set_scissor(int x, int y, int width, int height) {
static void gfx_opengl_set_scissor(int32_t x, int32_t y, int32_t width, int32_t height) {
if (gl_state.scissor_x == x && gl_state.scissor_y == y && gl_state.scissor_width == width && gl_state.scissor_height == height) {
return;
}
gl_state.scissor_x = x;
gl_state.scissor_y = y;
gl_state.scissor_width = width;
gl_state.scissor_height = height;
glScissor(x, y, width, height);
}
@ -666,14 +924,29 @@ 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);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * buf_vbo_len, buf_vbo, GL_STREAM_DRAW);
// Depth
gfx_opengl_set_depth_test(current_depth_test);
gfx_opengl_set_depth_mask(current_depth_mask);
gfx_opengl_set_zmode_decal(current_zmode_decal);
// Viewport and Scissor
gfx_opengl_set_viewport(current_viewport_x, current_viewport_y, current_viewport_width, current_viewport_height);
gfx_opengl_set_scissor(current_scissor_x, current_scissor_y, current_scissor_width, current_scissor_height);
// Draw vertex buffer
gfx_opengl_set_vertex_buffer(buf_vbo, buf_vbo_len * sizeof(float));
glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);
}
static inline bool gl_get_version(int *major, int *minor, bool *is_es) {
const char *vstr = (const char *)glGetString(GL_VERSION);
if (!vstr || !vstr[0]) return false;
if (!vstr || !vstr[0]) {
return false;
}
if (!strncmp(vstr, "OpenGL ES ", 10)) {
vstr += 10;
@ -686,34 +959,103 @@ static inline bool gl_get_version(int *major, int *minor, bool *is_es) {
return (sscanf(vstr, "%d.%d", major, minor) == 2);
}
static void gfx_opengl_get_framebuffer(uint16_t *buffer) {
if (USE_FRAMEBUFFER) {
gfx_opengl_bind_render_target(&framebuffer_rt);
uint8_t pixels[FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT * 4];
glReadPixels(0, 0, FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
uint32_t bi = 0;
for (int32_t y = FRAMEBUFFER_HEIGHT - 1; y >= 0; y--) {
for (int32_t x = 0; x < FRAMEBUFFER_WIDTH; x++) {
uint32_t fb_pixel = (y * FRAMEBUFFER_WIDTH + x) * 4;
uint8_t r = pixels[fb_pixel + 0] >> 3;
uint8_t g = pixels[fb_pixel + 1] >> 3;
uint8_t b = pixels[fb_pixel + 2] >> 3;
uint8_t a = 1; //pixels[fb_pixel + 3] / 255;
buffer[bi] = (r << 11) | (g << 6) | (b << 1) | a;
bi++;
}
}
}
}
static void gfx_opengl_init(void) {
#if FOR_WINDOWS || defined(OSX_BUILD)
GLenum err;
if ((err = glewInit()) != GLEW_OK)
sys_fatal("could not init GLEW:\n%s", glewGetErrorString(err));
#endif
tex_cache_size = TEX_CACHE_STEP;
tex_cache = calloc(tex_cache_size, sizeof(struct GLTexture));
if (!tex_cache) sys_fatal("out of memory allocating texture cache");
if (!tex_cache) {
printf("Ran out of memory allocating texture cache!");
return;
}
// check GL version
// Check GL version
int vmajor = 0;
int vminor = 0;
bool is_es = false;
gl_get_version(&vmajor, &vminor, &is_es);
if (vmajor < 2 && vminor < 1 && !is_es)
sys_fatal("OpenGL 2.1+ is required.\nReported version: %s%d.%d", is_es ? "ES" : "", vmajor, vminor);
if (vmajor < 2 && vminor < 1 && !is_es) {
printf("GL: OpenGL 2.1+ is required.\nGL: Reported version: %s%d.%d\n", is_es ? "ES" : "", vmajor, vminor);
return;
}
printf("GL: OpenGL loaded:\n");
printf("Vendor: %s\n", glGetString(GL_VENDOR));
printf("Renderer: %s\n", glGetString(GL_RENDERER));
printf("Version: %s\n", glGetString(GL_VERSION));
printf("Using: OpenGL %s%d.%d\n", is_es ? "ES " : " ", vmajor, vminor);
// Initialize resolution before drawing first frame
if (current_width != gfx_current_dimensions.width || current_height != gfx_current_dimensions.height) {
current_width = gfx_current_dimensions.width;
current_height = gfx_current_dimensions.height;
}
// Initialize render targets
if (USE_FRAMEBUFFER) {
gfx_opengl_create_render_target_views(false);
// Create the render target shader, used to draw into fullscreen quads
rt_shader_program.opengl_program_id = gfx_opengl_compile_shader(rt_vertex_shader, rt_fragment_shader);
rt_shader_program.attrib_locations[0] = glGetAttribLocation(rt_shader_program.opengl_program_id, "a_position");
rt_shader_program.attrib_sizes[0] = 2;
rt_shader_program.attrib_locations[1] = glGetAttribLocation(rt_shader_program.opengl_program_id, "a_uv");
rt_shader_program.attrib_sizes[1] = 2;
rt_shader_program.num_attribs = 2;
rt_shader_program.num_floats = 4;
rt_shader_program.used_textures[0] = true;
rt_shader_program.used_textures[1] = false;
rt_shader_program.num_inputs = 0; // Unused in this case
rt_shader_program.used_noise = false; // Unused in this case
rt_shader_program.used_lightmap = false; // Unused in this case
glUseProgram(rt_shader_program.opengl_program_id);
GLint sampler_location = glGetUniformLocation(rt_shader_program.opengl_program_id, "u_texture");
glUniform1i(sampler_location, 0);
}
glGenBuffers(1, &opengl_vbo);
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
#if !defined(__SWITCH__)
if (vmajor >= 3 && !is_es) {
glGenVertexArrays(1, &opengl_vao);
glBindVertexArray(opengl_vao);
}
#endif
glDepthFunc(GL_LEQUAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
@ -723,6 +1065,16 @@ static void gfx_opengl_on_resize(void) {
static void gfx_opengl_start_frame(void) {
frame_count++;
if (USE_FRAMEBUFFER) {
if (current_width != gfx_current_dimensions.width || current_height != gfx_current_dimensions.height) {
current_width = gfx_current_dimensions.width;
current_height = gfx_current_dimensions.height;
gfx_opengl_create_render_target_views(true);
}
}
gfx_opengl_bind_render_target(&main_rt);
glDisable(GL_SCISSOR_TEST);
glDepthMask(GL_TRUE); // Must be set to clear Z-buffer
@ -732,6 +1084,23 @@ static void gfx_opengl_start_frame(void) {
}
static void gfx_opengl_end_frame(void) {
if (USE_FRAMEBUFFER) {
// Set the shader and vertex attribs for quad rendering
glUseProgram(rt_shader_program.opengl_program_id);
gfx_opengl_vertex_array_set_attribs(&rt_shader_program);
// Draw quad with main render target into the other render targets
gfx_opengl_draw_render_target(NULL, &main_rt, false);
gfx_opengl_draw_render_target(&framebuffer_rt, &main_rt, true);
// Set again the last shader used before drawing render targets.
// Not doing so can lead to rendering issues on the first drawcalls
// of the next frame, if they use the same shader as the ones before.
gfx_opengl_load_shader(current_shader_program);
}
}
static void gfx_opengl_finish_render(void) {
@ -740,6 +1109,32 @@ static void gfx_opengl_finish_render(void) {
static void gfx_opengl_shutdown(void) {
}
static void gfx_opengl_set_current_depth_test(bool depth_test) {
current_depth_test = depth_test;
}
static void gfx_opengl_set_current_depth_mask(bool z_upd) {
current_depth_mask = z_upd;
}
static void gfx_opengl_set_current_zmode_decal(bool zmode_decal) {
current_zmode_decal = zmode_decal;
}
static void gfx_opengl_set_current_viewport(int x, int y, int width, int height) {
current_viewport_x = x;
current_viewport_y = y;
current_viewport_width = width;
current_viewport_height = height;
}
static void gfx_opengl_set_current_scissor(int x, int y, int width, int height) {
current_scissor_x = x;
current_scissor_y = y;
current_scissor_width = width;
current_scissor_height = height;
}
struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_z_is_from_0_to_1,
gfx_opengl_unload_shader,
@ -751,11 +1146,11 @@ struct GfxRenderingAPI gfx_opengl_api = {
gfx_opengl_select_texture,
gfx_opengl_upload_texture,
gfx_opengl_set_sampler_parameters,
gfx_opengl_set_depth_test,
gfx_opengl_set_depth_mask,
gfx_opengl_set_zmode_decal,
gfx_opengl_set_viewport,
gfx_opengl_set_scissor,
gfx_opengl_set_current_depth_test,
gfx_opengl_set_current_depth_mask,
gfx_opengl_set_current_zmode_decal,
gfx_opengl_set_current_viewport,
gfx_opengl_set_current_scissor,
gfx_opengl_set_use_alpha,
gfx_opengl_draw_triangles,
gfx_opengl_init,

View file

@ -28,6 +28,7 @@
#include "pc/configfile.h"
#include "pc/debug_context.h"
#include "pc/game_main.h"
#include "pc/pc_main.h"
#include "pc/platform.h"

View file

@ -17,7 +17,7 @@
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
#include "../pc_main.h"
#include "../game_main.h"
#include "../configfile.h"
#include "../cliopts.h"
#include "../platform.h"

View file

@ -33,7 +33,7 @@
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
#include "../pc_main.h"
#include "../game_main.h"
#include "../configfile.h"
#include "../cliopts.h"
@ -56,7 +56,7 @@
# define FRAMERATE 30
#endif
static SDL_Window *wnd;
static SDL_Window *wnd = NULL;
static SDL_GLContext ctx = NULL;
static kb_callback_t kb_key_down = NULL;
@ -74,6 +74,10 @@ static inline void gfx_sdl_set_vsync(const bool enabled) {
}
static void gfx_sdl_set_fullscreen(void) {
#ifdef __SWITCH__
SDL_SetWindowFullscreen(wnd, 0);
SDL_ShowCursor(SDL_ENABLE);
#else
if (configWindow.reset)
configWindow.fullscreen = false;
if (configWindow.fullscreen == IS_FULLSCREEN())
@ -82,17 +86,37 @@ static void gfx_sdl_set_fullscreen(void) {
SDL_SetWindowFullscreen(wnd, SDL_WINDOW_FULLSCREEN_DESKTOP);
} else {
SDL_SetWindowFullscreen(wnd, 0);
SDL_ShowCursor(1);
SDL_ShowCursor(SDL_ENABLE);
configWindow.exiting_fullscreen = true;
}
#endif
}
static void gfx_sdl_reset_dimension_and_pos(void) {
if (configWindow.exiting_fullscreen) {
configWindow.exiting_fullscreen = false;
SDL_ShowCursor(0);
SDL_ShowCursor(SDL_DISABLE);
}
#ifdef __SWITCH__
if (configWindow.reset) {
configWindow.x = 0;
configWindow.y = 0;
if (appletGetOperationMode() == 1) {
configWindow.w = 1920;
configWindow.h = 1080;
} else {
configWindow.w = 1280;
configWindow.h = 720;
}
configWindow.reset = false;
} else if (!configWindow.settings_changed) {
return;
}
SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
SDL_SetWindowPosition(wnd, configWindow.x, configWindow.y);
#else
if (configWindow.reset) {
configWindow.x = WAPI_WIN_CENTERPOS;
configWindow.y = WAPI_WIN_CENTERPOS;
@ -108,18 +132,22 @@ static void gfx_sdl_reset_dimension_and_pos(void) {
SDL_SetWindowSize(wnd, configWindow.w, configWindow.h);
SDL_SetWindowPosition(wnd, xpos, ypos);
// in case vsync changed
gfx_sdl_set_vsync(configWindow.vsync);
#endif
}
static void gfx_sdl_init(const char *window_title) {
static void gfx_sdl_init(const char *window_title) {
#if defined(_WIN32) || defined(_WIN64)
SetProcessDPIAware();
#endif
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
SDL_Init(SDL_INIT_VIDEO);
#ifndef __SWITCH__
SDL_StartTextInput();
#endif
if (configWindow.msaa > 0) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
@ -127,11 +155,46 @@ static void gfx_sdl_init(const char *window_title) {
} else {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
}
// Request a depth buffer
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifdef USE_GLES
#ifdef __SWITCH__
// Request an OpenGL 3 context
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
if (appletGetOperationMode() == 1) {
configWindow.w = 1920;
configWindow.h = 1080;
} else {
configWindow.w = 1280;
configWindow.h = 720;
}
configWindow.x = 0;
configWindow.y = 0;
printf("Creating SDL Window with size: %d %d\n", configWindow.w, configWindow.h);
wnd = SDL_CreateWindow("sdl2_gles2", configWindow.w, configWindow.h, configWindow.w, configWindow.h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (!wnd) {
printf("SDL2: Failed to create window with error: %s\n", SDL_GetError());
return;
}
ctx = SDL_GL_CreateContext(wnd);
if (!ctx) {
printf("SDL2: Failed to create context with error: %s\n", SDL_GetError());
return;
}
gfx_sdl_set_vsync(2);
gfx_sdl_set_fullscreen();
#else
#if defined(USE_GLES)
// Request an OpenGL 2.1 context
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); // These attributes allow for hardware acceleration on RPis.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
@ -139,13 +202,17 @@ static void gfx_sdl_init(const char *window_title) {
int xpos = (configWindow.x == WAPI_WIN_CENTERPOS) ? SDL_WINDOWPOS_CENTERED : configWindow.x;
int ypos = (configWindow.y == WAPI_WIN_CENTERPOS) ? SDL_WINDOWPOS_CENTERED : configWindow.y;
wnd = SDL_CreateWindow(
window_title,
xpos, ypos, configWindow.w, configWindow.h,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
ctx = SDL_GL_CreateContext(wnd);
if (!ctx) {
printf("SDL2: Failed to create context with error: %s", SDL_GetError());
return;
}
gfx_sdl_set_vsync(configWindow.vsync);
@ -153,6 +220,7 @@ static void gfx_sdl_init(const char *window_title) {
if (configWindow.fullscreen) {
SDL_ShowCursor(SDL_DISABLE);
}
#endif
controller_bind_init();
}
@ -311,7 +379,7 @@ static void gfx_sdl_set_window_title(const char* title) {
}
static void gfx_sdl_reset_window_title(void) {
SDL_SetWindowTitle(wnd, TITLE);
SDL_SetWindowTitle(wnd, "SM64 Coop DX");
}
static void gfx_sdl_shutdown(void) {

View file

@ -14,7 +14,7 @@ typedef bool (*kb_callback_t)(int code);
struct GfxWindowManagerAPI {
void (*init)(const char *window_title);
void (*set_keyboard_callbacks)(kb_callback_t on_key_down, kb_callback_t on_key_up, void (*on_all_keys_up)(void),
void (*on_text_input)(char*), void (*on_text_editing)(char*, int));
void (*on_text_input)(char*), void (*on_text_editing)(char*, int));
void (*set_scroll_callback)(void (*on_scroll)(float, float));
void (*main_loop)(void (*run_one_game_iter)(void));
void (*get_dimensions)(uint32_t *width, uint32_t *height);
@ -26,7 +26,7 @@ struct GfxWindowManagerAPI {
void (*shutdown)(void);
void (*start_text_input)(void);
void (*stop_text_input)(void);
char* (*get_clipboard_text)(void);
char *(*get_clipboard_text)(void);
void (*set_clipboard_text)(const char*);
void (*set_cursor_visible)(bool);
void (*delay)(unsigned int ms);

View file

@ -7,7 +7,7 @@
#include "djui/djui.h"
#include "pc/djui/djui_unicode.h"
#include "pc_main.h"
#include "game_main.h"
#include "pc/utils/misc.h"
#include "pc/cliopts.h"
#include "rom_checker.h"
@ -179,7 +179,7 @@ void render_loading_screen(void) {
// loading screen loop
while (!gGameInited) {
WAPI.main_loop(loading_screen_produce_one_frame);
wm_api->main_loop(loading_screen_produce_one_frame);
}
int err = join_thread(&gLoadingThread);
@ -192,7 +192,7 @@ void render_rom_setup_screen(void) {
loading_screen_set_segment_text("No rom detected, drag & drop Super Mario 64 (U) [!].z64 on to this screen");
while (!gRomIsValid) {
WAPI.main_loop(loading_screen_produce_one_frame);
wm_api->main_loop(loading_screen_produce_one_frame);
}
}

View file

@ -18,6 +18,7 @@
#include "pc/debuglog.h"
#include "pc/djui/djui_console.h"
#include "pc/string_utils.h"
#define LOG_LUA(...) { if (!gSmLuaSuppressErrors) { printf("[LUA] "), printf(__VA_ARGS__), printf("\n"), smlua_mod_error(), snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR); } }
#define LOG_LUA_LINE(...) { if (!gSmLuaSuppressErrors) { printf("[LUA] "), printf(__VA_ARGS__), printf("\n"), smlua_mod_error(); snprintf(gDjuiConsoleTmpBuffer, CONSOLE_MAX_TMP_BUFFER, __VA_ARGS__), sys_swap_backslashes(gDjuiConsoleTmpBuffer), djui_console_message_create(gDjuiConsoleTmpBuffer, CONSOLE_MESSAGE_ERROR), smlua_logline(); } }

View file

@ -14,12 +14,13 @@
#include "pc/network/network_player.h"
#include "pc/network/socket/socket.h"
#include "pc/chat_commands.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/djui/djui_lua_profiler.h"
#include "pc/djui/djui_panel.h"
#include "pc/configfile.h"
#include "pc/utils/misc.h"
#include "pc/lua/utils/smlua_model_utils.h"
#include "pc/string_utils.h"
#include "../mods/mods.h"
#include "game/print.h"

View file

@ -3,6 +3,7 @@
#include "pc/lua/smlua.h"
#include "smlua_anim_utils.h"
#include "pc/debuglog.h"
#include "pc/string_utils.h"
// models
#include "actors/common0.h"

View file

@ -1,5 +1,3 @@
#define MINIAUDIO_IMPLEMENTATION // required by miniaudio
// enable Vorbis decoding (provides ogg audio decoding support) for miniaudio
#define STB_VORBIS_HEADER_ONLY
#include "pc/utils/stb_vorbis.c"
@ -15,7 +13,7 @@
#include "pc/mods/mods_utils.h"
#include "pc/utils/misc.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/fs/fmem.h"
struct AudioOverride {
@ -158,19 +156,15 @@ void smlua_audio_utils_replace_sequence(u8 sequenceId, u8 bankId, u8 defaultVolu
// mod audio //
///////////////
// Optimization: disable spatialization for everything as it's not used
#define MA_SOUND_STREAM_FLAGS (MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_STREAM)
#define MA_SOUND_SAMPLE_FLAGS (MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_PITCH | MA_SOUND_FLAG_DECODE) // No pitch, pre-decode audio samples
static ma_engine sModAudioEngine;
static struct DynamicPool *sModAudioPool;
static void smlua_audio_custom_init(void) {
sModAudioPool = dynamic_pool_init();
ma_result result = ma_engine_init(NULL, &sModAudioEngine);
ma_result result = ma_initalize(NULL, &sModAudioEngine);
if (result != MA_SUCCESS) {
LOG_ERROR("failed to init Miniaudio: %d", result);
LOG_ERROR("Failed to init Miniaudio: %d", result);
}
}
@ -291,23 +285,11 @@ struct ModAudio* audio_load_internal(const char* filename, bool isStream) {
}
f_close(f);
f_delete(f);
// decode the audio buffer
ma_result result = ma_decoder_init_memory(buffer, size, NULL, &audio->decoder);
ma_result result = ma_sound_from_buffer(&sModAudioEngine, &audio->sound, &audio->decoder, buffer, size, isStream);
if (result != MA_SUCCESS) {
free(buffer);
LOG_ERROR("failed to load audio file '%s': failed to decode raw audio: %d", filename, result);
return NULL;
}
result = ma_sound_init_from_data_source(
&sModAudioEngine, &audio->decoder,
isStream ? MA_SOUND_STREAM_FLAGS : MA_SOUND_SAMPLE_FLAGS,
NULL, &audio->sound
);
if (result != MA_SUCCESS) {
free(buffer);
LOG_ERROR("failed to load audio file '%s': %d", filename, result);
LOG_ERROR("Failed to load audio file '%s': Failed to decode raw audio: %d", filename, result);
return NULL;
}
@ -331,8 +313,8 @@ void audio_stream_destroy(struct ModAudio* audio) {
void audio_stream_play(struct ModAudio* audio, bool restart, f32 volume) {
if (!audio_sanity_check(audio, true, "play")) { return; }
if (configMuteFocusLoss && !WAPI.has_focus()) {
if (configMuteFocusLoss && !wm_api->has_focus()) {
ma_sound_set_volume(&audio->sound, 0);
} else {
f32 musicVolume = (f32)configMusicVolume / 127.0f * (f32)gLuaVolumeLevel / 127.0f;
@ -359,7 +341,7 @@ void audio_stream_stop(struct ModAudio* audio) {
f32 audio_stream_get_position(struct ModAudio* audio) {
if (!audio_sanity_check(audio, true, "get stream position from")) { return 0; }
u64 cursor; ma_data_source_get_cursor_in_pcm_frames(&audio->decoder, &cursor);
ma_uint64 cursor; ma_data_source_get_cursor_in_pcm_frames(&audio->decoder, &cursor);
return (f32)cursor / ma_engine_get_sample_rate(&sModAudioEngine);
}
@ -384,7 +366,7 @@ void audio_stream_set_looping(struct ModAudio* audio, bool looping) {
void audio_stream_set_loop_points(struct ModAudio* audio, s64 loopStart, s64 loopEnd) {
if (!audio_sanity_check(audio, true, "set stream loop points for")) { return; }
u64 length; ma_data_source_get_length_in_pcm_frames(&audio->decoder, &length);
ma_uint64 length; ma_data_source_get_length_in_pcm_frames(&audio->decoder, &length);
if (loopStart < 0) loopStart += length;
if (loopEnd <= 0) loopEnd += length;
@ -423,9 +405,9 @@ f32 audio_stream_get_volume(struct ModAudio* audio) {
}
void audio_stream_set_volume(struct ModAudio* audio, f32 volume) {
if (!audio_sanity_check(audio, true, "set stream volume for")) { return; }
if (configMuteFocusLoss && !WAPI.has_focus()) {
if (!audio_sanity_check(audio, true, "set stream volume")) { return; }
if (configMuteFocusLoss && !wm_api->has_focus()) {
ma_sound_set_volume(&audio->sound, 0);
} else {
f32 musicVolume = (f32)configMusicVolume / 127.0f * (f32)gLuaVolumeLevel / 127.0f;
@ -531,9 +513,7 @@ void audio_sample_play(struct ModAudio* audio, Vec3f position, f32 volume) {
ma_sound *sound = &audio->sound;
if (ma_sound_is_playing(sound)) {
struct ModAudioSampleCopies* copy = calloc(1, sizeof(struct ModAudioSampleCopies));
ma_result result = ma_decoder_init_memory(audio->buffer, audio->bufferSize, NULL, &copy->decoder);
if (result != MA_SUCCESS) { return; }
result = ma_sound_init_from_data_source(&sModAudioEngine, &copy->decoder, MA_SOUND_SAMPLE_FLAGS, NULL, &copy->sound);
ma_result result = ma_sound_from_buffer(&sModAudioEngine, &copy->sound, &copy->decoder, audio->buffer, audio->bufferSize, false);
if (result != MA_SUCCESS) { return; }
ma_sound_set_end_callback(&copy->sound, audio_sample_copy_end_callback, copy);
copy->parent = audio;
@ -563,7 +543,7 @@ void audio_sample_play(struct ModAudio* audio, Vec3f position, f32 volume) {
pan = (get_sound_pan(mtx[3][0] * factor, mtx[3][2] * factor) - 0.5f) * 2.0f;
}
if (configMuteFocusLoss && !WAPI.has_focus()) {
if (configMuteFocusLoss && !wm_api->has_focus()) {
ma_sound_set_volume(sound, 0);
} else {
f32 intensity = sound_get_level_intensity(dist);
@ -584,7 +564,7 @@ void audio_custom_update_volume(void) {
while (node) {
struct DynamicPoolNode* prev = node->prev;
struct ModAudio* audio = node->ptr;
if (configMuteFocusLoss && !WAPI.has_focus()) {
if (configMuteFocusLoss && !wm_api->has_focus()) {
ma_sound_set_volume(&audio->sound, 0);
} else if (audio->isStream) {
ma_sound_set_volume(&audio->sound, gMasterVolume * musicVolume * audio->baseVolume);
@ -615,7 +595,7 @@ void smlua_audio_custom_deinit(void) {
if (sModAudioPool) {
audio_custom_shutdown();
free(sModAudioPool);
ma_engine_uninit(&sModAudioEngine);
ma_uninitalize(&sModAudioEngine);
sModAudioPool = NULL;
}
}

View file

@ -1,7 +1,7 @@
#ifndef SMLUA_AUDIO_UTILS_H
#define SMLUA_AUDIO_UTILS_H
#include "pc/utils/miniaudio.h"
#include "pc/utils/miniaudio_api.h"
/* |description|Resets all custom sequences back to vanilla|descriptionEnd| */
void smlua_audio_utils_reset_all(void);

View file

@ -14,7 +14,7 @@
#include "pc/mods/mod.h"
#include "pc/mods/mods.h"
#include "pc/mods/mods_utils.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "game/object_list_processor.h"
#include "game/rendering_graph_node.h"
#include "game/level_update.h"
@ -539,11 +539,11 @@ struct Mod* get_active_mod(void) {
///
void set_window_title(const char* title) {
WAPI.set_window_title(title);
wm_api->set_window_title(title);
}
void reset_window_title(void) {
WAPI.reset_window_title();
wm_api->reset_window_title();
}
///

View file

@ -6,7 +6,7 @@
#include "game/save_file.h"
#include "game/segment2.h"
#include "game/level_info.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "../smlua.h"
#include "smlua_level_utils.h"
#include "smlua_text_utils.h"

View file

@ -6,6 +6,7 @@
#include "pc/utils/misc.h"
#include "pc/utils/md5.h"
#include "pc/debuglog.h"
#include "pc/string_utils.h"
#include "pc/fs/fmem.h"
size_t mod_get_lua_size(struct Mod* mod) {

View file

@ -9,6 +9,7 @@
#include "mods_utils.h"
#include "pc/utils/md5.h"
#include "pc/lua/smlua_hooks.h"
#include "pc/string_utils.h"
#include "pc/loading.h"
#define MOD_CACHE_FILENAME "mod.cache"

View file

@ -6,7 +6,8 @@
#include "pc/debuglog.h"
#include "pc/loading.h"
#include "pc/fs/fmem.h"
#include "pc/pc_main.h"
#include "pc/string_utils.h"
#include "pc/game_main.h"
#include "pc/utils/misc.h"
#if defined(_WIN32) || defined(_WIN64)

View file

@ -3,6 +3,7 @@
#include "mods.h"
#include "mods_utils.h"
#include "pc/debuglog.h"
#include "pc/string_utils.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
@ -26,6 +27,9 @@ void mods_size_enforce(struct Mods* mods) {
}
static bool mods_incompatible_match(struct Mod* a, struct Mod* b) {
#ifdef __SWITCH__
return false;
#else
if (a->incompatible == NULL || b->incompatible == NULL) {
return false;
}
@ -52,6 +56,7 @@ static bool mods_incompatible_match(struct Mod* a, struct Mod* b) {
free(bi);
return false;
#endif
}
void mods_update_selectable(void) {

View file

@ -1,3 +1,5 @@
#ifndef __CONSOLE__
// adapted from https://www.mumble.info/documentation/developer/positional-audio/link-plugin/
#include "mumble.h"
@ -196,3 +198,5 @@ bool should_update_context() {
return true;
}
#endif // __CONSOLE__

View file

@ -1,3 +1,5 @@
#ifndef __CONSOLE__
#ifndef MUMBLE_H
#define MUMBLE_H
@ -31,4 +33,6 @@ void mumble_update_menu(void);
bool should_update_context(void);
#endif /* MUMBLE_H */
#endif /* MUMBLE_H */
#endif // __CONSOLE__

View file

@ -3,6 +3,7 @@
#include <PR/ultratypes.h>
#include "ban_list.h"
#include "pc/debuglog.h"
#include "pc/string_utils.h"
char** gBanAddresses = NULL;
bool* gBanPerm = NULL;

View file

@ -3,6 +3,7 @@
#include <PR/ultratypes.h>
#include "moderator_list.h"
#include "pc/debuglog.h"
#include "pc/string_utils.h"
char** gModeratorAddresses = NULL;
bool* gModerator = NULL;

View file

@ -19,7 +19,7 @@
#include "pc/mods/mods.h"
#include "pc/crash_handler.h"
#include "pc/debuglog.h"
#include "pc/pc_main.h"
#include "pc/game_main.h"
#include "pc/gfx/gfx_pc.h"
#include "pc/fs/fmem.h"
#include "game/hardcoded.h"

View file

@ -10,6 +10,7 @@
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
#include "pc/fs/fmem.h"
#include "pc/string_utils.h"
#define CHUNK_SIZE 800
#define OFFSET_COUNT 50

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