diff --git a/.ci/switch/buildswitch.bash b/.ci/switch/buildswitch.bash new file mode 100755 index 000000000..032b19157 --- /dev/null +++ b/.ci/switch/buildswitch.bash @@ -0,0 +1,11 @@ +#!/bin/bash + +cp -av /usr/local/lib/libSDL2* /lib/x86_64-linux-gnu/ +git config --global --add safe.directory /soh +make setup -C soh -j$(nproc) OPTFLAGS=-O2 DEBUG=0 CC="gcc" CXX="g++" + +/opt/devkitpro/portlibs/switch/bin/aarch64-none-elf-cmake -B StormLib/build-switch -S StormLib -DCMAKE_INSTALL_PREFIX=/opt/devkitpro/portlibs/switch/ +make -C StormLib/build-switch -j$(nproc) +make install -C StormLib/build-switch + +make -f Makefile.switch -j$(nproc) OPTFLAGS=-O2 DEBUG=0 diff --git a/.gitignore b/.gitignore index 5f9933097..e4e07589b 100644 --- a/.gitignore +++ b/.gitignore @@ -407,6 +407,13 @@ oot.otr shipofharkinian.ini shipofharkinian.json +# Switch Stuff + +*.nro +*.nacp +ZAPDTR/ZAPDUtils/lib/* +!/soh/icon.jpg + # Xcode xcuserdata/ *.xcconfig diff --git a/Dockerfile.switch b/Dockerfile.switch new file mode 100644 index 000000000..7319f22a6 --- /dev/null +++ b/Dockerfile.switch @@ -0,0 +1,58 @@ +FROM ubuntu:20.04 as build + +ENV LANG C.UTF-8 +ARG DEBIAN_FRONTEND=noninteractive + +ENV GCCVER=10 +RUN \ + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y \ + binutils \ + gcc-10 \ + g++-10 \ + p7zip-full \ + python3 \ + make \ + cmake \ + curl \ + git \ + lld \ + wget \ + libsdl2-dev \ + zlib1g-dev \ + libbz2-dev \ + libpng-dev \ + libgles2-mesa-dev && \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCCVER} 10 && \ + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCCVER} 10 + +RUN git clone https://github.com/Perlmint/glew-cmake.git && \ + cmake glew-cmake && \ + make -j$(nproc) && \ + make install ARCH64=true + +ENV SDL2VER=2.0.22 +RUN curl -sLO https://libsdl.org/release/SDL2-${SDL2VER}.tar.gz && \ + tar -xzf SDL2-${SDL2VER}.tar.gz && \ + cd SDL2-${SDL2VER} && \ + ./configure --build=x86_64-linux-gnu && \ + make && make install && \ + rm ../SDL2-${SDL2VER}.tar.gz + +RUN \ + ln -sf /proc/self/mounts /etc/mtab && \ + mkdir -p /usr/local/share/keyring/ && \ + wget -O /usr/local/share/keyring/devkitpro-pub.gpg https://apt.devkitpro.org/devkitpro-pub.gpg && \ + echo "deb [signed-by=/usr/local/share/keyring/devkitpro-pub.gpg] https://apt.devkitpro.org stable main" > /etc/apt/sources.list.d/devkitpro.list && \ + apt-get update -y && \ + apt-get install -y devkitpro-pacman && \ + yes | dkp-pacman -Syu switch-dev switch-portlibs --noconfirm + +ENV DEVKITPRO=/opt/devkitpro +ENV DEVKITARM=/opt/devkitpro/devkitARM +ENV DEVKITPPC=/opt/devkitpro/devkitPPC +ENV PATH=$PATH:/opt/devkitpro/portlibs/switch/bin/ + +RUN mkdir /soh +WORKDIR /soh diff --git a/Jenkinsfile b/Jenkinsfile index f9ac7e7c8..033f1f758 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -106,9 +106,9 @@ pipeline { mv OTRGui/build/assets build/ mv ZAPDTR/ZAPD.out build/assets/extractor/ mv README.md readme.txt - + docker exec sohcont appimage/appimage.sh - + 7z a soh-linux.7z SOH-Linux.AppImage readme.txt ''' @@ -158,7 +158,47 @@ pipeline { } } } + stage ('Build Switch') { + options { + timeout(time: 20) + } + agent { + label "SoH-Linux-Builders" + } + steps { + checkout([ + $class: 'GitSCM', + branches: scm.branches, + doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations, + extensions: scm.extensions, + userRemoteConfigs: scm.userRemoteConfigs + ]) + catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { + sh ''' + + cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 + docker build . -t sohswitch -f Dockerfile.switch + docker run --name sohcont -dit --rm -v $(pwd):/soh sohswitch /bin/bash + docker exec sohcont .ci/switch/buildswitch.bash + + mv soh/soh.nro . + mv README.md readme.txt + + 7z a soh-switch.7z soh.nro readme.txt + + ''' + } + sh 'sudo docker container stop sohcont' + archiveArtifacts artifacts: 'soh-switch.7z', followSymlinks: false, onlyIfSuccessful: true + } + post { + always { + step([$class: 'WsCleanup']) // Clean workspace + } + } + } } } } } + diff --git a/Makefile.switch b/Makefile.switch new file mode 100644 index 000000000..2dd9f5ea2 --- /dev/null +++ b/Makefile.switch @@ -0,0 +1,36 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +export SOH_TOP_DIR := $(CURDIR) + +.PHONY: all clean ZAPDUtils libultraship soh StormLib + +all: soh + @echo "Done!" + +ZAPDUtils: + @echo "Building $@..." + @$(MAKE) --no-print-directory -C $(CURDIR)/ZAPDTR/ZAPDUtils -f $(CURDIR)/ZAPDTR/ZAPDUtils/Makefile.switch + +StormLib: + @echo "Building $@..." + LDFLAGS="" ${DEVKITPRO}/portlibs/switch/bin/aarch64-none-elf-cmake -DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/Switch.cmake -DCMAKE_BUILD_TYPE=Release -B $(CURDIR)/StormLib/nxbuild -S $(CURDIR)/StormLib + @$(MAKE) --no-print-directory -C $(CURDIR)/StormLib/nxbuild -f $(CURDIR)/StormLib/nxbuild/Makefile + +libultraship: StormLib ZAPDUtils + @echo "Building $@..." + @$(MAKE) --no-print-directory -C $(CURDIR)/libultraship -f $(CURDIR)/libultraship/Makefile.switch + +soh: libultraship + @echo "Building $@..." + @$(MAKE) --no-print-directory -C $(CURDIR)/soh -f $(CURDIR)/soh/Makefile.switch + +otr: + @echo "Building $@..." + @$(MAKE) --no-print-directory -C $(CURDIR)/soh -f $(CURDIR)/soh/Makefile setup + +clean: + @$(MAKE) --no-print-directory -C $(CURDIR)/ZAPDTR/ZAPDUtils -f $(CURDIR)/ZAPDTR/ZAPDUtils/Makefile.switch clean + @$(MAKE) --no-print-directory -C $(CURDIR)/libultraship -f $(CURDIR)/libultraship/Makefile.switch clean + @$(MAKE) --no-print-directory -C $(CURDIR)/soh -f $(CURDIR)/soh/Makefile.switch clean \ No newline at end of file diff --git a/OTRExporter/OTRExporter/OTRExporter.vcxproj b/OTRExporter/OTRExporter/OTRExporter.vcxproj index cecb9eaf3..c39da3df5 100644 --- a/OTRExporter/OTRExporter/OTRExporter.vcxproj +++ b/OTRExporter/OTRExporter/OTRExporter.vcxproj @@ -65,12 +65,6 @@ - - - {02d10590-9542-3f55-aaf8-6055677e2a2a} - false - - 16.0 Win32Proj diff --git a/StormLib/.gitignore b/StormLib/.gitignore index 3d764df91..660d12e05 100644 --- a/StormLib/.gitignore +++ b/StormLib/.gitignore @@ -140,6 +140,7 @@ Desktop.ini *.egg-info dist build +nxbuild eggs parts bin diff --git a/StormLib/CMakeLists.txt b/StormLib/CMakeLists.txt index bef21d8e9..243dea578 100644 --- a/StormLib/CMakeLists.txt +++ b/StormLib/CMakeLists.txt @@ -323,6 +323,11 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DO_LARGEFILE=0 -Dstat64=stat -Dlstat64=lstat -Dlseek64=lseek -Doff64_t=off_t -Dfstat64=fstat -Dftruncate64=ftruncate") endif() +if(NOT WIN32 AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL FreeBSD) + # Enable POSIX extensions such as `readlink` and `ftruncate`. + add_definitions(-D_POSIX_C_SOURCE=200809L) +endif() + add_library(${LIBRARY_NAME} ${LIB_TYPE} ${SRC_FILES} ${SRC_ADDITIONAL_FILES} ${STORM_DEF_FILES}) if(WIN32) set_target_properties(${LIBRARY_NAME} PROPERTIES OUTPUT_NAME "StormLib") diff --git a/StormLib/src/StormPort.h b/StormLib/src/StormPort.h index d38641422..77195f88d 100644 --- a/StormLib/src/StormPort.h +++ b/StormLib/src/StormPort.h @@ -95,7 +95,7 @@ #define PKEXPORT - #ifndef __SYS_ZLIB + #ifndef __SYS_ZLIB #define __SYS_ZLIB #endif diff --git a/ZAPDTR/ZAPD/ZAPD.vcxproj b/ZAPDTR/ZAPD/ZAPD.vcxproj index ad3c3e08c..9369e97da 100644 --- a/ZAPDTR/ZAPD/ZAPD.vcxproj +++ b/ZAPDTR/ZAPD/ZAPD.vcxproj @@ -359,12 +359,6 @@ - - - {02d10590-9542-3f55-aaf8-6055677e2a2a} - false - - diff --git a/ZAPDTR/ZAPDUtils/Makefile.switch b/ZAPDTR/ZAPDUtils/Makefile.switch new file mode 100644 index 000000000..ed173c44f --- /dev/null +++ b/ZAPDTR/ZAPDUtils/Makefile.switch @@ -0,0 +1,171 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +# +# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .json +# - config.json +# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead +# of a homebrew executable (.nro). This is intended to be used for sysmodules. +# NACP building is skipped as well. +#--------------------------------------------------------------------------------- +TARGET := ZAPDUtils +BUILD := build +SOURCES := Utils +DATA := +INCLUDES := + +#------------------------------------------------------------------------------- +# source files +#------------------------------------------------------------------------------- +SOURCEFILES_C := + +SOURCEFILES_CPP := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ + +CXXFLAGS := $(CFLAGS) -fno-rtti -fexceptions -std=gnu++20 +CFLAGS += -std=gnu11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach sf,$(SOURCEFILES_C),$(CURDIR)/$(dir $(sf))) \ + $(foreach sf,$(SOURCEFILES_CPP),$(CURDIR)/$(dir $(sf))) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) \ + $(foreach f,$(SOURCEFILES_C),$(notdir $(f))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach f,$(SOURCEFILES_CPP),$(notdir $(f))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD) : lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.switch + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -rf build lib + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT) : $(OFILES) + +$(OFILES_SRC) : $(HFILES) +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj index 05b9e1908..164f4bb11 100644 --- a/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj +++ b/ZAPDTR/ZAPDUtils/ZAPDUtils.vcxproj @@ -186,12 +186,6 @@ - - - {02d10590-9542-3f55-aaf8-6055677e2a2a} - false - - diff --git a/libultraship/Makefile b/libultraship/Makefile index 18dfca271..37640969d 100644 --- a/libultraship/Makefile +++ b/libultraship/Makefile @@ -9,6 +9,7 @@ UNAME := $(shell uname) ASAN ?= 0 DEBUG ?= 1 OPTFLAGS ?= -O0 +X11 ?= 0 LTO ?= 0 # flag to save whether the compiler being used is clang or gcc by checking CXX --version @@ -49,6 +50,11 @@ CPPFLAGS := -MMD MMFLAGS := -Wno-deprecated-declarations -ObjC++ -fobjc-weak -fobjc-arc +ifeq ($(X11), 1) +CXXFLAGS += -DX11_SUPPORTED +CFLAGS += -DX11_SUPPORTED +endif + # if not using clang, ask clang to use gcc standard library ifneq ($(CXX_IS_CLANG),1) STD_ISYSTEM=$(shell ${CXX} -xc++ -E -v - < /dev/null 2>&1 | grep "> search starts here" -A2 | tail -n 2 | head -n 1) diff --git a/libultraship/Makefile.switch b/libultraship/Makefile.switch new file mode 100644 index 000000000..72f0171aa --- /dev/null +++ b/libultraship/Makefile.switch @@ -0,0 +1,192 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +# +# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .json +# - config.json +# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead +# of a homebrew executable (.nro). This is intended to be used for sysmodules. +# NACP building is skipped as well. +#--------------------------------------------------------------------------------- +TARGET := ultraship +BUILD := build +SOURCES := \ + libultraship/Factories \ + libultraship/Lib/Fast3D \ + libultraship/Lib/ImGui \ + libultraship/Lib/Mercury \ + libultraship +DATA := +INCLUDES := \ + ../ZAPDTR/ZAPDUtils \ + ../StormLib/src \ + libultraship/Lib/Fast3D/U64 \ + libultraship/Lib/ImGui \ + libultraship/Lib/spdlog \ + libultraship/Lib/spdlog/include \ + libultraship + +#------------------------------------------------------------------------------- +# source files +#------------------------------------------------------------------------------- + +SOURCEFILES_C := \ + libultraship/mixer.c \ + libultraship/Lib/stb/stb_impl.c \ + +SOURCEFILES_CPP := \ + libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \ + libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \ + libultraship/Lib/StrHash64.cpp \ + libultraship/Lib/tinyxml2/tinyxml2.cpp + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE -ffast-math -O3 + +CFLAGS := -Wall -ffunction-sections \ + $(ARCH) $(DEFINES) \ + -DSPDLOG_NO_THREAD_ID \ + -DSTBI_NO_THREAD_LOCALS + +CFLAGS += $(INCLUDE) -D__SWITCH__ -DENABLE_OPENGL + +CXXFLAGS := $(CFLAGS) -std=gnu++20 +CFLAGS += -std=gnu11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach sf,$(SOURCEFILES_C),$(CURDIR)/$(dir $(sf))) \ + $(foreach sf,$(SOURCEFILES_CPP),$(CURDIR)/$(dir $(sf))) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) \ + $(foreach f,$(SOURCEFILES_C),$(notdir $(f))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach f,$(SOURCEFILES_CPP),$(notdir $(f))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD) : lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.switch + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -rf build lib + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- + +$(OUTPUT) : $(OFILES) + +$(OFILES_SRC) : $(HFILES) +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/libultraship/libultraship/Archive.cpp b/libultraship/libultraship/Archive.cpp index c57fb608c..81b0e180e 100644 --- a/libultraship/libultraship/Archive.cpp +++ b/libultraship/libultraship/Archive.cpp @@ -6,6 +6,10 @@ #include "Lib/StrHash64.h" #include +#ifdef __SWITCH__ +#include "SwitchImpl.h" +#endif + namespace Ship { Archive::Archive(const std::string& MainPath, bool enableWriting) : Archive(MainPath, "", enableWriting) { @@ -68,7 +72,7 @@ namespace Ship { //} if (!attempt) { - printf("({%i}) Failed to open file {%s} from mpq archive {%s}", GetLastError(), filePath.c_str(), MainPath.c_str()); + SPDLOG_ERROR("({}) Failed to open file {} from mpq archive {}.", GetLastError(), filePath.c_str(), MainPath.c_str()); std::unique_lock Lock(FileToLoad->FileLoadMutex); FileToLoad->bHasLoadError = true; return FileToLoad; @@ -327,13 +331,21 @@ namespace Ship { #ifdef _WIN32 std::wstring wfullPath = std::filesystem::absolute(MainPath).wstring(); #endif +#if defined(__SWITCH__) + std::string fullPath = MainPath; +#else std::string fullPath = std::filesystem::absolute(MainPath).string(); +#endif #ifdef _WIN32 if (!SFileOpenArchive(wfullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) { #else if (!SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) { #endif + + #ifdef __SWITCH__ + Switch::ThrowMissingOTR(fullPath); + #endif SPDLOG_ERROR("({}) Failed to open main mpq file {}.", GetLastError(), fullPath.c_str()); return false; } @@ -362,7 +374,11 @@ namespace Ship { bool Archive::LoadPatchMPQ(const std::string& path) { HANDLE patchHandle = NULL; +#if defined(__SWITCH__) + std::string fullPath = path; +#else std::string fullPath = std::filesystem::absolute(path).string(); +#endif if (mpqHandles.contains(fullPath)) { return true; } diff --git a/libultraship/libultraship/Console.cpp b/libultraship/libultraship/Console.cpp index da61e4056..85ba1f78d 100644 --- a/libultraship/libultraship/Console.cpp +++ b/libultraship/libultraship/Console.cpp @@ -98,20 +98,14 @@ void Console::Update() { } } -extern "C" uint8_t __enableGameInput; - void Console::Draw() { bool input_focus = false; - __enableGameInput = true; if (!this->opened) return; ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoFocusOnAppearing); const ImVec2 pos = ImGui::GetWindowPos(); const ImVec2 size = ImGui::GetWindowSize(); - - __enableGameInput = !ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); - // SohImGui::ShowCursor(ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | ImGuiHoveredFlags_RectOnly), SohImGui::Dialogues::dConsole); // Renders autocomplete window @@ -230,8 +224,8 @@ void Console::Draw() { // Renders input textfield constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; - ImGui::PushItemWidth(-1); - if(ImGui::InputTextWithHint("CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { + ImGui::PushItemWidth(-53); + if(ImGui::InputTextWithHint("##CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) { input_focus = true; if(this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' ') this->Dispatch(std::string(this->InputBuffer)); @@ -250,6 +244,13 @@ void Console::Draw() { } } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 50); + if(ImGui::Button("Submit") && !input_focus && this->InputBuffer[0] != '\0' && this->InputBuffer[0] != ' '){ + this->Dispatch(std::string(this->InputBuffer)); + memset(this->InputBuffer, 0, MAX_BUFFER_SIZE); + } + ImGui::SetItemDefaultFocus(); if (input_focus) ImGui::SetKeyboardFocusHere(-1); ImGui::PopItemWidth(); diff --git a/libultraship/libultraship/Cvar.cpp b/libultraship/libultraship/Cvar.cpp index 231308fe7..27d44df80 100644 --- a/libultraship/libultraship/Cvar.cpp +++ b/libultraship/libultraship/Cvar.cpp @@ -14,7 +14,7 @@ extern "C" CVar* CVar_Get(const char* name) { return (it != cvars.end()) ? it->second.get() : nullptr; } -extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) { +extern "C" int32_t CVar_GetS32(const char* name, int32_t defaultValue) { CVar* cvar = CVar_Get(name); if (cvar) { @@ -47,7 +47,7 @@ extern "C" const char* CVar_GetString(const char* name, const char* defaultValue return defaultValue; } -extern "C" void CVar_SetS32(const char* name, s32 value) { +extern "C" void CVar_SetS32(const char* name, int32_t value) { auto& cvar = cvars[name]; if (!cvar) { cvar = std::make_unique(); @@ -74,7 +74,7 @@ extern "C" void CVar_SetString(const char* name, const char* value) { cvar->value.valueStr = ImStrdup(value); } -extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) { +extern "C" void CVar_RegisterS32(const char* name, int32_t defaultValue) { if (!CVar_Get(name)) CVar_SetS32(name, defaultValue); } diff --git a/libultraship/libultraship/Cvar.h b/libultraship/libultraship/Cvar.h index f9583ef0c..1507b519d 100644 --- a/libultraship/libultraship/Cvar.h +++ b/libultraship/libultraship/Cvar.h @@ -1,7 +1,7 @@ #ifndef _CVAR_H #define _CVAR_H -#include +#include typedef enum CVarType { CVAR_TYPE_S32, CVAR_TYPE_FLOAT, CVAR_TYPE_STRING } CVarType; @@ -10,7 +10,7 @@ typedef struct CVar { CVarType type; union { - s32 valueS32; + int32_t valueS32; float valueFloat; const char* valueStr; } value; @@ -23,13 +23,13 @@ extern "C" //#include CVar* CVar_Get(const char* name); -s32 CVar_GetS32(const char* name, s32 defaultValue); +int32_t CVar_GetS32(const char* name, int32_t defaultValue); float CVar_GetFloat(const char* name, float defaultValue); const char* CVar_GetString(const char* name, const char* defaultValue); -void CVar_SetS32(const char* name, s32 value); +void CVar_SetS32(const char* name, int32_t value); void CVar_SetString(const char* name, const char* value); -void CVar_RegisterS32(const char* name, s32 defaultValue); +void CVar_RegisterS32(const char* name, int32_t defaultValue); void CVar_RegisterFloat(const char* name, float defaultValue); void CVar_RegisterString(const char* name, const char* defaultValue); diff --git a/libultraship/libultraship/Environment.cpp b/libultraship/libultraship/Environment.cpp index 7f10c8c44..53d0f330b 100644 --- a/libultraship/libultraship/Environment.cpp +++ b/libultraship/libultraship/Environment.cpp @@ -9,6 +9,7 @@ namespace SohUtils { void saveEnvironmentVar(const std::string& key, const std::string& value) { environmentVars[key] = value; } + std::string getEnvironmentVar(const std::string& key) { return environmentVars[key]; } diff --git a/libultraship/libultraship/GameOverlay.h b/libultraship/libultraship/GameOverlay.h index 605cd5898..c9290390e 100644 --- a/libultraship/libultraship/GameOverlay.h +++ b/libultraship/libultraship/GameOverlay.h @@ -38,5 +38,5 @@ namespace Ship { void LoadFont(const std::string& name, const std::string& path, float fontSize); }; - static bool OverlayCommand(const std::vector& args); + bool OverlayCommand(const std::vector& args); } diff --git a/libultraship/libultraship/GlobalCtx2.cpp b/libultraship/libultraship/GlobalCtx2.cpp index 329644192..5eb449ad3 100644 --- a/libultraship/libultraship/GlobalCtx2.cpp +++ b/libultraship/libultraship/GlobalCtx2.cpp @@ -10,6 +10,8 @@ #include "ModManager.h" #ifdef __APPLE__ #include "OSXFolderManager.h" +#elif defined(__SWITCH__) +#include "SwitchImpl.h" #endif namespace Ship { @@ -72,11 +74,16 @@ namespace Ship { { #ifdef _WIN32 MessageBox(nullptr, L"Main OTR file not found!", L"Uh oh", MB_OK); +#elif defined(__SWITCH__) + printf("Main OTR file not found!\n"); #else SPDLOG_ERROR("Main OTR file not found!"); #endif exit(1); } + #ifdef __SWITCH__ + Ship::Switch::Init(PostInitPhase); + #endif INSTANCE = new ModManager(ResMan); INSTANCE->Init(); } diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index f1f1fd12b..f7288ae3a 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -27,6 +27,16 @@ #include "Lib/spdlog/include/spdlog/common.h" #include "Utils/StringHelper.h" +#if __APPLE__ +#include +#else +#include +#endif + +#ifdef __SWITCH__ +#include "SwitchImpl.h" +#endif + #ifdef ENABLE_OPENGL #include "Lib/ImGui/backends/imgui_impl_opengl3.h" #include "Lib/ImGui/backends/imgui_impl_sdl.h" @@ -127,6 +137,7 @@ namespace SohImGui { void ImGuiWMInit() { switch (impl.backend) { case Backend::SDL: + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1"); ImGui_ImplSDL2_InitForOpenGL(static_cast(impl.sdl.window), impl.sdl.context); break; #if defined(ENABLE_DX11) || defined(ENABLE_DX12) @@ -339,10 +350,17 @@ namespace SohImGui { io = &ImGui::GetIO(); io->ConfigFlags |= ImGuiConfigFlags_DockingEnable; io->Fonts->AddFontDefault(); + #ifdef __SWITCH__ + Ship::Switch::SetupFont(io->Fonts); + #endif lastBackendID = GetBackendID(GlobalCtx2::GetInstance()->GetConfig()); if (CVar_GetS32("gOpenMenuBar", 0) != 1) { + #ifdef __SWITCH__ + SohImGui::overlay->TextDrawNotification(30.0f, true, "Press - to access enhancements menu"); + #else SohImGui::overlay->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu"); + #endif } auto imguiIniPath = Ship::GlobalCtx2::GetPathRelativeToAppDirectory("imgui.ini"); @@ -358,6 +376,9 @@ namespace SohImGui { controller->Init(); ImGuiWMInit(); ImGuiBackendInit(); + #ifdef __SWITCH__ + ImGui::GetStyle().ScaleAllSizes(2); + #endif ModInternal::RegisterHook([] { if (GlobalCtx2::GetInstance()->GetWindow()->IsFullscreen()) @@ -386,7 +407,10 @@ namespace SohImGui { CVar_SetS32("gNewSeedGenerated", 0); CVar_SetS32("gNewFileDropped", 0); CVar_SetString("gDroppedFile", "None"); - // Game::SaveSettings(); + + #ifdef __SWITCH__ + Switch::ApplyOverclock(); + #endif } void Update(EventImpl event) { @@ -734,7 +758,7 @@ namespace SohImGui { const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->WorkPos); - ImGui::SetNextWindowSize(ImVec2(wnd->GetCurrentWidth(), wnd->GetCurrentHeight())); + ImGui::SetNextWindowSize(ImVec2((int) wnd->GetCurrentWidth(), (int) wnd->GetCurrentHeight())); ImGui::SetNextWindowViewport(viewport->ID); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); @@ -757,7 +781,7 @@ namespace SohImGui { ImGui::DockSpace(dockId, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None | ImGuiDockNodeFlags_NoDockingInCentralNode); - if (ImGui::IsKeyPressed(TOGGLE_BTN)) { + if (ImGui::IsKeyPressed(TOGGLE_BTN) || ImGui::IsKeyPressed(TOGGLE_PAD_BTN)) { bool menu_bar = CVar_GetS32("gOpenMenuBar", 0); CVar_SetS32("gOpenMenuBar", !menu_bar); needs_save = true; @@ -791,8 +815,13 @@ namespace SohImGui { if (ImGui::BeginMenuBar()) { if (DefaultAssets.contains("Game_Icon")) { + #ifdef __SWITCH__ + ImVec2 iconSize = ImVec2(20.0f, 20.0f); + #else + ImVec2 iconSize = ImVec2(16.0f, 16.0f); + #endif ImGui::SetCursorPos(ImVec2(5, 2.5f)); - ImGui::Image(GetTextureByID(DefaultAssets["Game_Icon"]->textureId), ImVec2(16.0f, 16.0f)); + ImGui::Image(GetTextureByID(DefaultAssets["Game_Icon"]->textureId), iconSize); ImGui::SameLine(); ImGui::SetCursorPos(ImVec2(25, 0)); } @@ -931,8 +960,6 @@ namespace SohImGui { EXPERIMENTAL(); ImGui::Text("Texture Filter (Needs reload)"); EnhancementCombobox("gTextureFilter", filters, 3, 0); - GfxRenderingAPI* gapi = gfx_get_current_rendering_api(); - gapi->set_texture_filter((FilteringMode)CVar_GetS32("gTextureFilter", 0)); overlay->DrawSettings(); ImGui::EndMenu(); } @@ -1235,8 +1262,16 @@ namespace SohImGui { const char* fps_cvar = "gInterpolationFPS"; { - int val = CVar_GetS32(fps_cvar, 20); - val = MAX(MIN(val, 250), 20); + #ifdef __SWITCH__ + int minFps = 20; + int maxFps = 60; + #else + int minFps = 20; + int maxFps = 250; + #endif + + int val = CVar_GetS32(fps_cvar, minFps); + val = MAX(MIN(val, maxFps), 20); int fps = val; if (fps == 20) @@ -1258,7 +1293,7 @@ namespace SohImGui { ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); - if (ImGui::SliderInt("##FPSInterpolation", &val, 20, 250, "", ImGuiSliderFlags_AlwaysClamp)) + if (ImGui::SliderInt("##FPSInterpolation", &val, minFps, maxFps, "", ImGuiSliderFlags_AlwaysClamp)) { if (val > 250) { @@ -1316,6 +1351,23 @@ namespace SohImGui { EnhancementCheckbox("Free Camera", "gFreeCamera"); Tooltip("Enables camera control\nNote: You must remap C buttons off of\nthe right stick in the controller\nconfig menu, and map the camera stick\nto the right stick."); + #ifdef __SWITCH__ + int slot = CVar_GetS32("gSwitchPerfMode", (int)SwitchProfiles::STOCK); + ImGui::Text("Switch performance mode"); + if (ImGui::BeginCombo("##perf", SWITCH_CPU_PROFILES[slot])) { + for (int sId = 0; sId <= SwitchProfiles::POWERSAVINGM3; sId++) { + if (ImGui::Selectable(SWITCH_CPU_PROFILES[sId], sId == slot)) { + INFO("Profile:: %s", SWITCH_CPU_PROFILES[sId]); + CVar_SetS32("gSwitchPerfMode", sId); + Switch::ApplyOverclock(); + needs_save = true; + } + + } + ImGui::EndCombo(); + } + #endif + ImGui::EndMenu(); } @@ -1430,6 +1482,8 @@ namespace SohImGui { ImGui::Text("Platform: Windows"); #elif __APPLE__ ImGui::Text("Platform: macOS"); +#elif defined(__SWITCH__) + ImGui::Text("Platform: Nintendo Switch"); #else ImGui::Text("Platform: Linux"); #endif diff --git a/libultraship/libultraship/InputEditor.cpp b/libultraship/libultraship/InputEditor.cpp index 25e641a06..eb191cc20 100644 --- a/libultraship/libultraship/InputEditor.cpp +++ b/libultraship/libultraship/InputEditor.cpp @@ -9,7 +9,6 @@ namespace Ship { - extern "C" uint8_t __enableGameInput; #define SEPARATION() ImGui::Dummy(ImVec2(0, 5)) void InputEditor::Init() { @@ -116,7 +115,11 @@ namespace Ship { DrawButton("Z", BTN_Z); DrawButton("START", BTN_START); SEPARATION(); + #ifdef __SWITCH__ + SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 56.0f); + #else SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 48.0f); + #endif ImGui::SameLine(); SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20)); DrawButton("Up", BTN_DUP); @@ -124,7 +127,11 @@ namespace Ship { DrawButton("Left", BTN_DLEFT); DrawButton("Right", BTN_DRIGHT); SEPARATION(); + #ifdef __SWITCH__ + SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 122.0f); + #else SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 94.0f); + #endif ImGui::SameLine(); SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20)); DrawButton("Up", BTN_STICKUP); @@ -148,7 +155,11 @@ namespace Ship { } else { ImGui::Dummy(ImVec2(0, 6)); } - SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f); + #ifdef __SWITCH__ + SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 52.0f); + #else + SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f); + #endif ImGui::SameLine(); if (!IsKeyboard) { @@ -174,44 +185,52 @@ namespace Ship { ImGui::InputFloat("##MSensitivity", &profile.Thresholds[SENSITIVITY], 1.0f, 0.0f, "%.0f"); ImGui::PopItemWidth(); ImGui::EndChild(); + #ifdef __SWITCH__ + SohImGui::EndGroupPanel(43.0f); + #else SohImGui::EndGroupPanel(14.0f); + #endif } if(Backend->CanGyro()) { ImGui::SameLine(); SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20)); - float cursorX = ImGui::GetCursorPosX() + 5; - ImGui::SetCursorPosX(cursorX); - ImGui::Checkbox("Enable Gyro", &profile.UseGyro); - ImGui::SetCursorPosX(cursorX); - ImGui::Text("Gyro Sensitivity: %d%%", static_cast(100.0f * profile.Thresholds[GYRO_SENSITIVITY])); - ImGui::PushItemWidth(135.0f); - ImGui::SetCursorPosX(cursorX); - ImGui::SliderFloat("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0.0f, 1.0f, ""); - ImGui::PopItemWidth(); - ImGui::Dummy(ImVec2(0, 1)); - ImGui::SetCursorPosX(cursorX); - if (ImGui::Button("Recalibrate Gyro##RGyro")) { - profile.Thresholds[DRIFT_X] = 0.0f; - profile.Thresholds[DRIFT_Y] = 0.0f; - } - ImGui::SetCursorPosX(cursorX); - DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->wGyroY, 10.0f * Backend->wGyroX)); + float cursorX = ImGui::GetCursorPosX() + 5; + ImGui::SetCursorPosX(cursorX); + ImGui::Checkbox("Enable Gyro", &profile.UseGyro); + ImGui::SetCursorPosX(cursorX); + ImGui::Text("Gyro Sensitivity: %d%%", static_cast(100.0f * profile.Thresholds[GYRO_SENSITIVITY])); + ImGui::PushItemWidth(135.0f); + ImGui::SetCursorPosX(cursorX); + ImGui::SliderFloat("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0.0f, 1.0f, ""); + ImGui::PopItemWidth(); + ImGui::Dummy(ImVec2(0, 1)); + ImGui::SetCursorPosX(cursorX); + if (ImGui::Button("Recalibrate Gyro##RGyro")) { + profile.Thresholds[DRIFT_X] = 0.0f; + profile.Thresholds[DRIFT_Y] = 0.0f; + } + ImGui::SetCursorPosX(cursorX); + DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->wGyroY, 10.0f * Backend->wGyroX)); - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - ImGui::BeginChild("##GyInput", ImVec2(90, 85), false); - ImGui::Text("Drift X"); - ImGui::PushItemWidth(80); - ImGui::InputFloat("##GDriftX", &profile.Thresholds[DRIFT_X], 1.0f, 0.0f, "%.1f"); - ImGui::PopItemWidth(); - ImGui::Text("Drift Y"); - ImGui::PushItemWidth(80); - ImGui::InputFloat("##GDriftY", &profile.Thresholds[DRIFT_Y], 1.0f, 0.0f, "%.1f"); - ImGui::PopItemWidth(); - ImGui::EndChild(); + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + ImGui::BeginChild("##GyInput", ImVec2(90, 85), false); + ImGui::Text("Drift X"); + ImGui::PushItemWidth(80); + ImGui::InputFloat("##GDriftX", &profile.Thresholds[DRIFT_X], 1.0f, 0.0f, "%.1f"); + ImGui::PopItemWidth(); + ImGui::Text("Drift Y"); + ImGui::PushItemWidth(80); + ImGui::InputFloat("##GDriftY", &profile.Thresholds[DRIFT_Y], 1.0f, 0.0f, "%.1f"); + ImGui::PopItemWidth(); + ImGui::EndChild(); + #ifdef __SWITCH__ + SohImGui::EndGroupPanel(46.0f); + #else SohImGui::EndGroupPanel(14.0f); + #endif } ImGui::SameLine(); @@ -227,7 +246,11 @@ namespace Ship { SohImGui::EndGroupPanel(); ImGui::SetCursorPosX(cursor.x); + #ifdef __SWITCH__ + ImGui::SetCursorPosY(cursor.y + 167); + #else ImGui::SetCursorPosY(cursor.y + 120); + #endif SohImGui::BeginGroupPanel("Options", ImVec2(158, 20)); float cursorX = ImGui::GetCursorPosX() + 5; ImGui::SetCursorPosX(cursorX); @@ -245,16 +268,21 @@ namespace Ship { } void InputEditor::DrawHud() { - - __enableGameInput = true; - if (!this->Opened) { BtnReading = -1; CVar_SetS32("gControllerConfigurationEnabled", 0); return; } - ImGui::SetNextWindowSizeConstraints(ImVec2(641, 250), ImVec2(1200, 290)); +#ifdef __SWITCH__ + ImVec2 minSize = ImVec2(641, 250); + ImVec2 maxSize = ImVec2(2200, 505); +#else + ImVec2 minSize = ImVec2(641, 250); + ImVec2 maxSize = ImVec2(1200, 290); +#endif + + ImGui::SetNextWindowSizeConstraints(minSize, maxSize); //OTRTODO: Disable this stupid workaround ( ReadRawPress() only works when the window is on the main viewport ) ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID); ImGui::Begin("Controller Configuration", &this->Opened, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp index 43dae33ff..0576583d8 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_glx.cpp @@ -1,4 +1,4 @@ -#ifdef __linux__ +#if defined(__linux__) && defined(X11_SUPPORTED) #include #include #include @@ -156,6 +156,7 @@ static struct { Atom atom_wm_delete_window; bool is_fullscreen; + bool is_running = true; void (*on_fullscreen_changed)(bool is_now_fullscreen); int keymap[256]; @@ -399,7 +400,7 @@ static void gfx_glx_set_keyboard_callbacks(bool (*on_key_down)(int scancode), bo } static void gfx_glx_main_loop(void (*run_one_game_iter)(void)) { - while (1) { + while (glx.is_running) { run_one_game_iter(); } } @@ -440,7 +441,7 @@ static void gfx_glx_handle_events(void) { } } if (xev.type == ClientMessage && (Atom)xev.xclient.data.l[0] == glx.atom_wm_delete_window) { - exit(0); + glx.is_running = false; } } } diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp index d79c3aa8f..ad683e047 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp @@ -31,6 +31,9 @@ #elif __APPLE__ #include #include +#elif __SWITCH__ +#include +#include #else #include #include @@ -643,6 +646,10 @@ static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); } +#ifdef __SWITCH__ +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 +#endif + static uint32_t gfx_cm_to_opengl(uint32_t val) { switch (val) { case G_TX_NOMIRROR | G_TX_CLAMP: @@ -710,9 +717,9 @@ static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_ } static void gfx_opengl_init(void) { -//#if FOR_WINDOWS +#ifndef __SWITCH__ glewInit(); -//#endif +#endif glGenBuffers(1, &opengl_vbo); glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo); @@ -840,9 +847,7 @@ void gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) { if (noise_scale != 0.0f) { current_noise_scale = 1.0f / noise_scale; } - glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo); - current_framebuffer = fb_id; } diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp index 0a04c9580..dd5f9bf95 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp @@ -1206,8 +1206,8 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo rdp.viewport_or_scissor_changed = false; } - uint64_t cc_id = rdp.combine_mode; + uint64_t cc_id = rdp.combine_mode; bool use_alpha = (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16); bool use_fog = (rdp.other_mode_l >> 30) == G_BL_CLR_FOG; bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA; diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index cb0d7a7f0..2576bc17b 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -15,6 +15,11 @@ #include "SDL_opengl.h" #elif __APPLE__ #include +#elif __SWITCH__ +#include +#include +#include +#include "../../SwitchImpl.h" #else #include #define GL_GLEXT_PROTOTYPES 1 @@ -42,6 +47,7 @@ static int vsync_enabled = 0; static int window_width = DESIRED_SCREEN_WIDTH; static int window_height = DESIRED_SCREEN_HEIGHT; static bool fullscreen_state; +static bool is_running = true; static void (*on_fullscreen_changed_callback)(bool is_now_fullscreen); static bool (*on_key_down_callback)(int scancode); static bool (*on_key_up_callback)(int scancode); @@ -146,31 +152,43 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen, uint32 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); +#elif defined(__SWITCH__) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif #ifdef _WIN32 timer = CreateWaitableTimer(nullptr, false, nullptr); #endif - //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - //SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); - char title[512]; int len = sprintf(title, "%s (%s)", game_name, GFX_API_NAME); - window_width = width; - window_height = height; +#ifdef __SWITCH__ + // For Switch we need to set the window width before creating the window + Ship::Switch::GetDisplaySize(&window_width, &window_height); +#endif wnd = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_width, window_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + +#ifndef __SWITCH__ SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); if (start_in_fullscreen) { set_fullscreen(true, false); } +#endif ctx = SDL_GL_CreateContext(wnd); +#ifdef __SWITCH__ + if(!gladLoadGLLoader(SDL_GL_GetProcAddress)){ + printf("Failed to initialize glad\n"); + } +#endif + SDL_GL_SetSwapInterval(1); SohImGui::WindowImpl window_impl; @@ -211,14 +229,21 @@ static void gfx_sdl_set_keyboard_callbacks(bool (*on_key_down)(int scancode), bo } static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) { - while (1) - { +#ifdef __SWITCH__ + while(Ship::Switch::IsRunning()) { +#else + while(is_running) { +#endif run_one_game_iter(); } +#ifdef __SWITCH__ + Ship::Switch::Exit(); +#endif + ModInternal::ExecuteHooks(); } static void gfx_sdl_get_dimensions(uint32_t *width, uint32_t *height) { - *width = window_width; + *width = window_width; *height = window_height; } @@ -271,7 +296,11 @@ static void gfx_sdl_handle_events(void) { #endif case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { - SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); + #ifdef __SWITCH__ + Ship::Switch::GetDisplaySize(&window_width, &window_height); + #else + SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); + #endif } break; case SDL_DROPFILE: @@ -303,7 +332,7 @@ static inline void sync_framerate_with_timer(void) { const int64_t next = previous_time + 10 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR; const int64_t left = next - t; if (left > 0) { -#if defined __linux__ || defined __APPLE__ +#ifndef _WIN32 const timespec spec = { 0, left * 100 }; nanosleep(&spec, nullptr); #else diff --git a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp index b7587d0e7..6d4483a91 100644 --- a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp +++ b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp @@ -132,6 +132,10 @@ #else #include // Use GL ES 3 #endif +#elif defined(__SWITCH__) +#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM +#define GL_GLEXT_PROTOTYPES 1 +#include #elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. // Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w. diff --git a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp index 931660a9d..8cbdceac5 100644 --- a/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp +++ b/libultraship/libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp @@ -65,6 +65,7 @@ #include "imgui.h" #include "imgui_impl_sdl.h" +#include "imgui_internal.h" // SDL // (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) @@ -77,7 +78,7 @@ #include #endif -#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) +#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) && !defined(__SWITCH__) #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1 #else #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 @@ -105,6 +106,7 @@ struct ImGui_ImplSDL2_Data char* ClipboardTextData; bool MouseCanUseGlobalState; bool UseVulkan; + bool ShowingVirtualKeyboard; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -269,6 +271,23 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGuiInputTextState* state = ImGui::GetInputTextState(ImGui::GetActiveID()); + + #ifdef __SWITCH__ + if (io.WantTextInput) { + if (!bd->ShowingVirtualKeyboard) { + state->ClearText(); + + bd->ShowingVirtualKeyboard = true; + SDL_StartTextInput(); + } + } else { + if (bd->ShowingVirtualKeyboard) { + bd->ShowingVirtualKeyboard = false; + SDL_StopTextInput(); + } + } + #endif switch (event->type) { @@ -411,6 +430,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = (void*)window; +#if defined(_WIN32) || defined(__APPLE__) SDL_SysWMinfo info; SDL_VERSION(&info.version); if (SDL_GetWindowWMInfo(window, &info)) @@ -421,6 +441,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void main_viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; #endif } +#endif // Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event. // Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered. @@ -583,8 +604,11 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() static void ImGui_ImplSDL2_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) - return; + + // Remove this check because we always want to be able to trigger the menu via controller + // The ImGuiConfigFlags_NavEnableGamepad is still separately used by ImGui for enabling imgui navigation + // if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + // return; // Get gamepad io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; @@ -600,10 +624,17 @@ static void ImGui_ImplSDL2_UpdateGamepads() const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); +#ifdef __SWITCH__ + MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_B); // Xbox A, PS Cross + MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_A); // Xbox B, PS Circle + MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_Y); // Xbox X, PS Square + MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_X); // Xbox Y, PS Triangle +#else MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle +#endif MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); @@ -757,6 +788,7 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) SDL_GL_MakeCurrent(vd->Window, backup_context); viewport->PlatformHandle = (void*)vd->Window; +#if defined(_WIN32) || defined(__APPLE__) SDL_SysWMinfo info; SDL_VERSION(&info.version); if (SDL_GetWindowWMInfo(vd->Window, &info)) @@ -767,6 +799,7 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; #endif } +#endif } static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport) diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index 3d02a8614..398ce1944 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -4,6 +4,10 @@ #include "Window.h" #include +#ifdef _MSC_VER +#define strdup _strdup +#endif + extern "C" uint8_t __osMaxControllers; namespace Ship { @@ -25,11 +29,16 @@ namespace Ship { char GuidBuf[33]; SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf)); - GUID = std::string(GuidBuf); Cont = NewCont; wCamX = 0; wCamY = 0; - +#ifdef __SWITCH__ + GUID = StringHelper::Sprintf("%s:%d", GuidBuf, physicalSlot); + ControllerName = StringHelper::Sprintf("%s #%d", SDL_GameControllerNameForIndex(physicalSlot), physicalSlot + 1); +#else + GUID = std::string(GuidBuf); + ControllerName = std::string(SDL_GameControllerNameForIndex(physicalSlot)); +#endif return true; } @@ -441,7 +450,7 @@ namespace Ship { } const char* SDLController::GetControllerName() { - return SDL_GameControllerNameForIndex(physicalSlot); + return strdup(ControllerName.c_str()); } void SDLController::CreateDefaultBinding(int32_t slot) { diff --git a/libultraship/libultraship/SDLController.h b/libultraship/libultraship/SDLController.h index ae239a2f1..e5d24c946 100644 --- a/libultraship/libultraship/SDLController.h +++ b/libultraship/libultraship/SDLController.h @@ -31,6 +31,7 @@ namespace Ship { void CreateDefaultBinding(int32_t slot) override; private: + std::string ControllerName = "Unknown"; SDL_GameController* Cont; int physicalSlot; bool supportsGyro; diff --git a/libultraship/libultraship/SwitchImpl.cpp b/libultraship/libultraship/SwitchImpl.cpp new file mode 100644 index 000000000..321b40648 --- /dev/null +++ b/libultraship/libultraship/SwitchImpl.cpp @@ -0,0 +1,286 @@ +#ifdef __SWITCH__ +#include "SwitchImpl.h" +#include +#include +#include "SwitchPerformanceProfiles.h" +#include "Cvar.h" +#include "Hooks.h" + +extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue); +extern "C" void CVar_SetS32(const char* name, s32 value); + +#define DOCKED_MODE 1 +#define HANDHELD_MODE 0 + +static AppletHookCookie applet_hook_cookie; +static bool isRunning = true; +static bool hasFocus = true; + +void DetectAppletMode(); + +static void on_applet_hook(AppletHookType hook, void *param); + +void Ship::Switch::Init(SwitchPhase phase){ + switch(phase){ + case PreInitPhase: + DetectAppletMode(); + break; + case PostInitPhase: + appletInitializeGamePlayRecording(); + #ifdef DEBUG + socketInitializeDefault(); + nxlinkStdio(); + #endif + appletSetGamePlayRecordingState(true); + appletHook(&applet_hook_cookie, on_applet_hook, NULL); + appletSetFocusHandlingMode(AppletFocusHandlingMode_NoSuspend); + if (!hosversionBefore(8, 0, 0)) { + clkrstInitialize(); + } + break; + } +} + +void Ship::Switch::Exit(){ +#ifdef DEBUG + socketExit(); +#endif + clkrstExit(); + appletSetGamePlayRecordingState(false); +} + +void Ship::Switch::SetupFont(ImFontAtlas* fonts) { + plInitialize(PlServiceType_System); + static PlFontData stdFontData, extFontData; + + PlFontData fonts_std; + PlFontData fonts_ext; + + plGetSharedFontByType(&fonts_std, PlSharedFontType_Standard); + plGetSharedFontByType(&fonts_ext, PlSharedFontType_NintendoExt); + + ImFontConfig config; + config.FontDataOwnedByAtlas = false; + + strcpy(config.Name, "Nintendo Standard"); + fonts->AddFontFromMemoryTTF (fonts_std.address, fonts_std.size, 24.0f, &config, fonts->GetGlyphRangesCyrillic()); + + strcpy(config.Name, "Nintendo Ext"); + static const ImWchar ranges[] = + { + 0xE000, 0xE06B, + 0xE070, 0xE07E, + 0xE080, 0xE099, + 0xE0A0, 0xE0BA, + 0xE0C0, 0xE0D6, + 0xE0E0, 0xE0F5, + 0xE100, 0xE105, + 0xE110, 0xE116, + 0xE121, 0xE12C, + 0xE130, 0xE13C, + 0xE140, 0xE14D, + 0xE150, 0xE153, + 0, + }; + + fonts->AddFontFromMemoryTTF (fonts_ext.address, fonts_ext.size, 24.0f, &config, ranges); + fonts->Build (); + + plExit(); +} + +bool Ship::Switch::IsRunning(){ + return isRunning; +} + +void Ship::Switch::GetDisplaySize(int *width, int *height) { + switch (appletGetOperationMode()) { + case DOCKED_MODE: + *width = 1920; + *height = 1080; + break; + case HANDHELD_MODE: + *width = 1280; + *height = 720; + break; + } +} + +void Ship::Switch::ApplyOverclock(void) { + SwitchProfiles perfMode = (SwitchProfiles) CVar_GetS32("gSwitchPerfMode", (int) Ship::MAXIMUM); + + if (perfMode >= 0 && perfMode <= Ship::POWERSAVINGM3) { + if (hosversionBefore(8, 0, 0)) { + pcvSetClockRate(PcvModule_CpuBus, SWITCH_CPU_SPEEDS_VALUES[ perfMode ]); + } else { + ClkrstSession session = {0}; + clkrstOpenSession(&session, PcvModuleId_CpuBus, 3); + clkrstSetClockRate(&session, SWITCH_CPU_SPEEDS_VALUES[ perfMode ]); + clkrstCloseSession(&session); + } + } +} + +struct Star { + SDL_Rect* rect; + float speed; + int layer; + int8_t color[3]; +}; + +std::vector stars; + +void Ship::Switch::PrintErrorMessageToScreen(const char *str, ...) { + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + return; + + int width, height; + Uint64 now, last, deltaTime; + GetDisplaySize(&width, &height); + + SDL_Window* win = SDL_CreateWindow("Switch-Error", 0, 0, width, height, 0); + SDL_Renderer* renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED); + + va_list args; + va_start(args, str); + vprintf(str, args); + va_end(args); + + int layers = 9; + + for(int layer = 0; layer < layers; layer++) { + for(int i = 0; i < 100; i++) { + srand(time(0)); + + int brightness = 50 - layer * (rand() * 5); + SDL_Rect rect; + rect.x = rand() % width; + rect.y = i*i; + rect.w = rand() % 20; + rect.h = rand() % 20; + + stars.push_back(new Star{ + &rect, + 0.03f, + layer, + { + 120 + brightness, + 120 + brightness, + 120 + brightness + } + }); + } + } + + while(appletMainLoop()){ + SDL_Event e; + if ( SDL_PollEvent(&e) ) { + if (e.type == SDL_QUIT) + break; + } + + last = now; + now = SDL_GetPerformanceCounter(); + + deltaTime = (double)((now - last) * 1000 / (double) SDL_GetPerformanceFrequency() ); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + + for(int i = 0; i < stars.size(); i++){ + Star* star = stars[i]; + + if(star->rect->x >= width){ + star->rect->x = -star->rect->w; + } + + star->rect->x += 1; + // star->rect->y += (cos((star->rect->x / star->layer)) * .9f ) / 16; + SDL_SetRenderDrawColor(renderer, star->color[0], star->color[1], star->color[2], 255); + SDL_RenderFillRect( renderer, star->rect ); + } + + SDL_RenderPresent(renderer); + SDL_Delay(0); + } + +} + +static void on_applet_hook(AppletHookType hook, void *param) { + AppletFocusState focus_state; + + /* Exit request */ + switch (hook) { + case AppletHookType_OnExitRequest: + isRunning = false; + break; + + /* Focus state*/ + case AppletHookType_OnFocusState: + focus_state = appletGetFocusState(); + hasFocus = focus_state == AppletFocusState_InFocus; + + if (!hasFocus) { + if (hosversionBefore(8, 0, 0)) { + pcvSetClockRate(PcvModule_CpuBus, SWITCH_CPU_SPEEDS_VALUES[ Ship::STOCK ]); + } else { + ClkrstSession session = {0}; + clkrstOpenSession(&session, PcvModuleId_CpuBus, 3); + clkrstSetClockRate(&session, SWITCH_CPU_SPEEDS_VALUES[ Ship::STOCK ]); + clkrstCloseSession(&session); + } + } else + Ship::Switch::ApplyOverclock(); + break; + + /* Performance mode */ + case AppletHookType_OnPerformanceMode: + Ship::Switch::ApplyOverclock(); + break; + default: break; + } +} + +const char* RandomTexts[] = { + "Psst, don't forget to blame Melon", + "Potsanity when?", + "Why are you acting so random?", + "Enough! My ship sails in the morning", + "Do you want 2 or 7 of those?", + "Lamp oil, rope, bombs you want it, it's yours my friend as long as you have enough rupees", + "You can build it yourself", + "Descargar para android", + "Made with <3 by the Harbour Masters!", + "They say that Kenix is not a developer", + "Squadala we're off", + "They say one once saw an equals not get set equals", + "This is the port all true gamers dock at" + "Enhancements? Times Savers? Cheats? You want them? They're yours my friend!", + "They say you gotta have the BIIIIG salad", + "They say Louis stopped working on the imports so he can focus on the exports", + "They say ZAPD is good software", +}; + +void DetectAppletMode() { + AppletType at = appletGetAppletType(); + if (at == AppletType_Application || at == AppletType_SystemApplication) + return; + + srand(time(0)); + Ship::Switch::PrintErrorMessageToScreen( + "\x1b[2;2HYou've launched the Ship while in Applet mode." + "\x1b[4;2HPlease relaunch while in full-memory mode." + "\x1b[5;2HHold R when opening any game to enter HBMenu." + "\x1b[44;2H%s." + , RandomTexts[rand() % 25]); +} + +void Ship::Switch::ThrowMissingOTR(std::string OTRPath){ + Ship::Switch::PrintErrorMessageToScreen( + "\x1b[2;2HYou've launched the Ship without the OTR file." + "\x1b[4;2HPlease relaunch making sure %s exists." + "\x1b[44;2H%s." + , OTRPath.c_str(), RandomTexts[rand() % 25]); +} +#endif \ No newline at end of file diff --git a/libultraship/libultraship/SwitchImpl.h b/libultraship/libultraship/SwitchImpl.h new file mode 100644 index 000000000..af592413a --- /dev/null +++ b/libultraship/libultraship/SwitchImpl.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "Lib/ImGui/imgui.h" +#include "SwitchPerformanceProfiles.h" + +namespace Ship { + enum SwitchProfiles { + MAXIMUM, + HIGH, + BOOST, + STOCK, + POWERSAVINGM1, + POWERSAVINGM2, + POWERSAVINGM3 + }; + + enum SwitchPhase { + PreInitPhase, + PostInitPhase + }; + + class Switch { + public: + static void Init(SwitchPhase phase); + static void Exit(); + static void SetupFont(ImFontAtlas* fonts); + static bool IsRunning(); + static void GetDisplaySize(int *width, int *height); + static void ApplyOverclock(); + static void ThrowMissingOTR(std::string OTRPath); + static void PrintErrorMessageToScreen(const char *str, ...); + }; +}; \ No newline at end of file diff --git a/libultraship/libultraship/SwitchPerformanceProfiles.h b/libultraship/libultraship/SwitchPerformanceProfiles.h new file mode 100644 index 000000000..1cb930c0a --- /dev/null +++ b/libultraship/libultraship/SwitchPerformanceProfiles.h @@ -0,0 +1,21 @@ +#pragma once + +static const char *SWITCH_CPU_PROFILES[] = { + "Maximum Performance", + "High Performance", + "Boost Performance", + "Stock Performance", + "Powersaving Mode 1", + "Powersaving Mode 2", + "Powersaving Mode 3", +}; + +static unsigned SWITCH_CPU_SPEEDS_VALUES[] = { + 1785000000, + 1581000000, + 1224000000, + 1020000000, + 918000000, + 816000000, + 714000000 +}; \ No newline at end of file diff --git a/libultraship/libultraship/Window.cpp b/libultraship/libultraship/Window.cpp index 9d28ecf5e..9957ebc48 100644 --- a/libultraship/libultraship/Window.cpp +++ b/libultraship/libultraship/Window.cpp @@ -28,6 +28,7 @@ #include #include "Hooks.h" #include "Console.h" +#include "Cvar.h" #include @@ -35,7 +36,6 @@ extern "C" { struct OSMesgQueue; uint8_t __osMaxControllers = MAXCONTROLLERS; - uint8_t __enableGameInput = 1; int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status) { *controllerBits = 0; @@ -45,6 +45,7 @@ extern "C" { exit(EXIT_FAILURE); } + #ifndef __SWITCH__ const char* controllerDb = "gamecontrollerdb.txt"; int mappingsAdded = SDL_GameControllerAddMappingsFromFile(controllerDb); if (mappingsAdded >= 0) { @@ -52,6 +53,7 @@ extern "C" { } else { SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError()); } + #endif Ship::Window::ControllerApi->Init(controllerBits); @@ -72,7 +74,7 @@ extern "C" { pad->gyro_x = 0; pad->gyro_y = 0; - if (__enableGameInput) { + if (!CVar_GetS32("gOpenMenuBar", 0)) { Ship::Window::ControllerApi->WriteToPad(pad); } @@ -302,7 +304,6 @@ namespace Ship { void Window::MainLoop(void (*MainFunction)(void)) { WmApi->main_loop(MainFunction); } - bool Window::KeyUp(int32_t dwScancode) { std::shared_ptr pConf = GlobalCtx2::GetInstance()->GetConfig(); @@ -314,7 +315,7 @@ namespace Ship { //if (dwScancode == Ship::stoi(Conf["KEYBOARD SHORTCUTS"]["KEY_CONSOLE"])) { // ToggleConsole(); //} - + lastScancode = -1; bool bIsProcessed = false; diff --git a/libultraship/libultraship/WindowShim.cpp b/libultraship/libultraship/WindowShim.cpp index 4469c5c29..ca9357575 100644 --- a/libultraship/libultraship/WindowShim.cpp +++ b/libultraship/libultraship/WindowShim.cpp @@ -22,7 +22,7 @@ void SetWindowManager(struct GfxWindowManagerAPI** WmApi, struct GfxRenderingAPI // First set default #ifdef ENABLE_OPENGL *RenderingApi = &gfx_opengl_api; - #if defined(__linux__) + #if defined(__linux__) && defined(X11_SUPPORTED) // LINUX_TODO: // *WmApi = &gfx_glx; *WmApi = &gfx_sdl; @@ -51,7 +51,7 @@ void SetWindowManager(struct GfxWindowManagerAPI** WmApi, struct GfxRenderingAPI *RenderingApi = &gfx_opengl_api; *WmApi = &gfx_sdl; } -#ifdef __linux__ +#if defined(__linux__) && defined(X11_SUPPORTED) if (gfx_backend == "glx") { *RenderingApi = &gfx_opengl_api; *WmApi = &gfx_glx; diff --git a/libultraship/libultraship/libultraship.vcxproj b/libultraship/libultraship/libultraship.vcxproj index 920f6442f..9c759f85a 100644 --- a/libultraship/libultraship/libultraship.vcxproj +++ b/libultraship/libultraship/libultraship.vcxproj @@ -450,12 +450,6 @@ - - - {02d10590-9542-3f55-aaf8-6055677e2a2a} - false - - diff --git a/soh/Makefile b/soh/Makefile index b05321a60..2c0f9ff31 100644 --- a/soh/Makefile +++ b/soh/Makefile @@ -179,7 +179,7 @@ all: $(MAKE) $(TARGET) setup: - cd ../OTRExporter && python3 extract_baserom.py + cd ../OTRExporter $(MAKE) mpq mpq: diff --git a/soh/Makefile.switch b/soh/Makefile.switch new file mode 100644 index 000000000..10eaaebab --- /dev/null +++ b/soh/Makefile.switch @@ -0,0 +1,280 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional) +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +# +# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .json +# - config.json +# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead +# of a homebrew executable (.nro). This is intended to be used for sysmodules. +# NACP building is skipped as well. +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := switch +DATA := +INCLUDES := \ + . \ + assets \ + build \ + include \ + src \ + ../ZAPDTR/ZAPDUtils \ + ../libultraship/libultraship \ + ../libultraship/libultraship/Lib/spdlog/include \ + ../libultraship/libultraship/Lib/Fast3D/U64 \ + ../libultraship/libultraship/Lib/Fast3D/U64/PR + +#------------------------------------------------------------------------------- +# source files +#------------------------------------------------------------------------------- +SOURCEFILES_C := \ + $(shell find soh -type f -name "*.c") \ + $(shell find src/boot -type f -name "*.c") \ + $(shell find src/buffers -type f -name "*.c") \ + $(shell find src/code -type f -name "*.c") \ + $(shell find src/overlays -type f -name "*.c") \ + src/libultra/gu/coss.c \ + src/libultra/gu/guLookAt.c \ + src/libultra/gu/guLookAtHilite.c \ + src/libultra/gu/guPerspectiveF.c \ + src/libultra/gu/guPosition.c \ + src/libultra/gu/guS2DInitBg.c \ + src/libultra/gu/ortho.c \ + src/libultra/gu/rotate.c \ + src/libultra/gu/sins.c \ + src/libultra/gu/sintable.c \ + src/libultra/libc/sprintf.c + +SOURCEFILES_CPP := \ + $(shell find soh -type f -name "*.cpp") +#--------------------------------------------------------------------------------- +# app info +#--------------------------------------------------------------------------------- + +APP_TITLE := Ship of Harkinian +APP_AUTHOR := Harbour Masters +APP_VERSION := Rachael-Alfa + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE -ffast-math -O3 + +CFLAGS := -ffunction-sections \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -D__SWITCH__ \ + -DSPDLOG_NO_THREAD_ID \ + -DSTBI_NO_THREAD_LOCALS \ + `sdl2-config --cflags` + +CXXFLAGS := $(CFLAGS) -std=gnu++20 -fpermissive +CFLAGS += -std=gnu11 + +# disable some warnings +CFLAGS += -Wno-incompatible-pointer-types -Wno-int-conversion \ + -Wno-builtin-declaration-mismatch -Wno-implicit-function-declaration \ + -Wno-stringop-overflow -Wno-discarded-qualifiers -Wno-switch-unreachable + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +STATIC_LIBS := $(SOH_TOP_DIR)/libultraship/lib/libultraship.a \ + $(SOH_TOP_DIR)/ZAPDTR/ZAPDUtils/lib/libZAPDUtils.a \ + $(SOH_TOP_DIR)/ZAPDTR/ZAPDUtils/lib/libZAPDUtils.a \ + $(SOH_TOP_DIR)/StormLib/nxbuild/libstorm.a \ + +LIBS := -L$(SOH_TOP_DIR)/StormLib/nxbuild/ -lultraship -lZAPDUtils -lstorm -lz -lbz2 -lnx -lglad -lglapi -ldrm_nouveau -lm `sdl2-config --libs` + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) $(SOH_TOP_DIR)/StormLib/nxbuild $(SOH_TOP_DIR)/libultraship $(SOH_TOP_DIR)/ZAPDTR/ZAPDUtils + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach sf,$(SOURCEFILES_C),$(CURDIR)/$(dir $(sf))) \ + $(foreach sf,$(SOURCEFILES_CPP),$(CURDIR)/$(dir $(sf))) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) \ + $(foreach f,$(SOURCEFILES_C),$(notdir $(f))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) \ + $(foreach f,$(SOURCEFILES_CPP),$(notdir $(f))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(CONFIG_JSON)),) + jsons := $(wildcard *.json) + ifneq (,$(findstring $(TARGET).json,$(jsons))) + export APP_JSON := $(TOPDIR)/$(TARGET).json + else + ifneq (,$(findstring config.json,$(jsons))) + export APP_JSON := $(TOPDIR)/config.json + endif + endif +else + export APP_JSON := $(TOPDIR)/$(CONFIG_JSON) +endif + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.jpg) + ifneq (,$(findstring $(TARGET).jpg,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).jpg + else + ifneq (,$(findstring icon.jpg,$(icons))) + export APP_ICON := $(TOPDIR)/icon.jpg + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_ICON)),) + export NROFLAGS += --icon=$(APP_ICON) +endif + +ifeq ($(strip $(NO_NACP)),) + export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp +endif + +ifneq ($(APP_TITLEID),) + export NACPFLAGS += --titleid=$(APP_TITLEID) +endif + +ifneq ($(ROMFS),) + export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.switch + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... +ifeq ($(strip $(APP_JSON)),) + @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf +else + @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf +endif + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(APP_JSON)),) + +all : $(OUTPUT).nro + +ifeq ($(strip $(NO_NACP)),) +$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp +else +$(OUTPUT).nro : $(OUTPUT).elf +endif + +else + +all : $(OUTPUT).nsp + +$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm + +$(OUTPUT).nso : $(OUTPUT).elf + +endif + +$(OUTPUT).elf : $(OFILES) \ + $(STATIC_LIBS) + +$(OFILES_SRC) : $(HFILES_BIN) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/soh/icon.jpg b/soh/icon.jpg new file mode 100644 index 000000000..3a855753b Binary files /dev/null and b/soh/icon.jpg differ diff --git a/soh/include/functions.h b/soh/include/functions.h index 72fd6e98c..b185519f4 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -60,7 +60,7 @@ void Locale_ResetRegion(void); u32 func_80001F48(void); u32 func_80001F8C(void); u32 Locale_IsRegionNative(void); -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__SWITCH__) void __assert(const char* exp, const char* file, s32 line); #endif void isPrintfInit(void); @@ -1872,7 +1872,7 @@ void FaultDrawer_SetCharPad(s8, s8); void FaultDrawer_SetCursor(s32, s32); void FaultDrawer_FillScreen(); void* FaultDrawer_FormatStringFunc(void*, const char*, u32); -void FaultDrawer_VPrintf(const char*, char*); +void FaultDrawer_VPrintf(const char*, va_list); void FaultDrawer_Printf(const char*, ...); void FaultDrawer_DrawText(s32, s32, const char*, ...); void FaultDrawer_SetDrawerFB(void*, u16, u16); diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index 3911bb6c4..c765aa4ed 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -783,6 +783,8 @@ typedef struct { /* 0x0E */ u8 ttl; // duration after which the DMA can be discarded } SampleDma; // size = 0x10 +#include + typedef struct { /* 0x0000 */ char unk_0000; /* 0x0001 */ s8 numSynthesisReverbs; diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 6dc6b18b4..c766049ae 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -44,11 +44,6 @@ void BootCommands_ParseBootArgs(s32 argc, char** argv) } } } - - for (i = 0; i < argc; i++) - DebugArena_Free(argv[i]); - - //DebugArena_Free(argv); } /* diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 64281ddd5..66b9b8939 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -8,6 +8,7 @@ #include #include #include +#include /** * Colors variables @@ -93,10 +94,10 @@ const char* RainbowColorCvarList[] = { "gCCRupeePrim", "gCCKeysPrim", "gDog1Col", "gDog2Col", "gCCVSOAPrim", "gKeese1_Ef_Prim","gKeese2_Ef_Prim","gKeese1_Ef_Env","gKeese2_Ef_Env", "gDF_Col", "gDF_Env", - "gNL_Diamond_Col", "gNL_Diamond_Env", "gNL_Orb_Col", "gNL_Orb_Env", + "gNL_Diamond_Col", "gNL_Diamond_Env", "gNL_Orb_Col", "gNL_Orb_Env", "gTrailCol", "gCharged1Col", "gCharged1ColEnv", "gCharged2Col", "gCharged2ColEnv", "gCCFileChoosePrim", "gCCFileChooseTextPrim", "gCCEquipmentsPrim", "gCCItemsPrim", - "gCCMapsPrim", "gCCQuestsPrim", "gCCSavePrim", "gCCGameoverPrim", + "gCCMapsPrim", "gCCQuestsPrim", "gCCSavePrim", "gCCGameoverPrim", }; const char* MarginCvarList[] { "gHearts", "gMagicBar", "gVSOA", "gBBtn", "gABtn", "gStartBtn", diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp index e14cf502d..8f46310cf 100644 --- a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp @@ -10,6 +10,7 @@ #define NOGDI #define WIN32_LEAN_AND_MEAN #include +#include #define TICKS_PER_SEC 268123480.0 diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index c64134fbc..142d2576f 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -300,7 +300,7 @@ static void WriteLocation( // node->SetAttribute("price", price); // } // if (!location->IsAddedToPool()) { - // #ifdef ENABLE_DEBUG + // #ifdef ENABLE_DEBUG // node->SetAttribute("not-added", true); // #endif // } @@ -673,7 +673,7 @@ static void WriteHints(int language) { static void WriteAllLocations(int language) { for (const uint32_t key : allLocations) { ItemLocation* location = Location(key); - + switch (language) { case 0: default: @@ -725,7 +725,7 @@ const char* SpoilerLog_Write(int language) { WriteHints(language); //WriteShuffledEntrances(spoilerLog); WriteAllLocations(language); - + if (!std::filesystem::exists(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Randomizer"))) { std::filesystem::create_directory(Ship::GlobalCtx2::GetPathRelativeToAppDirectory("Randomizer")); } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 6a1ecc198..393619cce 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -51,6 +51,10 @@ #include #endif +#ifdef __SWITCH__ +#include "SwitchImpl.h" +#endif + #include OTRGlobals* OTRGlobals::Instance; @@ -104,6 +108,9 @@ extern "C" void OTRExtScanner() { } extern "C" void InitOTR() { +#ifdef __SWITCH__ + Ship::Switch::Init(Ship::PreInitPhase); +#endif OTRGlobals::Instance = new OTRGlobals(); SaveManager::Instance = new SaveManager(); auto t = OTRGlobals::Instance->context->GetResourceManager()->LoadFile("version"); @@ -225,6 +232,7 @@ extern "C" void Graph_StartFrame() { // C->C++ Bridge extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { +#ifndef __SWITCH__ if (!audio.initialized) { audio.initialized = true; std::thread([]() { @@ -251,19 +259,16 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) #define NUM_AUDIO_CHANNELS 2 + int samples_left = AudioPlayer_Buffered(); u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; - // printf("Audio samples: %d %u\n", samples_left, num_audio_samples); // 3 is the maximum authentic frame divisor. s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); } - //for (uint32_t i = 0; i < 2 * num_audio_samples; i++) { - // audio_buffer[i] = Rand_Next() & 0xFF; - //} - // printf("Audio samples before submitting: %d\n", audio_api->buffered()); + AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); audio.processing = false; @@ -276,8 +281,9 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { std::unique_lock Lock(audio.mutex); audio.processing = true; } - audio.cv_to_thread.notify_one(); +#endif + audio.cv_to_thread.notify_one(); std::vector> mtx_replacements; int target_fps = CVar_GetS32("gInterpolationFPS", 20); static int last_fps; @@ -318,12 +324,14 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { last_fps = fps; last_update_rate = R_UPDATE_RATE; +#ifndef __SWITCH__ { std::unique_lock Lock(audio.mutex); while (audio.processing) { audio.cv_from_thread.wait(Lock); } } +#endif // OTRTODO: FIGURE OUT END FRAME POINT /* if (OTRGlobals::Instance->context->GetWindow()->lastScancode != -1) @@ -1412,7 +1420,7 @@ extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBuff price = 40; break; } - switch (language) { + switch (language) { case 0: default: scrubText += 0x12; // add the sound scrubText += 0x38; // sound id @@ -1467,7 +1475,7 @@ extern "C" int CopyScrubMessage(u16 scrubTextId, char* buffer, const int maxBuff scrubText += 0xA3; // message id break; } - + return CopyStringToCharBuffer(scrubText, buffer, maxBufferSize); } @@ -1488,7 +1496,7 @@ extern "C" int Randomizer_CopyGanonHintText(char* buffer, const int maxBufferSiz } extern "C" int Randomizer_CopyHintFromCheck(RandomizerCheck check, char* buffer, const int maxBufferSize) { - // we don't want to make a copy of the std::string returned from GetHintFromCheck + // we don't want to make a copy of the std::string returned from GetHintFromCheck // so we're just going to let RVO take care of it const std::string& hintText = OTRGlobals::Instance->gRandomizer->GetHintFromCheck(check); return CopyStringToCharBuffer(hintText, buffer, maxBufferSize); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index f59cf0ecc..e0de89d09 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -49,6 +49,8 @@ SaveManager::SaveManager() { } void SaveManager::LoadRandomizerVersion1() { + if(!CVar_GetS32("gRandomizer", 0)) return; + for (int i = 0; i < ARRAY_COUNT(gSaveContext.itemLocations); i++) { SaveManager::Instance->LoadData("get" + std::to_string(i), gSaveContext.itemLocations[i].get); SaveManager::Instance->LoadData("check" + std::to_string(i), gSaveContext.itemLocations[i].check); @@ -88,6 +90,9 @@ void SaveManager::LoadRandomizerVersion1() { } void SaveManager::SaveRandomizer() { + + if(!gSaveContext.n64ddFlag) return; + for (int i = 0; i < ARRAY_COUNT(gSaveContext.itemLocations); i++) { SaveManager::Instance->SaveData("get" + std::to_string(i), gSaveContext.itemLocations[i].get); SaveManager::Instance->SaveData("check" + std::to_string(i), gSaveContext.itemLocations[i].check); @@ -170,7 +175,7 @@ void SaveManager::Init() { } else { CreateDefaultGlobal(); } - + // Load files to initialize metadata for (int fileNum = 0; fileNum < MaxFiles; fileNum++) { if (std::filesystem::exists(GetFileName(fileNum))) { @@ -906,7 +911,7 @@ void SaveManager::LoadArray(const std::string& name, const size_t size, LoadArra } currentJsonContext = saveJsonContext; } - + void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) { // Create an empty struct and set it as the current load context, then call the function that loads the struct. diff --git a/soh/src/boot/assert.c b/soh/src/boot/assert.c index b7895dddd..5a44a9308 100644 --- a/soh/src/boot/assert.c +++ b/soh/src/boot/assert.c @@ -1,5 +1,6 @@ #include "global.h" +#ifndef __SWITCH__ void __assert(const char* exp, const char* file, s32 line) { char msg[256]; @@ -7,3 +8,4 @@ void __assert(const char* exp, const char* file, s32 line) { sprintf(msg, "ASSERT: %s:%d(%d)", file, line, osGetThreadId(NULL)); Fault_AddHungupAndCrashImpl(msg, exp); } +#endif \ No newline at end of file diff --git a/soh/src/code/fault_drawer.c b/soh/src/code/fault_drawer.c index 9759bfe72..8cd08248f 100644 --- a/soh/src/code/fault_drawer.c +++ b/soh/src/code/fault_drawer.c @@ -265,16 +265,14 @@ void* FaultDrawer_FormatStringFunc(void* arg, const char* str, u32 count) { return arg; } -void FaultDrawer_VPrintf(const char* str, char* args) { // va_list +void FaultDrawer_VPrintf(const char* str, va_list args) { // va_list _Printf(FaultDrawer_FormatStringFunc, (char*)&sFaultDrawerStruct, str, args); } void FaultDrawer_Printf(const char* fmt, ...) { va_list args; va_start(args, fmt); - FaultDrawer_VPrintf(fmt, args); - va_end(args); } @@ -284,7 +282,6 @@ void FaultDrawer_DrawText(s32 x, s32 y, const char* fmt, ...) { FaultDrawer_SetCursor(x, y); FaultDrawer_VPrintf(fmt, args); - va_end(args); } diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c index f4dcf56e8..cf0a53c76 100644 --- a/soh/src/code/graph.c +++ b/soh/src/code/graph.c @@ -481,6 +481,22 @@ static void RunFrame() uint64_t ticksA, ticksB; ticksA = GetPerfCounter(); +#ifdef __SWITCH__ + #define SAMPLES_HIGH 752 + #define SAMPLES_LOW 720 + + #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) + #define NUM_AUDIO_CHANNELS 2 + int samples_left = AudioPlayer_Buffered(); + u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; + + s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; + for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { + AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); + } + + AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); +#endif Graph_StartFrame(); // TODO: Workaround for rumble being too long. Implement os thread functions. diff --git a/soh/src/code/main.c b/soh/src/code/main.c index 372e3947c..fd02b016a 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -41,8 +41,6 @@ void main(int argc, char** argv) GameConsole_Init(); InitOTR(); BootCommands_Init(); - - BootCommands_ParseBootArgs(argc - 1, (char**)&argv[1]); Main(0); } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index e711e8abe..a91dd5e41 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -111,7 +111,7 @@ void Message_ResetOcarinaNoteState(void) { sOcarinaNoteCEnvR = 10; sOcarinaNoteCEnvG = 10; sOcarinaNoteCEnvB = 10; - if (CVar_GetS32("gHudColors", 1) == 0) { + if (CVar_GetS32("gHudColors", 1) == 0) { sOcarinaNoteAPrimR = 80; sOcarinaNoteAPrimG = 150; sOcarinaNoteAPrimB = 255; @@ -240,8 +240,6 @@ void Message_DrawTextChar(GlobalContext* globalCtx, void* textureImage, Gfx** p) s16 x = msgCtx->textPosX; s16 y = msgCtx->textPosY; - gSPInvalidateTexCache(gfx++, textureImage); - gDPPipeSync(gfx++); sCharTexSize = (R_TEXT_CHAR_SCALE / 100.0f) * 16.0f; @@ -1229,6 +1227,8 @@ void Message_Decode(GlobalContext* globalCtx) { MessageContext* msgCtx = &globalCtx->msgCtx; Font* font = &globalCtx->msgCtx.font; + gSPInvalidateTexCache(globalCtx->state.gfxCtx->polyOpa.p++, NULL); + globalCtx->msgCtx.textDelayTimer = 0; globalCtx->msgCtx.textUnskippable = globalCtx->msgCtx.textDelay = globalCtx->msgCtx.textDelayTimer = 0; sTextFade = false; @@ -1624,6 +1624,7 @@ void Message_OpenText(GlobalContext* globalCtx, u16 textId) { } sMessageHasSetSfx = D_8014B2F4 = sTextboxSkipped = sTextIsCredits = 0; + gSPInvalidateTexCache(globalCtx->state.gfxCtx->polyOpa.p++, NULL); if (textId >= 0x0500 && textId < 0x0600) { // text ids 0500 to 0600 are reserved for credits sTextIsCredits = true; @@ -1793,7 +1794,7 @@ void Message_StartTextbox(GlobalContext* globalCtx, u16 textId, Actor* actor) { // so we need to switch the order of these lines if (gSaveContext.n64ddFlag && textId == 0x2053) { msgCtx->talkActor = actor; - Message_OpenText(globalCtx, textId); + Message_OpenText(globalCtx, textId); } else { Message_OpenText(globalCtx, textId); msgCtx->talkActor = actor; @@ -2114,7 +2115,7 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) { if(CBtnB_2 > 255){CBtnB_2=255;}; s16 sOcarinaNoteCPrimColors_CUSTOM[][3] = { { CBtnR, CBtnG, CBtnB }, //Unified - { CBtnR_2, CBtnG_2, CBtnB_2 }, + { CBtnR_2, CBtnG_2, CBtnB_2 }, { CBtnRL, CBtnGL, CBtnBL }, //Left { CBtnRD, CBtnGD, CBtnBD }, //Down { CBtnRR, CBtnGR, CBtnBR }, //Right @@ -2704,15 +2705,15 @@ void Message_DrawMain(GlobalContext* globalCtx, Gfx** p) { Message_ContinueTextbox(globalCtx, msgCtx->lastPlayedSong + 0x893); // You played [song name] Message_Decode(globalCtx); msgCtx->msgMode = MSGMODE_DISPLAY_SONG_PLAYED_TEXT; - - if (CVar_GetS32("gFastOcarinaPlayback", 0) == 0 || globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_TIME + + if (CVar_GetS32("gFastOcarinaPlayback", 0) == 0 || globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_TIME || globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_STORMS || globalCtx->msgCtx.lastPlayedSong == OCARINA_SONG_SUNS) { msgCtx->stateTimer = 20; } else { msgCtx->stateTimer = 1; } - + Message_DrawText(globalCtx, &gfx); break; case MSGMODE_DISPLAY_SONG_PLAYED_TEXT: diff --git a/soh/switch/pathconf.c b/soh/switch/pathconf.c new file mode 100644 index 000000000..9e4111db3 --- /dev/null +++ b/soh/switch/pathconf.c @@ -0,0 +1,5 @@ +#include + +long pathconf(const char *path, int name) { + return -1; +} \ No newline at end of file