Wii U support (#1097)

* Wii U support

* [WiiU] Combined Dockerfile

* [WiiU] Combined Dockerfile

* [WiiU] Combined Dockerfile

* Add Jenkins support

* wiiu: fix scissor clamp

* wiiu: improve button remapping

* wiiu: fix scaling issues

* Update Dockerfile after merge

* Pull assets before build

* Only stop container once

* Adjust logging sinks

* wiiu: Change button mapping to match PC version

* wiiu: Implement controller changes

* wiiu: Update BUILDING.md

Co-authored-by: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com>
Co-authored-by: David Chavez <david@dcvz.io>
This commit is contained in:
GaryOderNichts 2022-08-15 04:57:24 +02:00 committed by GitHub
parent b989ef4f7f
commit 68e7f2e6c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 5460 additions and 73 deletions

View File

@ -167,6 +167,27 @@ cmake --build build-switch --target soh_nro
# To develop the project open the repository in VSCode (or your preferred editor)
```
## Wii U
1. Requires that your build machine is setup with the tools necessary for your platform above
2. Requires that you have the Wii U build tools installed
3. Clone the Ship of Harkinian repository
4. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice
```bash
cd Shipwright
# Setup cmake project for your host machine
cmake -H. -Bbuild-cmake -GNinja
# Extract assets & generate OTR (run this anytime you need to regenerate OTR)
cmake --build build-cmake --target ExtractAssets
# Setup cmake project for building for Wii U
cmake -H. -Bbuild-wiiu -GNinja -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/WiiU.cmake # -DCMAKE_BUILD_TYPE:STRING=Release (if you're packaging)
# Build project and generate rpx
cmake --build build-wiiu --target soh
# Now you can run the executable in ./build-wiiu/soh/soh.rpx
# To develop the project open the repository in VSCode (or your preferred editor)
```
# Compatible Roms
```
OOT_PAL_GC checksum 0x09465AC3

View File

@ -122,7 +122,7 @@ add_subdirectory(ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD)
add_subdirectory(ZAPDTR/ZAPDUtils ${CMAKE_BINARY_DIR}/ZAPDUtils)
add_subdirectory(OTRExporter)
add_subdirectory(soh)
if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|NintendoSwitch")
if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin|NintendoSwitch|CafeOS")
add_subdirectory(OTRGui)
endif()
@ -179,13 +179,13 @@ add_custom_target(CreateOSXIcons
add_dependencies(soh CreateOSXIcons)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch")
if(CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch|CafeOS")
INSTALL(FILES ${CMAKE_SOURCE_DIR}/README.md DESTINATION . COMPONENT ship RENAME readme.txt )
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(CPACK_GENERATOR "External")
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch")
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch|CafeOS")
set(CPACK_GENERATOR "ZIP")
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
set(CPACK_GENERATOR "Bundle")

View File

@ -56,12 +56,13 @@ RUN \
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
yes | dkp-pacman -Syu switch-dev switch-portlibs wiiu-dev wiiu-portlibs --noconfirm
ENV DEVKITPRO=/opt/devkitpro
ENV DEVKITARM=/opt/devkitpro/devkitARM
ENV DEVKITPPC=/opt/devkitpro/devkitPPC
ENV PATH=$PATH:/opt/devkitpro/portlibs/switch/bin/
ENV PATH=$PATH:/opt/devkitpro/portlibs/switch/bin/:$DEVKITPPC/bin
ENV WUT_ROOT=$DEVKITPRO/wut
RUN mkdir /soh
WORKDIR /soh

37
Jenkinsfile vendored
View File

@ -185,6 +185,43 @@ pipeline {
}
}
}
stage ('Build Wii U') {
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') {
unstash 'assets'
sh '''
if docker ps -aq --filter "name=sohwiiucont" | grep -q .; then docker rm -f sohwiiucont; fi
docker build . -t sohwiiu
docker run --name sohwiiucont -dit --rm -v $(pwd):/soh sohwiiu /bin/bash
docker exec sohwiiucont scripts/wiiu/build.sh
mv build-wiiu/soh/*.rpx soh.rpx
mv README.md readme.txt
7z a soh-wiiu.7z soh.rpx readme.txt
'''
}
archiveArtifacts artifacts: 'soh-wiiu.7z', followSymlinks: false, onlyIfSuccessful: true
}
post {
always {
sh 'sudo docker container stop sohwiiucont'
sh 'docker images --quiet --filter=dangling=true | xargs --no-run-if-empty docker rmi' // Clean dangling docker images
step([$class: 'WsCleanup']) // Clean workspace
}
}
}
}
}
}

View File

@ -34,7 +34,12 @@
// Local functions - platform-specific functions
#ifndef STORMLIB_WINDOWS
#ifndef STORMLIB_WIIU // WIIU doesn't support thread_local
static thread_local DWORD dwLastError = ERROR_SUCCESS;
#else
static DWORD dwLastError = ERROR_SUCCESS;
#endif
DWORD GetLastError()
{

View File

@ -2005,7 +2005,7 @@ void ConvertTMPQHeader(void *header, uint16_t version)
TMPQHeader * theHeader = (TMPQHeader *)header;
// Swap header part version 1
if(version == MPQ_FORMAT_VERSION_1)
if(version >= MPQ_FORMAT_VERSION_1)
{
theHeader->dwID = SwapUInt32(theHeader->dwID);
theHeader->dwHeaderSize = SwapUInt32(theHeader->dwHeaderSize);
@ -2018,21 +2018,21 @@ void ConvertTMPQHeader(void *header, uint16_t version)
theHeader->dwBlockTableSize = SwapUInt32(theHeader->dwBlockTableSize);
}
if(version == MPQ_FORMAT_VERSION_2)
if(version >= MPQ_FORMAT_VERSION_2)
{
theHeader->HiBlockTablePos64 = SwapUInt64(theHeader->HiBlockTablePos64);
theHeader->wHashTablePosHi = SwapUInt16(theHeader->wHashTablePosHi);
theHeader->wBlockTablePosHi = SwapUInt16(theHeader->wBlockTablePosHi);
}
if(version == MPQ_FORMAT_VERSION_3)
if(version >= MPQ_FORMAT_VERSION_3)
{
theHeader->ArchiveSize64 = SwapUInt64(theHeader->ArchiveSize64);
theHeader->BetTablePos64 = SwapUInt64(theHeader->BetTablePos64);
theHeader->HetTablePos64 = SwapUInt64(theHeader->HetTablePos64);
}
if(version == MPQ_FORMAT_VERSION_4)
if(version >= MPQ_FORMAT_VERSION_4)
{
theHeader->HashTableSize64 = SwapUInt64(theHeader->HashTableSize64);
theHeader->BlockTableSize64 = SwapUInt64(theHeader->BlockTableSize64);

View File

@ -180,7 +180,7 @@ static DWORD LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAtt
if((pbAttrPtr + cbArraySize) > pbAttrFileEnd)
return ERROR_FILE_CORRUPT;
BSWAP_ARRAY32_UNSIGNED(ArrayCRC32, cbCRC32Size);
BSWAP_ARRAY32_UNSIGNED(ArrayCRC32, cbArraySize);
for(i = 0; i < dwAttributesEntries; i++)
ha->pFileTable[i].dwCrc32 = ArrayCRC32[i];
pbAttrPtr += cbArraySize;
@ -196,7 +196,7 @@ static DWORD LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAtt
if((pbAttrPtr + cbArraySize) > pbAttrFileEnd)
return ERROR_FILE_CORRUPT;
BSWAP_ARRAY64_UNSIGNED(ArrayFileTime, cbFileTimeSize);
BSWAP_ARRAY64_UNSIGNED(ArrayFileTime, cbArraySize);
for(i = 0; i < dwAttributesEntries; i++)
ha->pFileTable[i].FileTime = ArrayFileTime[i];
pbAttrPtr += cbArraySize;

View File

@ -480,7 +480,7 @@ static bool IsMatchingPatchFile(
{
// Load the patch header
SFileReadFile(hFile, &PatchHeader, sizeof(MPQ_PATCH_HEADER), &dwTransferred, NULL);
BSWAP_ARRAY32_UNSIGNED(pPatchHeader, sizeof(DWORD) * 6);
BSWAP_ARRAY32_UNSIGNED(&PatchHeader, sizeof(DWORD) * 6);
// If the file contains an incremental patch,
// compare the "MD5 before patching" with the base file MD5

View File

@ -631,8 +631,8 @@ typedef struct _TMPQHash
#else
BYTE Platform;
BYTE Reserved;
BYTE Platform;
USHORT lcLocale;
#endif

View File

@ -254,6 +254,34 @@
#endif
//-----------------------------------------------------------------------------
// Defines for Wii U platform
#if !defined(STORMLIB_PLATFORM_DEFINED) && defined(__WIIU__)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <malloc.h>
#undef STORMLIB_LITTLE_ENDIAN // Wii U is always big endian
#define STORMLIB_MAC // Use Mac compatible code
#define STORMLIB_WIIU
#define STORMLIB_PLATFORM_DEFINED
#endif
//-----------------------------------------------------------------------------
// Assumption: If the platform is not defined, assume a Linux-like platform

View File

@ -465,6 +465,12 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
PNG::PNG
Threads::Threads
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"ZAPDUtils;"
"libultraship;"
PNG::PNG
)
else()
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
@ -478,7 +484,7 @@ else()
)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
if(CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_library(pathconf OBJECT pathconf.c)
target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}" $<TARGET_OBJECTS:pathconf> )
else()

View File

@ -130,7 +130,13 @@ float BinaryReader::ReadSingle()
stream->Read((char*)&result, sizeof(float));
if (endianness != Endianness::Native)
result = BitConverter::ToFloatBE((uint8_t*)&result, 0);
{
float tmp;
char* dst = (char*)&tmp;
char* src = (char*)&result;
dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
result = tmp;
}
if (std::isnan(result))
throw std::runtime_error("BinaryReader::ReadSingle(): Error reading stream");
@ -145,7 +151,14 @@ double BinaryReader::ReadDouble()
stream->Read((char*)&result, sizeof(double));
if (endianness != Endianness::Native)
result = BitConverter::ToDoubleBE((uint8_t*)&result, 0);
{
double tmp;
char* dst = (char*)&tmp;
char* src = (char*)&result;
dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
result = tmp;
}
if (std::isnan(result))
throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream");

View File

@ -107,7 +107,13 @@ void BinaryWriter::Write(uint64_t value)
void BinaryWriter::Write(float value)
{
if (endianness != Endianness::Native)
value = BitConverter::ToFloatBE((uint8_t*)&value, 0);
{
float tmp;
char* dst = (char*)&tmp;
char* src = (char*)&value;
dst[3] = src[0]; dst[2] = src[1]; dst[1] = src[2]; dst[0] = src[3];
value = tmp;
}
stream->Write((char*)&value, sizeof(float));
}
@ -115,7 +121,14 @@ void BinaryWriter::Write(float value)
void BinaryWriter::Write(double value)
{
if (endianness != Endianness::Native)
value = BitConverter::ToDoubleBE((uint8_t*)&value, 0);
{
double tmp;
char* dst = (char*)&tmp;
char* src = (char*)&value;
dst[7] = src[0]; dst[6] = src[1]; dst[5] = src[2]; dst[4] = src[3];
dst[3] = src[4]; dst[2] = src[5]; dst[1] = src[6]; dst[0] = src[7];
value = tmp;
}
stream->Write((char*)&value, sizeof(double));
}

View File

@ -64,7 +64,11 @@ void StringHelper::ReplaceOriginal(std::string& str, const std::string& from, co
bool StringHelper::StartsWith(const std::string& s, const std::string& input)
{
#if __cplusplus >= 202002L
return s.starts_with(input.c_str());
#else
return s.rfind(input, 0) == 0;
#endif
}
bool StringHelper::Contains(const std::string& s, const std::string& input)

View File

@ -86,11 +86,17 @@ set(Source_Files__Controller
"InputEditor.h"
"KeyboardController.cpp"
"KeyboardController.h"
"SDLController.cpp"
"SDLController.h"
"UltraController.h"
"DummyController.h"
)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
list(APPEND Source_Files__Controller
"SDLController.cpp"
"SDLController.h"
)
endif()
source_group("Source Files\\Controller" FILES ${Source_Files__Controller})
set(Source_Files__Controller__Attachment
@ -150,16 +156,21 @@ source_group("Source Files\\Lib" FILES ${Source_Files__Lib})
set(Source_Files__Lib__Fast3D
"Lib/Fast3D/gfx_cc.cpp"
"Lib/Fast3D/gfx_cc.h"
"Lib/Fast3D/gfx_opengl.cpp"
"Lib/Fast3D/gfx_opengl.h"
"Lib/Fast3D/gfx_pc.cpp"
"Lib/Fast3D/gfx_pc.h"
"Lib/Fast3D/gfx_rendering_api.h"
"Lib/Fast3D/gfx_screen_config.h"
"Lib/Fast3D/gfx_sdl.h"
"Lib/Fast3D/gfx_sdl2.cpp"
"Lib/Fast3D/gfx_window_manager_api.h"
)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
list(APPEND Source_Files__Lib__Fast3D
"Lib/Fast3D/gfx_opengl.cpp"
"Lib/Fast3D/gfx_opengl.h"
"Lib/Fast3D/gfx_sdl.h"
"Lib/Fast3D/gfx_sdl2.cpp"
)
endif()
source_group("Source Files\\Lib\\Fast3D" FILES ${Source_Files__Lib__Fast3D})
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
@ -179,14 +190,19 @@ set(Source_Files__Lib__Fast3D__extra
"Lib/Fast3D/gfx_glx.cpp"
"Lib/Fast3D/gfx_glx.h"
)
elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(Source_Files__Lib__Fast3D__extra
"Lib/Fast3D/gfx_wiiu.cpp"
"Lib/Fast3D/gfx_wiiu.h"
"Lib/Fast3D/gfx_gx2.cpp"
"Lib/Fast3D/gfx_gx2.h"
"Lib/Fast3D/gx2_shader_gen.c"
"Lib/Fast3D/gx2_shader_gen.h"
)
endif()
source_group("Source Files\\Lib\\Fast3D\\extra" FILES ${Source_Files__Lib__Fast3D__extra})
set(Source_Files__Lib__ImGui
"Lib/ImGui/backends/imgui_impl_opengl3.cpp"
"Lib/ImGui/backends/imgui_impl_opengl3.h"
"Lib/ImGui/backends/imgui_impl_sdl.cpp"
"Lib/ImGui/backends/imgui_impl_sdl.h"
"Lib/ImGui/imconfig.h"
"Lib/ImGui/imgui.cpp"
"Lib/ImGui/imgui.h"
@ -199,6 +215,16 @@ set(Source_Files__Lib__ImGui
"Lib/ImGui/imstb_textedit.h"
"Lib/ImGui/imstb_truetype.h"
)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
list(APPEND Source_Files__Lib__ImGui
"Lib/ImGui/backends/imgui_impl_opengl3.cpp"
"Lib/ImGui/backends/imgui_impl_opengl3.h"
"Lib/ImGui/backends/imgui_impl_sdl.cpp"
"Lib/ImGui/backends/imgui_impl_sdl.h"
)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(Source_Files__Lib__ImGui__Windows
"Lib/ImGui/backends/imgui_impl_dx11.cpp"
@ -206,8 +232,19 @@ set(Source_Files__Lib__ImGui__Windows
"Lib/ImGui/backends/imgui_impl_win32.cpp"
"Lib/ImGui/backends/imgui_impl_win32.h"
)
elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(Source_Files__Lib__ImGui__WiiU
"Lib/ImGui/backends/wiiu/imgui_impl_wiiu.cpp"
"Lib/ImGui/backends/wiiu/imgui_impl_wiiu.h"
"Lib/ImGui/backends/wiiu/imgui_impl_gx2.cpp"
"Lib/ImGui/backends/wiiu/imgui_impl_gx2.h"
)
endif ()
source_group("Source Files\\Lib\\ImGui" FILES ${Source_Files__Lib__ImGui} ${Source_Files__Lib__ImGui__Windows})
source_group("Source Files\\Lib\\ImGui" FILES
${Source_Files__Lib__ImGui}
${Source_Files__Lib__ImGui__Windows}
${Source_Files__Lib__ImGui__WiiU}
)
set(Source_Files__Lib__Mercury
"Lib/Mercury/Mercury.cpp"
@ -316,6 +353,18 @@ set(Source_Files__NintendoSwitch
source_group("Source Files\\NintendoSwitch" FILES ${Source_Files__NintendoSwitch})
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
set(Source_Files__CafeOS
"WiiUController.cpp"
"WiiUController.h"
"WiiUGamepad.cpp"
"WiiUGamepad.h"
"WiiUImpl.cpp"
"WiiUImpl.h"
)
source_group("Source Files\\CafeOS" FILES ${Source_Files__CafeOS})
endif()
set(ALL_FILES
${Header_Files__Resources__Factories}
${Header_Files__Resources__Files}
@ -332,6 +381,7 @@ set(ALL_FILES
${Source_Files__Lib__Fast3D__extra}
${Source_Files__Lib__ImGui}
${Source_Files__Lib__ImGui__Windows}
${Source_Files__Lib__ImGui__WiiU}
${Source_Files__Lib__Mercury}
${Source_Files__Lib__stb}
${Source_Files__Lib__dr_libs}
@ -343,6 +393,7 @@ set(ALL_FILES
${Source_Files__Resources__mpq}
${Source_Files__Darwin}
${Source_Files__NintendoSwitch}
${Source_Files__CafeOS}
)
################################################################################
@ -445,9 +496,21 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
STORMLIB_NO_AUTO_LINK
)
endif()
endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
target_compile_definitions(${PROJECT_NAME} PRIVATE
"$<$<CONFIG:Debug>:"
"_DEBUG"
">"
"$<$<CONFIG:Release>:"
"NDEBUG"
">"
"SPDLOG_ACTIVE_LEVEL=3;"
"SPDLOG_NO_THREAD_ID;"
"SPDLOG_NO_TLS;"
"STBI_NO_THREAD_LOCALS;"
)
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
target_compile_definitions(${PROJECT_NAME} PRIVATE
"$<$<CONFIG:Debug>:"
"_DEBUG"
@ -462,7 +525,7 @@ endif()
################################################################################
# Compile and link options
################################################################################
if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch")
if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch|CafeOS")
find_package(SDL2)
find_package(GLEW)
find_package(X11)
@ -485,7 +548,7 @@ if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows|NintendoSwitch")
set(GLEW-INCLUDE ${GLEW_INCLUDE_DIRS})
endif()
set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS})
elseif (CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch")
elseif (CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
find_package(SDL2)
else()
set(GLEW-INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/Lib/GLEW/)
@ -627,6 +690,15 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch")
SDL2::SDL2
Threads::Threads
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
find_package(SDL2 REQUIRED)
target_link_libraries(${PROJECT_NAME}
storm
SDL2::SDL2-static
)
target_include_directories(${PROJECT_NAME} PRIVATE
${DEVKITPRO}/portlibs/wiiu/include/
)
else()
target_link_libraries(${PROJECT_NAME}
SDL2::SDL2

View File

@ -3,11 +3,17 @@
#include "Window.h"
#include "Controller.h"
#include "DummyController.h"
#include "KeyboardController.h"
#include "SDLController.h"
#include <Utils/StringHelper.h>
#include "Cvar.h"
#ifndef __WIIU__
#include "KeyboardController.h"
#include "SDLController.h"
#else
#include "WiiUGamepad.h"
#include "WiiUController.h"
#endif
namespace Ship {
void ControlDeck::Init(uint8_t* bits) {
@ -20,6 +26,7 @@ namespace Ship {
virtualDevices.clear();
physicalDevices.clear();
#ifndef __WIIU__
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
auto sdl = std::make_shared<SDLController>(i);
@ -30,6 +37,20 @@ namespace Ship {
physicalDevices.push_back(std::make_shared<DummyController>("Auto", "Auto", true));
physicalDevices.push_back(std::make_shared<KeyboardController>());
#else
physicalDevices.push_back(std::make_shared<DummyController>("Auto", "Auto", true));
auto gamepad = std::make_shared<Ship::WiiUGamepad>();
gamepad->Open();
physicalDevices.push_back(gamepad);
for (int i = 0; i < 4; i++) {
auto controller = std::make_shared<Ship::WiiUController>((WPADChan) i);
controller->Open();
physicalDevices.push_back(controller);
}
#endif
physicalDevices.push_back(std::make_shared<DummyController>("Disconnected", "None", false));
for (const auto& device : physicalDevices) {

View File

@ -21,7 +21,9 @@ namespace Ship {
void Controller::Read(OSContPad* pad, int32_t virtualSlot) {
ReadFromSource(virtualSlot);
#ifndef __WIIU__
SDL_PumpEvents();
#endif
// Button Inputs
pad->button |= getPressedButtons(virtualSlot) & 0xFFFF;

View File

@ -11,6 +11,8 @@
#include "OSXFolderManager.h"
#elif defined(__SWITCH__)
#include "SwitchImpl.h"
#elif defined(__WIIU__)
#include "WiiUImpl.h"
#endif
namespace Ship {
@ -59,7 +61,6 @@ namespace Ship {
void GlobalCtx2::InitWindow() {
InitLogging();
Config = std::make_shared<Mercury>(GetPathRelativeToAppDirectory("shipofharkinian.json"));
Config->reload();
MainPath = Config->getString("Game.Main Archive", GetPathRelativeToAppDirectory("oot.otr"));
PatchesPath = Config->getString("Game.Patches Archive", GetAppDirectoryPath() + "/mods");
@ -73,6 +74,8 @@ namespace Ship {
MessageBox(nullptr, L"Main OTR file not found!", L"Uh oh", MB_OK);
#elif defined(__SWITCH__)
printf("Main OTR file not found!\n");
#elif defined(__WIIU__)
Ship::WiiU::ThrowMissingOTR(MainPath.c_str());
#else
SPDLOG_ERROR("Main OTR file not found!");
#endif
@ -85,28 +88,36 @@ namespace Ship {
void GlobalCtx2::InitLogging() {
try {
auto logPath = GetPathRelativeToAppDirectory(("logs/" + GetName() + ".log").c_str());
// Setup Logging
spdlog::init_thread_pool(8192, 1);
std::vector<spdlog::sink_ptr> Sinks;
auto SohConsoleSink = std::make_shared<spdlog::sinks::soh_sink_mt>();
SohConsoleSink->set_level(spdlog::level::trace);
#if defined(__linux__)
Sinks.push_back(SohConsoleSink);
#if (!defined(_WIN32) && !defined(__WIIU__)) || defined(_DEBUG)
auto ConsoleSink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
ConsoleSink->set_level(spdlog::level::trace);
Sinks.push_back(ConsoleSink);
#endif
#ifndef __WIIU__
auto logPath = GetPathRelativeToAppDirectory(("logs/" + GetName() + ".log").c_str());
auto FileSink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath, 1024 * 1024 * 10, 10);
FileSink->set_level(spdlog::level::trace);
std::vector<spdlog::sink_ptr> Sinks{
#if defined(__linux__)
ConsoleSink,
Sinks.push_back(FileSink);
#endif
FileSink,
SohConsoleSink
};
Logger = std::make_shared<spdlog::async_logger>(GetName(), Sinks.begin(), Sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
GetLogger()->set_level(spdlog::level::trace);
#ifndef __WIIU__
GetLogger()->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%@] [%l] %v");
#else
GetLogger()->set_pattern("[%s:%#] [%l] %v");
#endif
spdlog::register_logger(GetLogger());
spdlog::set_default_logger(GetLogger());
}

View File

@ -30,6 +30,16 @@
#include "Lib/spdlog/include/spdlog/common.h"
#include "UltraController.h"
#ifdef __WIIU__
#include <gx2/registers.h> // GX2SetViewport / GX2SetScissor
#include "Lib/ImGui/backends/wiiu/imgui_impl_gx2.h"
#include "Lib/ImGui/backends/wiiu/imgui_impl_wiiu.h"
#include "Lib/Fast3D/gfx_wiiu.h"
#include "Lib/Fast3D/gfx_gx2.h"
#endif
#if __APPLE__
#include <SDL_hints.h>
#else
@ -101,7 +111,11 @@ namespace SohImGui {
bool statsWindowOpen;
const char* filters[3] = {
#ifdef __WIIU__
"",
#else
"Three-Point",
#endif
"Linear",
"None"
};
@ -110,7 +124,11 @@ namespace SohImGui {
#ifdef _WIN32
{ "dx11", "DirectX" },
#endif
#ifndef __WIIU__
{ "sdl", "OpenGL" }
#else
{ "wiiu", "GX2" }
#endif
};
@ -178,10 +196,16 @@ namespace SohImGui {
void ImGuiWMInit() {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
ImGui_ImplWiiU_Init();
break;
#else
case Backend::SDL:
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1");
ImGui_ImplSDL2_InitForOpenGL(static_cast<SDL_Window*>(impl.sdl.window), impl.sdl.context);
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_Init(impl.dx11.window);
@ -195,6 +219,11 @@ namespace SohImGui {
void ImGuiBackendInit() {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
ImGui_ImplGX2_Init();
break;
#else
case Backend::SDL:
#if defined(__APPLE__)
ImGui_ImplOpenGL3_Init("#version 410 core");
@ -202,6 +231,7 @@ namespace SohImGui {
ImGui_ImplOpenGL3_Init("#version 120");
#endif
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
@ -215,9 +245,17 @@ namespace SohImGui {
void ImGuiProcessEvent(EventImpl event) {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
if (!ImGui_ImplWiiU_ProcessInput((ImGui_ImplWiiU_ControllerInput*)event.gx2.input)) {
}
break;
#else
case Backend::SDL:
ImGui_ImplSDL2_ProcessEvent(static_cast<const SDL_Event*>(event.sdl.event));
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_WndProcHandler(static_cast<HWND>(event.win32.handle), event.win32.msg, event.win32.wparam, event.win32.lparam);
@ -230,9 +268,14 @@ namespace SohImGui {
void ImGuiWMNewFrame() {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
break;
#else
case Backend::SDL:
ImGui_ImplSDL2_NewFrame(static_cast<SDL_Window*>(impl.sdl.window));
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_NewFrame();
@ -245,9 +288,16 @@ namespace SohImGui {
void ImGuiBackendNewFrame() {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
io->DeltaTime = (float) frametime / 1000.0f / 1000.0f;
ImGui_ImplGX2_NewFrame();
break;
#else
case Backend::SDL:
ImGui_ImplOpenGL3_NewFrame();
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplDX11_NewFrame();
@ -260,9 +310,20 @@ namespace SohImGui {
void ImGuiRenderDrawData(ImDrawData* data) {
switch (impl.backend) {
#ifdef __WIIU__
case Backend::GX2:
ImGui_ImplGX2_RenderDrawData(data);
// Reset viewport and scissor for drawing the keyboard
GX2SetViewport(0.0f, 0.0f, io->DisplaySize.x, io->DisplaySize.y, 0.0f, 1.0f);
GX2SetScissor(0, 0, io->DisplaySize.x, io->DisplaySize.y);
ImGui_ImplWiiU_DrawKeyboardOverlay();
break;
#else
case Backend::SDL:
ImGui_ImplOpenGL3_RenderDrawData(data);
break;
#endif
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplDX11_RenderDrawData(data);
@ -395,9 +456,19 @@ namespace SohImGui {
Ship::Switch::SetupFont(io->Fonts);
#endif
#ifdef __WIIU__
// Scale everything by 2 for the Wii U
ImGui::GetStyle().ScaleAllSizes(2.0f);
io->FontGlobalScale = 2.0f;
// Setup display sizes
io->DisplaySize.x = window_impl.gx2.width;
io->DisplaySize.y = window_impl.gx2.height;
#endif
lastBackendID = GetBackendID(GlobalCtx2::GetInstance()->GetConfig());
if (CVar_GetS32("gOpenMenuBar", 0) != 1) {
#ifdef __SWITCH__
#if defined(__SWITCH__) || defined(__WIIU__)
SohImGui::overlay->TextDrawNotification(30.0f, true, "Press - to access enhancements menu");
#else
SohImGui::overlay->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu");
@ -412,6 +483,18 @@ namespace SohImGui {
if (UseViewports()) {
io->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
#ifdef __SWITCH__
bool enableControllerNavigation = true;
#else
bool enableControllerNavigation = CVar_GetS32("gControlNav", 0);
#endif
if (enableControllerNavigation && CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
} else {
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
console->Init();
overlay->Init();
controller->Init();
@ -616,7 +699,11 @@ namespace SohImGui {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
}
if (PlusMinusButton) {
#ifdef __WIIU__
ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2);
#else
ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f);
#endif
}
if (ImGui::SliderFloat(id, &val, min, max, format))
{
@ -846,12 +933,8 @@ namespace SohImGui {
#else
bool enableControllerNavigation = CVar_GetS32("gControlNav", 0);
#endif
if (enableControllerNavigation) {
if (CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |=ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
} else {
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
if (enableControllerNavigation && CVar_GetS32("gOpenMenuBar", 0)) {
io->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad | ImGuiConfigFlags_NavEnableKeyboard;
} else {
io->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
@ -875,13 +958,18 @@ namespace SohImGui {
if (DefaultAssets.contains("Game_Icon")) {
#ifdef __SWITCH__
ImVec2 iconSize = ImVec2(20.0f, 20.0f);
float posScale = 1.0f;
#elif defined(__WIIU__)
ImVec2 iconSize = ImVec2(16.0f * 2, 16.0f * 2);
float posScale = 2.0f;
#else
ImVec2 iconSize = ImVec2(16.0f, 16.0f);
float posScale = 1.0f;
#endif
ImGui::SetCursorPos(ImVec2(5, 2.5f));
ImGui::SetCursorPos(ImVec2(5, 2.5f) * posScale);
ImGui::Image(GetTextureByID(DefaultAssets["Game_Icon"]->textureId), iconSize);
ImGui::SameLine();
ImGui::SetCursorPos(ImVec2(25, 0));
ImGui::SetCursorPos(ImVec2(25, 0) * posScale);
}
static ImVec2 windowPadding(8.0f, 8.0f);
@ -957,9 +1045,11 @@ namespace SohImGui {
Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing");
gfx_current_dimensions.internal_mul = CVar_GetFloat("gInternalResolution", 1);
#endif
#ifndef __WIIU__
PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, false, true, false);
Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel");
gfx_msaa_level = CVar_GetS32("gMSAAValue", 1);
#endif
if (impl.backend == Backend::DX11)
{
@ -1434,7 +1524,7 @@ namespace SohImGui {
const char* fps_cvar = "gInterpolationFPS";
{
#ifdef __SWITCH__
#if defined(__SWITCH__) || defined(__WIIU__)
int minFps = 20;
int maxFps = 60;
#else
@ -1444,6 +1534,12 @@ namespace SohImGui {
int val = CVar_GetS32(fps_cvar, minFps);
val = MAX(MIN(val, maxFps), 20);
#ifdef __WIIU__
// only support divisors of 60 on the Wii U
val = 60 / (60 / val);
#endif
int fps = val;
if (fps == 20)
@ -1458,15 +1554,28 @@ namespace SohImGui {
std::string MinusBTNFPSI = " - ##FPSInterpolation";
std::string PlusBTNFPSI = " + ##FPSInterpolation";
if (ImGui::Button(MinusBTNFPSI.c_str())) {
#ifdef __WIIU__
if (val >= 60) val = 30;
else val = 20;
#else
val--;
#endif
CVar_SetS32(fps_cvar, val);
needs_save = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
#ifdef __WIIU__
ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f * 2);
#else
ImGui::PushItemWidth(ImGui::GetWindowSize().x - 79.0f);
#endif
if (ImGui::SliderInt("##FPSInterpolation", &val, minFps, maxFps, "", ImGuiSliderFlags_AlwaysClamp))
{
#ifdef __WIIU__
// only support divisors of 60 on the Wii U
val = 60 / (60 / val);
#endif
if (val > 360)
{
val = 360;
@ -1490,7 +1599,12 @@ namespace SohImGui {
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNFPSI.c_str())) {
#ifdef __WIIU__
if (val <= 20) val = 30;
else val = 60;
#else
val++;
#endif
CVar_SetS32(fps_cvar, val);
needs_save = true;
}
@ -1791,14 +1905,18 @@ namespace SohImGui {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Debug Stats", &statsWindowOpen, ImGuiWindowFlags_NoFocusOnAppearing);
#ifdef _WIN32
#if defined(_WIN32)
ImGui::Text("Platform: Windows");
#elif __APPLE__
#elif defined(__APPLE__)
ImGui::Text("Platform: macOS");
#elif defined(__SWITCH__)
ImGui::Text("Platform: Nintendo Switch");
#else
#elif defined(__WIIU__)
ImGui::Text("Platform: Nintendo Wii U");
#elif defined(__linux__)
ImGui::Text("Platform: Linux");
#else
ImGui::Text("Platform: Unknown");
#endif
ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate);
ImGui::End();
@ -2281,6 +2399,13 @@ namespace SohImGui {
return gfx_d3d11_get_texture_by_id(id);
}
#endif
#ifdef __WIIU__
if (impl.backend == Backend::GX2)
{
return gfx_gx2_texture_for_imgui(id);
}
#endif
return reinterpret_cast<ImTextureID>(id);
}

View File

@ -24,7 +24,8 @@ struct GameAsset {
namespace SohImGui {
enum class Backend {
DX11,
SDL
SDL,
GX2,
};
enum class Dialogues {
@ -45,6 +46,10 @@ namespace SohImGui {
void* window;
void* context;
} sdl;
struct {
uint32_t width;
uint32_t height;
} gx2;
};
} WindowImpl;
@ -58,6 +63,9 @@ namespace SohImGui {
struct {
void* event;
} sdl;
struct {
void* input;
} gx2;
} EventImpl;
extern WindowImpl impl;

View File

@ -45,6 +45,9 @@ namespace Ship {
if(btn != -1) {
backend->SetButtonMapping(CurrentPort, n64Btn, btn);
BtnReading = -1;
// avoid immediately triggering another button during gamepad nav
ImGui::SetKeyboardFocusHere(0);
}
}
@ -145,9 +148,17 @@ namespace Ship {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
#ifdef __WIIU__
ImGui::BeginChild("##MSInput", ImVec2(90 * 2, 50 * 2), false);
#else
ImGui::BeginChild("##MSInput", ImVec2(90 , 50), false);
#endif
ImGui::Text("Deadzone");
#ifdef __WIIU__
ImGui::PushItemWidth(80 * 2);
#else
ImGui::PushItemWidth(80);
#endif
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[0] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::EndChild();
@ -176,13 +187,25 @@ namespace Ship {
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
#ifdef __WIIU__
ImGui::BeginChild("##CSInput", ImVec2(90 * 2, 85 * 2), false);
#else
ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
#endif
ImGui::Text("Deadzone");
#ifdef __WIIU__
ImGui::PushItemWidth(80 * 2);
#else
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[2] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
#endif
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[2] /* This is the SDL value for right stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::Text("Sensitivity");
#ifdef __WIIU__
ImGui::PushItemWidth(80 * 2);
#else
ImGui::PushItemWidth(80);
#endif
ImGui::InputFloat("##MSensitivity", &profile->AxisSensitivities[2] /* This is the SDL value for right stick X axis */, 1.0f, 0.0f, "%.0f");
profile->AxisSensitivities[3] = profile->AxisSensitivities[2];
ImGui::PopItemWidth();
@ -195,15 +218,20 @@ namespace Ship {
}
if(Backend->CanGyro()) {
#ifndef __WIIU__
ImGui::SameLine();
#endif
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<int>(100.0f * profile->GyroData[GYRO_SENSITIVITY]));
#ifdef __WIIU__
ImGui::PushItemWidth(135.0f * 2);
#else
ImGui::PushItemWidth(135.0f);
#endif
ImGui::SetCursorPosX(cursorX);
ImGui::SliderFloat("##GSensitivity", &profile->GyroData[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
ImGui::PopItemWidth();
@ -218,13 +246,25 @@ namespace Ship {
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
#ifdef __WIIU__
ImGui::BeginChild("##GyInput", ImVec2(90 * 2, 85 * 2), false);
#else
ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);