diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e85cde12b..13e31277eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -541,8 +541,22 @@ set_property(SOURCE src/version.cpp PROPERTY COMPILE_DEFINITIONS ) # Platform setup -set(PLAYER_TARGET_PLATFORM "SDL2" CACHE STRING "Platform to compile for. Options: SDL2 SDL1 libretro psvita 3ds switch wii amigaos4") -set_property(CACHE PLAYER_TARGET_PLATFORM PROPERTY STRINGS SDL2 SDL1 libretro psvita 3ds switch wii amigaos4) +if(NINTENDO_3DS) + set(PLAYER_TARGET_PLATFORM "3ds" CACHE STRING "Platform to compile for.") +elseif(NINTENDO_SWITCH) + set(PLAYER_TARGET_PLATFORM "switch" CACHE STRING "Platform to compile for.") +elseif(VITA) + set(PLAYER_TARGET_PLATFORM "psvita" CACHE STRING "Platform to compile for.") +elseif(NINTENDO_WII) + set(PLAYER_TARGET_PLATFORM "wii" CACHE STRING "Platform to compile for.") +elseif(NINTENDO_WIIU) + set(PLAYER_TARGET_PLATFORM "SDL2" CACHE STRING "Platform to compile for.") +elseif(AMIGA) + set(PLAYER_TARGET_PLATFORM "SDL1" CACHE STRING "Platform to compile for.") +else() + set(PLAYER_TARGET_PLATFORM "SDL2" CACHE STRING "Platform to compile for. Options: SDL2 SDL1 libretro") + set_property(CACHE PLAYER_TARGET_PLATFORM PROPERTY STRINGS SDL2 SDL1 libretro) +endif() set(PLAYER_BUILD_EXECUTABLE ON) set(PLAYER_TEST_LIBRARIES ${PROJECT_NAME}) @@ -581,6 +595,7 @@ if(${PLAYER_TARGET_PLATFORM} STREQUAL "SDL2") if(NINTENDO_WIIU) target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_NINTENDO) target_sources(${PROJECT_NAME} PRIVATE + src/platform/wiiu/main.h src/platform/wiiu/input_buttons.cpp) endif() @@ -603,9 +618,6 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "libretro") add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/builds/libretro) target_link_libraries(${PROJECT_NAME} retro_common) elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "3ds") - if(NOT NINTENDO_3DS) - message(FATAL_ERROR "Missing toolchain file! Use '-DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/cmake/3DS.cmake' option.") - endif() target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_UI=CtrUi PLAYER_NINTENDO) target_compile_options(${PROJECT_NAME} PUBLIC -Wno-psabi) # Remove abi warning after devkitarm ships newer gcc # generate gfx assets @@ -636,9 +648,6 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "3ds") src/platform/3ds/ui.h) target_link_libraries(${PROJECT_NAME} 3ds-assets) elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "psvita") - if(NOT VITA) - message(FATAL_ERROR "Missing toolchain file! Use '-DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake' option.") - endif() include("$ENV{VITASDK}/share/vita.cmake" REQUIRED) target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_UI=Psp2Ui) target_compile_options(${PROJECT_NAME} PUBLIC -Wno-psabi) # Remove abi warning after vitasdk ships newer gcc @@ -651,9 +660,6 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "psvita") src/platform/psvita/ui.cpp src/platform/psvita/ui.h) elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "switch") - if(NOT NINTENDO_SWITCH) - message(FATAL_ERROR "Missing toolchain file! Use '-DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/cmake/Switch.cmake' option.") - endif() target_compile_definitions(${PROJECT_NAME} PUBLIC PLAYER_UI=NxUi PLAYER_NINTENDO) find_package(OpenGL CONFIG REQUIRED) find_library(GLAD glad REQUIRED) @@ -673,9 +679,6 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "switch") src/platform/switch/ui.h) target_link_libraries(${PROJECT_NAME} switch-assets) elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "wii") - if(NOT NINTENDO_WII) - message(FATAL_ERROR "Missing toolchain file! Use '-DCMAKE_TOOLCHAIN_FILE=$DEVKITPRO/cmake/Wii.cmake' option.") - endif() find_package(SDL REQUIRED) target_compile_definitions(${PROJECT_NAME} PUBLIC USE_SDL=1 PLAYER_NINTENDO) target_include_directories(${PROJECT_NAME} PUBLIC ${SDL_INCLUDE_DIR}) @@ -688,19 +691,6 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "wii") src/platform/sdl/axis.h src/platform/sdl/sdl_ui.cpp src/platform/sdl/sdl_ui.h) -elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "amigaos4") - if(NOT AMIGAOS4) - message(FATAL_ERROR "Missing toolchain file! Use '-DCMAKE_TOOLCHAIN_FILE=path/to/ppc-amigaos.cmake' option.") - endif() - find_package(SDL REQUIRED) - target_compile_definitions(${PROJECT_NAME} PUBLIC USE_SDL=1) - target_include_directories(${PROJECT_NAME} PUBLIC ${SDL_INCLUDE_DIR}) - target_sources(${PROJECT_NAME} PRIVATE - src/platform/sdl/sdl_audio.cpp - src/platform/sdl/sdl_audio.h - src/platform/sdl/axis.h - src/platform/sdl/sdl_ui.cpp - src/platform/sdl/sdl_ui.h) else() message(FATAL_ERROR "Invalid target platform") endif() @@ -712,13 +702,17 @@ if(${PLAYER_TARGET_PLATFORM} MATCHES "^(3ds|psvita|switch|wii)$" OR NINTENDO_WII set(PLAYER_ENABLE_TESTS OFF) option(PLAYER_VERSIONED_PACKAGES "Create zip packages with versioned name (for internal use)" ON) endif() -# Make romfs available -if(${PLAYER_TARGET_PLATFORM} MATCHES "^(3ds|switch)$") - option(PLAYER_ROMFS "Embedd a directory in the executable" OFF) - set(PLAYER_ROMFS_PATH "romfs" CACHE PATH "Directory to include in executable as romfs:/ path") - set(ROMFS_ARG "NO_ROMFS_IGNORE_ME") - if(PLAYER_ROMFS) - set(ROMFS_ARG "ROMFS") +# Make content available (romfs/wuhb bundle) +if(${PLAYER_TARGET_PLATFORM} MATCHES "^(3ds|switch)$" OR NINTENDO_WIIU) + option(PLAYER_BUNDLE "Embed a directory in the executable" OFF) + set(PLAYER_BUNDLE_PATH "content" CACHE PATH "Directory to include in executable") + set(BUNDLE_ARG "_IGNORE_ME") + if(PLAYER_BUNDLE) + if(NINTENDO_WIIU) + set(BUNDLE_ARG "CONTENT") + else() + set(BUNDLE_ARG "ROMFS") + endif() endif() endif() @@ -917,21 +911,17 @@ elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "SDL1") set(PLAYER_AUDIO_BACKEND "SDL1" CACHE STRING "Audio system to use. Options: SDL1 OFF") set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS SDL1 OFF) else() + # Assuming that all platforms not targeting SDL have only one audio backend set(PLAYER_AUDIO_BACKEND "Default" CACHE STRING "Audio system to use. Options: Default OFF") set_property(CACHE PLAYER_AUDIO_BACKEND PROPERTY STRINGS Default OFF) - - if(${PLAYER_AUDIO_BACKEND} STREQUAL "Default") - # Assuming that all platforms not targeting SDL have only one audio backend - set(PLAYER_AUDIO_BACKEND ${PLAYER_TARGET_PLATFORM}) - endif() endif() # Configure Audio backends -if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii|amigaos4)$") +if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL[12]|Default)$") set(PLAYER_HAS_AUDIO ON) target_compile_definitions(${PROJECT_NAME} PUBLIC SUPPORT_AUDIO=1) - if(${PLAYER_AUDIO_BACKEND} STREQUAL "libretro") + if(${PLAYER_TARGET_PLATFORM} STREQUAL "libretro") if (WIN32 OR UNIX OR APPLE) set(SUPPORT_NATIVE_MIDI ON) endif() @@ -986,7 +976,7 @@ CMAKE_DEPENDENT_OPTION(PLAYER_WITH_FLUIDLITE "Play MIDI audio with fluidlite" ON CMAKE_DEPENDENT_OPTION(PLAYER_WITH_XMP "Play MOD audio with libxmp" ON "PLAYER_HAS_AUDIO" OFF) CMAKE_DEPENDENT_OPTION(PLAYER_ENABLE_DRWAV "Play WAV audio with dr_wav (built-in). Unsupported files are played by libsndfile." ON "PLAYER_HAS_AUDIO" OFF) -if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii|amigaos4)$") +if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL[12]|Default)$") set(PLAYER_AUDIO_RESAMPLER "Auto" CACHE STRING "Audio resampler to use. Options: Auto speexdsp samplerate OFF") set_property(CACHE PLAYER_AUDIO_RESAMPLER PROPERTY STRINGS Auto speexdsp samplerate OFF) @@ -1102,7 +1092,7 @@ if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii|a endif() # Executable -if(${PLAYER_BUILD_EXECUTABLE} AND ${PLAYER_TARGET_PLATFORM} MATCHES "^SDL(1|2)$" AND NOT NINTENDO_WIIU) +if(${PLAYER_BUILD_EXECUTABLE} AND ${PLAYER_TARGET_PLATFORM} MATCHES "^SDL[12]$" AND NOT NINTENDO_WIIU) if(APPLE) set(EXE_NAME "EasyRPG-Player.app") set_source_files_properties(${${PROJECT_NAME}_BUNDLE_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") @@ -1219,7 +1209,7 @@ elseif(${PLAYER_TARGET_PLATFORM} MATCHES "^(psvita|3ds|switch|wii)$" OR NINTENDO ICON ${CMAKE_CURRENT_SOURCE_DIR}/resources/3ds/icon.png) ctr_create_3dsx(easyrpg-player SMDH easyrpg-player.smdh - ${ROMFS_ARG} ${PLAYER_ROMFS_PATH}) + ${BUNDLE_ARG} ${PLAYER_BUNDLE_PATH}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/easyrpg-player.3dsx resources/3ds/easyrpg-player.xml # consider removing, *hax² is mostly obsolete DESTINATION easyrpg-player COMPONENT 3ds) @@ -1235,7 +1225,7 @@ elseif(${PLAYER_TARGET_PLATFORM} MATCHES "^(psvita|3ds|switch|wii)$" OR NINTENDO nx_create_nro(easyrpg-player NACP easyrpg-player.nacp ICON "${PROJECT_SOURCE_DIR}/resources/switch/icon.jpg" - ${ROMFS_ARG} ${PLAYER_ROMFS_PATH}) + ${BUNDLE_ARG} ${PLAYER_BUNDLE_PATH}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/easyrpg-player.nro DESTINATION easyrpg-player COMPONENT switch) elseif(NINTENDO_WII) @@ -1256,14 +1246,17 @@ elseif(${PLAYER_TARGET_PLATFORM} MATCHES "^(psvita|3ds|switch|wii)$" OR NINTENDO ${CMAKE_CURRENT_BINARY_DIR}/resources/wii/meta.xml DESTINATION easyrpg-player COMPONENT wii) elseif(NINTENDO_WIIU) - add_executable(easyrpg-player src/platform/sdl/main.cpp) + add_executable(easyrpg-player src/platform/wiiu/main.cpp) target_link_libraries(easyrpg-player ${PROJECT_NAME}) wut_create_rpx(easyrpg-player) wut_create_wuhb(easyrpg-player NAME "EasyRPG Player ${PLAYER_VERSION_FULL}" - SHORT_NAME "Player" + SHORTNAME "EasyRPG Player" AUTHOR "EasyRPG Team" - ) # todo icon, splashs) + ICON resources/wiiu/icon.png + TVSPLASH resources/wiiu/splash-tv.png + DRCSPLASH resources/wiiu/splash-drc.png + ${BUNDLE_ARG} ${PLAYER_BUNDLE_PATH}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/easyrpg-player.rpx ${CMAKE_CURRENT_BINARY_DIR}/easyrpg-player.wuhb DESTINATION . COMPONENT wiiu) @@ -1319,12 +1312,6 @@ elseif(${PLAYER_TARGET_PLATFORM} MATCHES "^(psvita|3ds|switch|wii)$" OR NINTENDO set(CPACK_ARCHIVE_DEBUG_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PLATFORM}-debug") set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY OFF) # we do this manually include(CPack) -elseif(${PLAYER_TARGET_PLATFORM} STREQUAL "amigaos4") - add_executable(easyrpg-player "src/platform/sdl/main.cpp") - target_link_libraries(easyrpg-player - ${PROJECT_NAME} - ${SDL_LIBRARIES}) - # FIXME: packaging? else() # library if(${PLAYER_TARGET_PLATFORM} STREQUAL "libretro") add_library(easyrpg_libretro @@ -1497,9 +1484,15 @@ endif() # Print summary message(STATUS "") -message(STATUS "Target system: ${PLAYER_TARGET_PLATFORM}") -if(PLAYER_ROMFS) - message(STATUS "RomFS: Embedding directory \"${PLAYER_ROMFS_PATH}\"") +set(TARGET_STATUS "${PLAYER_TARGET_PLATFORM}") +if(NINTENDO_WIIU) + set(TARGET_STATUS "Wii U (SDL2)") +elseif(AMIGA) + set(TARGET_STATUS "Amiga (SDL1)") +endif() +message(STATUS "Target system: ${TARGET_STATUS}") +if(PLAYER_BUNDLE) + message(STATUS "Embedding directory \"${PLAYER_BUNDLE_PATH}\"") endif() message(STATUS "") @@ -1509,7 +1502,7 @@ if(PLAYER_BUILD_LIBLCF) endif() message(STATUS "Audio backend: ${PLAYER_AUDIO_BACKEND}") -if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL2|SDL1|libretro|psvita|3ds|switch|wii)$") +if(${PLAYER_AUDIO_BACKEND} MATCHES "^(SDL[12]|Default)$") message(STATUS "") set(WAV_LIBS) diff --git a/CMakePresets.json b/CMakePresets.json index 2f2d4e5daa..53ff62878a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -417,7 +417,6 @@ "name": "3ds-parent", "toolchainFile": "$env{DEVKITPRO}/cmake/3DS.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "3ds", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/3ds" }, "inherits": "dkp-user", @@ -478,7 +477,6 @@ "name": "switch-parent", "toolchainFile": "$env{DEVKITPRO}/cmake/Switch.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "switch", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/switch" }, "inherits": "dkp-user", @@ -539,7 +537,6 @@ "name": "wii-parent", "toolchainFile": "$env{DEVKITPRO}/cmake/Wii.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "wii", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/wii" }, "inherits": "dkp-user", @@ -660,7 +657,6 @@ "name": "psvita-parent", "toolchainFile": "$env{EASYRPG_BUILDSCRIPTS}/vita/vitasdk/share/vita.toolchain.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "psvita", "BUILD_SHARED_LIBS": "OFF" }, "hidden": true, diff --git a/builds/cmake/CMakePresets.json.template b/builds/cmake/CMakePresets.json.template index 15a21b7eaf..c611d25086 100644 --- a/builds/cmake/CMakePresets.json.template +++ b/builds/cmake/CMakePresets.json.template @@ -77,7 +77,6 @@ "displayName": "Nintendo 3DS", "toolchainFile": "$env{DEVKITPRO}/cmake/3DS.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "3ds", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/3ds" }, "inherits": "dkp-user" @@ -87,7 +86,6 @@ "displayName": "Nintendo Switch", "toolchainFile": "$env{DEVKITPRO}/cmake/Switch.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "switch", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/switch" }, "inherits": "dkp-user" @@ -97,7 +95,6 @@ "displayName": "Nintendo Wii", "toolchainFile": "$env{DEVKITPRO}/cmake/Wii.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "wii", "PLAYER_PREFIX_PATH_APPEND": "$env{EASYRPG_BUILDSCRIPTS}/wii" }, "inherits": "dkp-user" @@ -116,7 +113,6 @@ "displayName": "PlayStation Vita", "toolchainFile": "$env{EASYRPG_BUILDSCRIPTS}/vita/vitasdk/share/vita.toolchain.cmake", "cacheVariables": { - "PLAYER_TARGET_PLATFORM": "psvita", "BUILD_SHARED_LIBS": "OFF" } } diff --git a/builds/cmake/gen-cmake-presets.py b/builds/cmake/gen-cmake-presets.py old mode 100644 new mode 100755 diff --git a/docs/BUILDING.md b/docs/BUILDING.md index 83856138b6..567acdd7f8 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -94,13 +94,13 @@ The unsigned APK is stored in: app/build/outputs/apk/release/app-release-unsigned.apk -## Nintendo and Sony Homebrew ports (Wii, 3DS, Switch, PSVita/PSTV) +## Nintendo and Sony Homebrew ports (Wii (U), 3DS, Switch, PSVita/PSTV) This is based on the CMake method. Building requirements: -- devkitPPC for Wii +- devkitPPC for Wii and Wii U - devkitARM for 3DS - devkitA64 for Switch - vitasdk for PSVita/PSTV @@ -110,13 +110,12 @@ and vitasdk: https://vitasdk.org Invoke CMake with these additional parameters: - -DCMAKE_TOOLCHAIN_FILE=/cmake/3DS|Switch|Wii.cmake + -DCMAKE_TOOLCHAIN_FILE=/cmake/3DS|Switch|Wii|WiiU.cmake (or /share/vita.toolchain.cmake) - -DPLAYER_TARGET_PLATFORM=3ds|switch|wii|psvita -Switch and 3DS support romfs game loading, use these parameters: +Switch, Wii U and 3DS support shipping games, use these parameters: - -DPLAYER_ROMFS=ON -DPLAYER_ROMFS_PATH=path/to/myGame + -DPLAYER_BUNDLE=ON -DPLAYER_BUNDLE_PATH=path/to/myGame [buildscripts]: https://github.com/EasyRPG/buildscripts diff --git a/resources/wiiu/icon.png b/resources/wiiu/icon.png new file mode 100644 index 0000000000..704aa19472 Binary files /dev/null and b/resources/wiiu/icon.png differ diff --git a/resources/wiiu/splash-drc.png b/resources/wiiu/splash-drc.png new file mode 100644 index 0000000000..6b02413aa5 Binary files /dev/null and b/resources/wiiu/splash-drc.png differ diff --git a/resources/wiiu/splash-tv.png b/resources/wiiu/splash-tv.png new file mode 100644 index 0000000000..fb380777d8 Binary files /dev/null and b/resources/wiiu/splash-tv.png differ diff --git a/src/baseui.h b/src/baseui.h index b4877cdf67..cb9eaeaf02 100644 --- a/src/baseui.h +++ b/src/baseui.h @@ -68,8 +68,10 @@ class BaseUi { /** * Processes events queue. + * + * @return When false requests an immediate Player shutdown */ - virtual void ProcessEvents() = 0; + virtual bool ProcessEvents() = 0; /** * Cleans video buffer. diff --git a/src/decoder_wildmidi.cpp b/src/decoder_wildmidi.cpp index a4d00cd7c8..447661a8a8 100644 --- a/src/decoder_wildmidi.cpp +++ b/src/decoder_wildmidi.cpp @@ -142,9 +142,14 @@ bool WildMidiDecoder::Initialize(std::string& status_message) { } #elif defined(__WIIU__) // preferred SD card directory - config_file = "/vol/external01/data/easyrpg-player/wildmidi.cfg"; + config_file = "fs:/vol/external01/wiiu/data/easyrpg-player/wildmidi.cfg"; found = FileFinder::Root().Exists(config_file); + // shipped + if (!found) { + config_file = "fs:/vol/content/wildmidi.cfg"; + found = FileFinder::Root().Exists(config_file); + } // Current directory if (!found) { config_file = "wildmidi.cfg"; diff --git a/src/filefinder_rtp.cpp b/src/filefinder_rtp.cpp index 7753a527c9..eb2b273e81 100644 --- a/src/filefinder_rtp.cpp +++ b/src/filefinder_rtp.cpp @@ -52,8 +52,9 @@ FileFinder_RTP::FileFinder_RTP(bool no_rtp, bool no_rtp_warnings, std::string rt AddPath("sd:/data/rtp/" + version_str); AddPath("usb:/data/rtp/" + version_str); #elif defined(__WIIU__) - AddPath("./rtp/" + version_str); - AddPath("/data/easyrpg-player/rtp/" + version_str); + AddPath("fs:/vol/content/rtp/" + version_str); // shipped + AddPath("rtp/" + version_str); + AddPath("fs:/vol/external01/wiiu/data/easyrpg-player/rtp/" + version_str); #elif defined(__SWITCH__) AddPath("./rtp/" + version_str); AddPath("/switch/easyrpg-player/rtp/" + version_str); diff --git a/src/filesystem_native.cpp b/src/filesystem_native.cpp index b3969f3b2c..a77bf047c2 100644 --- a/src/filesystem_native.cpp +++ b/src/filesystem_native.cpp @@ -20,14 +20,21 @@ #include #include #include +#include #include #include #include +#include "filesystem_stream.h" #include "system.h" #include "output.h" #include "platform.h" +#ifdef USE_CUSTOM_FILEBUF +# include +# include +#endif + NativeFilesystem::NativeFilesystem(std::string base_path, FilesystemView parent_fs) : Filesystem(std::move(base_path), parent_fs) { } @@ -48,7 +55,17 @@ int64_t NativeFilesystem::GetFilesize(StringView path) const { } std::streambuf* NativeFilesystem::CreateInputStreambuffer(StringView path, std::ios_base::openmode mode) const { - auto* buf = new std::filebuf(); +#ifdef USE_CUSTOM_FILEBUF + (void)mode; + int fd = open(ToString(path).c_str(), O_RDONLY); + if (fd < 0) { + return nullptr; + } + + return new Filesystem_Stream::FdStreamBuf(fd, true); +#else + auto buf = new std::filebuf(); + buf->open( #ifdef _MSC_VER Utils::ToWideString(path), @@ -63,9 +80,24 @@ std::streambuf* NativeFilesystem::CreateInputStreambuffer(StringView path, std:: } return buf; +#endif } std::streambuf* NativeFilesystem::CreateOutputStreambuffer(StringView path, std::ios_base::openmode mode) const { +#ifdef USE_CUSTOM_FILEBUF + int flags = O_TRUNC; + + if ((mode & std::ios_base::app) == std::ios_base::app) { + flags = O_APPEND; + } + + int fd = open(ToString(path).c_str(), O_WRONLY | O_CREAT | flags, S_IRUSR | S_IWUSR); + if (fd < 0) { + return nullptr; + } + + return new Filesystem_Stream::FdStreamBuf(fd, false); +#else auto* buf = new std::filebuf(); buf->open( #ifdef _MSC_VER @@ -81,6 +113,7 @@ std::streambuf* NativeFilesystem::CreateOutputStreambuffer(StringView path, std: } return buf; +#endif } bool NativeFilesystem::GetDirectoryContent(StringView path, std::vector& entries) const { diff --git a/src/filesystem_stream.cpp b/src/filesystem_stream.cpp index cadf97d4a4..180a098958 100644 --- a/src/filesystem_stream.cpp +++ b/src/filesystem_stream.cpp @@ -19,6 +19,10 @@ #include +#ifdef USE_CUSTOM_FILEBUF +# include +#endif + Filesystem_Stream::InputStream::InputStream(std::streambuf* sb, std::string name) : std::istream(sb), name(std::move(name)) {} @@ -122,3 +126,123 @@ Filesystem_Stream::InputMemoryStreamBuf::InputMemoryStreamBuf(std::vector 0) { + auto dist = std::distance(gptr(), gptr() + offset); + if (gptr() + offset > egptr()) { + // Not cached: Outside of the buffer: Reposition the stream + file_offset = lseek(fd, dist - bytes_remaining(), SEEK_CUR); + clear_buffer(); + } else { + setg(buffer.begin(), gptr() + dist, egptr()); + } + } + return file_offset - bytes_remaining(); + } else { + // Not cached: Seek to end + clear_buffer(); + file_offset = lseek(fd, offset, SEEK_END); + + if (file_offset < 0) { + file_offset = 0; + return -1; + } + + return file_offset; + } + + assert(false); +} + +std::streambuf::pos_type Filesystem_Stream::FdStreamBuf::seekpos(std::streambuf::pos_type pos, std::ios_base::openmode mode) { + return seekoff(pos, std::ios_base::beg, mode); +} + + +Filesystem_Stream::FdStreamBuf::int_type Filesystem_Stream::FdStreamBuf::overflow(int c) { + assert(pptr() == epptr()); + + if (c == traits_type::eof() || sync() == -1) { + return traits_type::eof(); + } + + *pptr() = traits_type::to_char_type(c); + + pbump(1); + return c; +} + +int Filesystem_Stream::FdStreamBuf::sync() { + char *p = pbase(); + while (p < pptr()) { + int written = write(fd, p, pptr() - p); + if (written <= 0) { + return -1; + } + p += written; + } + + setp(buffer.begin(), buffer.end()); + return 0; +} + +void Filesystem_Stream::FdStreamBuf::clear_buffer() { + setg(buffer.begin(), buffer.end(), buffer.end()); +} + +ssize_t Filesystem_Stream::FdStreamBuf::bytes_remaining() const { + return egptr() - gptr(); +} + +#endif diff --git a/src/filesystem_stream.h b/src/filesystem_stream.h index 4a0d76bc7d..24a1f8b81f 100644 --- a/src/filesystem_stream.h +++ b/src/filesystem_stream.h @@ -24,6 +24,7 @@ #include #include "filesystem.h" #include "utils.h" +#include "system.h" namespace Filesystem_Stream { class InputStream final : public std::istream { @@ -96,6 +97,36 @@ namespace Filesystem_Stream { std::vector buffer; }; +#ifdef USE_CUSTOM_FILEBUF + class FdStreamBuf : public std::streambuf { + public: + FdStreamBuf(int fd, bool is_read); + FdStreamBuf(FdStreamBuf const& other) = delete; + FdStreamBuf const& operator=(FdStreamBuf const& other) = delete; + ~FdStreamBuf(); + + protected: + // Reading + int_type underflow() override; + std::streambuf::pos_type seekoff(std::streambuf::off_type offset, std::ios_base::seekdir dir, std::ios_base::openmode mode) override; + std::streambuf::pos_type seekpos(std::streambuf::pos_type pos, std::ios_base::openmode) override; + + // Writing + int_type overflow(int c = EOF) override; + int sync() override; + private: + // Reading + void clear_buffer(); + ssize_t bytes_remaining() const; + off_t file_offset = 0; + + // Both + int fd; + bool is_read; // Streams can be read and write but we only always use one mode + std::array buffer; + }; +#endif + static constexpr std::ios_base::seekdir CSeekdirToCppSeekdir(int origin); static constexpr int CppSeekdirToCSeekdir(std::ios_base::seekdir origin); diff --git a/src/filesystem_zip.cpp b/src/filesystem_zip.cpp index 68e5935100..eee40b0e36 100644 --- a/src/filesystem_zip.cpp +++ b/src/filesystem_zip.cpp @@ -30,8 +30,8 @@ #include #include -constexpr uint32_t end_of_central_directory = 0x06054b50; -constexpr int32_t end_of_central_directory_size = 22; +constexpr char end_of_central_directory[] = "\x50\x4b\x05\x06"; +constexpr int32_t end_of_central_directory_size = 18; constexpr uint32_t central_directory_entry = 0x02014b50; constexpr uint32_t local_header = 0x04034b50; @@ -212,23 +212,31 @@ bool ZipFilesystem::FindCentralDirectory(std::istream& zipfile, uint32_t& offset bool found = false; // seek to the first position where the end_of_central_directory Signature may occur - zipfile.seekg(-end_of_central_directory_size, std::ios_base::end); + zipfile.seekg(-end_of_central_directory_size - UINT16_MAX, std::ios_base::end); + zipfile.clear(); // The only variable length field in the end of central directory is the comment which // has a maximum length of UINT16_MAX - so if we seek longer, this is no zip file - for (size_t i = 0; i < UINT16_MAX && zipfile.good() && !found; i++) { - zipfile.read(reinterpret_cast(&magic), sizeof(magic)); - Utils::SwapByteOrder(magic); // Take care of big endian systems - if (magic == end_of_central_directory) { + std::vector items(UINT16_MAX); + zipfile.read(items.data(), items.size()); + zipfile.clear(); + + items.resize(zipfile.gcount()); + if (items.size() < sizeof(magic)) { + return false; + } + + int i = static_cast(items.size()) - sizeof(magic); + // The data is read once and then scanned backwards in memory (faster) + for (; i >= 0 && !found; --i) { + if (!memcmp(items.data() + i, end_of_central_directory, 4)) { found = true; - } - else { - // if not yet found the magic number step one byte back in the file - zipfile.seekg(-(static_cast(sizeof(magic)) + 1), std::ios_base::cur); + break; } } if (found) { + zipfile.seekg(-(static_cast(items.size()) - i - 4), std::ios_base::cur); // Move right after the magic zipfile.seekg(6, std::ios_base::cur); // Jump over multiarchive related fields zipfile.read(reinterpret_cast(&num_entries), sizeof(uint16_t)); Utils::SwapByteOrder(num_entries); diff --git a/src/game_config.cpp b/src/game_config.cpp index 33f8aeee9b..7eb6b9da05 100644 --- a/src/game_config.cpp +++ b/src/game_config.cpp @@ -84,10 +84,16 @@ void Game_ConfigInput::Hide() { Game_Config Game_Config::Create(CmdlineParser& cp) { Game_Config cfg; + // Set platform specific defaults #if USE_SDL >= 2 cfg.video.scaling_mode.Set(ConfigEnum::ScalingMode::Bilinear); #endif +#if defined(__WIIU__) + cfg.input.gamepad_swap_ab_and_xy.Set(true); +#endif + + cp.Rewind(); config_path = GetConfigPath(cp); @@ -127,7 +133,7 @@ FilesystemView Game_Config::GetGlobalConfigFilesystem() { #ifdef __wii__ path = "/data/easyrpg-player"; #elif defined(__WIIU__) - path = "/vol/external01/data/easyrpg-player"; // temp + path = "fs:/vol/external01/wiiu/data/easyrpg-player"; #elif defined(__SWITCH__) path = "/switch/easyrpg-player"; #elif defined(__3DS__) diff --git a/src/output.cpp b/src/output.cpp index 23129d9a1d..ed792352d7 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -214,9 +214,9 @@ static void HandleErrorOutput(const std::string& err) { #if !defined(USE_LIBRETRO) Game_Clock::SleepFor(1ms); #endif - DisplayUi->ProcessEvents(); - - if (Player::exit_flag) break; + if (!DisplayUi->ProcessEvents() || Player::exit_flag) { + break; + } Input::Update(); } diff --git a/src/platform.cpp b/src/platform.cpp index ea799a96f7..0106502673 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -157,6 +157,13 @@ bool Platform::File::MakeDirectory(bool follow_symlinks) const { } } +#if defined(__WIIU__) + if (cur_path == "fs:/vol" || cur_path == "/vol") { + // /vol is part of the path but checking for existance fails + continue; + } +#endif + File cf(cur_path); if (cf.IsDirectory(follow_symlinks)) { continue; diff --git a/src/platform/3ds/ui.cpp b/src/platform/3ds/ui.cpp index ea4472e36e..eab0b96408 100644 --- a/src/platform/3ds/ui.cpp +++ b/src/platform/3ds/ui.cpp @@ -217,9 +217,10 @@ CtrUi::~CtrUi() { ToggleBottomScreen(true); } -void CtrUi::ProcessEvents() { - if (!aptMainLoop()) - Player::Exit(); +bool CtrUi::ProcessEvents() { + if (!aptMainLoop()) { + return false; + } hidScanInput(); u32 input = hidKeysHeld(); @@ -324,6 +325,8 @@ void CtrUi::ProcessEvents() { } } #endif + + return true; } void CtrUi::UpdateDisplay() { diff --git a/src/platform/3ds/ui.h b/src/platform/3ds/ui.h index 9dc42b7122..febc4f3aa9 100644 --- a/src/platform/3ds/ui.h +++ b/src/platform/3ds/ui.h @@ -50,7 +50,7 @@ class CtrUi final : public BaseUi { */ /** @{ */ void UpdateDisplay() override; - void ProcessEvents() override; + bool ProcessEvents() override; void ToggleStretch() override; void ToggleTouchUi() override; void vGetConfig(Game_ConfigVideo& cfg) const override; diff --git a/src/platform/libretro/ui.cpp b/src/platform/libretro/ui.cpp index 0fd56faabd..efa65ca6b5 100644 --- a/src/platform/libretro/ui.cpp +++ b/src/platform/libretro/ui.cpp @@ -138,10 +138,10 @@ bool LibretroUi::vChangeDisplaySurfaceResolution(int new_width, int new_height) return true; } -void LibretroUi::ProcessEvents() { +bool LibretroUi::ProcessEvents() { # if defined(USE_JOYSTICK) && defined(SUPPORT_JOYSTICK) if (CheckInputState == nullptr) { - return; + return true; } LibretroUi::input_poll_cb(); @@ -184,6 +184,8 @@ void LibretroUi::ProcessEvents() { analog_input.trigger_right = normalize(CheckInputState(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_BUTTON, RETRO_DEVICE_ID_JOYPAD_R2)); # endif # endif + + return true; } retro_video_refresh_t LibretroUi::UpdateWindow = nullptr; diff --git a/src/platform/libretro/ui.h b/src/platform/libretro/ui.h index 6237d4642d..7f9ef8c3c9 100644 --- a/src/platform/libretro/ui.h +++ b/src/platform/libretro/ui.h @@ -47,7 +47,7 @@ class LibretroUi final : public BaseUi { /** @{ */ bool vChangeDisplaySurfaceResolution(int new_width, int new_height) override; void UpdateDisplay() override; - void ProcessEvents() override; + bool ProcessEvents() override; void vGetConfig(Game_ConfigVideo& cfg) const override; #ifdef SUPPORT_AUDIO diff --git a/src/platform/psvita/ui.cpp b/src/platform/psvita/ui.cpp index 397186bfa7..91afcc4120 100644 --- a/src/platform/psvita/ui.cpp +++ b/src/platform/psvita/ui.cpp @@ -207,7 +207,7 @@ Psp2Ui::~Psp2Ui() { vita2d_fini(); } -void Psp2Ui::ProcessEvents() { +bool Psp2Ui::ProcessEvents() { SceCtrlData input; SceTouchData touch; @@ -261,6 +261,8 @@ void Psp2Ui::ProcessEvents() { } } } + + return true; } void Psp2Ui::UpdateDisplay() { diff --git a/src/platform/psvita/ui.h b/src/platform/psvita/ui.h index 5f5fc59f49..d465f0620e 100644 --- a/src/platform/psvita/ui.h +++ b/src/platform/psvita/ui.h @@ -49,7 +49,7 @@ class Psp2Ui final : public BaseUi { */ /** @{ */ void UpdateDisplay() override; - void ProcessEvents() override; + bool ProcessEvents() override; void SetScalingMode(ConfigEnum::ScalingMode) override; void ToggleStretch() override; void ToggleTouchUi() override; diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 9924e4746c..aeffa5b805 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -31,17 +31,14 @@ #elif defined(__ANDROID__) # include # include "platform/android/android.h" -#elif defined(__WIIU__) -# include #endif -#if defined(__ANDROID__) || defined(__WIIU__) +#ifdef __ANDROID__ static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserData /* userdata */) { -# if defined(__ANDROID__) -# ifdef NDEBUG +# ifdef NDEBUG // docs say debugging logs should be disabled for release builds if (lvl == LogLevel::Debug || lvl == LogLevel::Info) return; -# endif +# endif int prio = (lvl == LogLevel::Error) ? ANDROID_LOG_ERROR : (lvl == LogLevel::Warning) ? ANDROID_LOG_WARN : @@ -49,12 +46,6 @@ static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserDat ANDROID_LOG_INFO; __android_log_write(prio, GAME_TITLE, msg.c_str()); -# elif defined(__WIIU__) - std::string m = std::string("[" GAME_TITLE "] ") + - Output::LogLevelToString(lvl) + ": " + msg; - - OSReport("%s\n", m.c_str()); -# endif } #endif @@ -80,7 +71,7 @@ extern "C" int main(int argc, char* argv[]) { args.assign(argv, argv + argc); #endif -#if defined(__WIIU__) || defined(__ANDROID__) +#ifdef __ANDROID__ Output::SetLogCallback(LogCallback); #endif diff --git a/src/platform/sdl/sdl2_ui.cpp b/src/platform/sdl/sdl2_ui.cpp index 416c575958..7c5d4ad72b 100644 --- a/src/platform/sdl/sdl2_ui.cpp +++ b/src/platform/sdl/sdl2_ui.cpp @@ -14,7 +14,6 @@ * You should have received a copy of the GNU General Public License * along with EasyRPG Player. If not, see . */ - #include #include #include @@ -32,7 +31,7 @@ #elif defined(EMSCRIPTEN) # include #elif defined(__WIIU__) -# include +# include "platform/wiiu/main.h" #endif #include "icon.h" @@ -57,7 +56,11 @@ AudioInterface& Sdl2Ui::GetAudio() { #endif static uint32_t GetDefaultFormat() { +#ifdef WORDS_BIGENDIAN + return SDL_PIXELFORMAT_ABGR32; +#else return SDL_PIXELFORMAT_RGBA32; +#endif } /** @@ -66,7 +69,18 @@ static uint32_t GetDefaultFormat() { * We prefer formats which have fast paths in pixman. */ static int GetFormatRank(uint32_t fmt) { + switch (fmt) { +#ifdef WORDS_BIGENDIAN + case SDL_PIXELFORMAT_RGBA32: + return 0; + case SDL_PIXELFORMAT_BGRA32: + return 0; + case SDL_PIXELFORMAT_ARGB32: + return 1; + case SDL_PIXELFORMAT_ABGR32: + return 2; +#else case SDL_PIXELFORMAT_RGBA32: return 2; case SDL_PIXELFORMAT_BGRA32: @@ -75,6 +89,7 @@ static int GetFormatRank(uint32_t fmt) { return 1; case SDL_PIXELFORMAT_ABGR32: return 0; +#endif default: return -1; } @@ -155,9 +170,6 @@ Sdl2Ui::Sdl2Ui(long width, long height, const Game_Config& cfg) : BaseUi(cfg) // Only handle keyboard events when the canvas has focus SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); #endif -#ifdef __WIIU__ - //WHBProcInit(); -#endif if (SDL_Init(SDL_INIT_VIDEO) < 0) { Output::Error("Couldn't initialize SDL.\n{}\n", SDL_GetError()); @@ -210,10 +222,6 @@ Sdl2Ui::~Sdl2Ui() { SDL_DestroyWindow(sdl_window); } SDL_Quit(); - -#ifdef __WIIU__ - //WHBProcShutdown(); -#endif } bool Sdl2Ui::vChangeDisplaySurfaceResolution(int new_width, int new_height) { @@ -524,7 +532,13 @@ void Sdl2Ui::ToggleZoom() { #endif } -void Sdl2Ui::ProcessEvents() { +bool Sdl2Ui::ProcessEvents() { +#if defined(__WIIU__) + if (!WiiU_ProcessProcUI()) { + return false; + } +#endif + SDL_Event evnt; #if defined(USE_MOUSE) && defined(SUPPORT_MOUSE) @@ -540,6 +554,8 @@ void Sdl2Ui::ProcessEvents() { if (Player::exit_flag) break; } + + return true; } void Sdl2Ui::SetScalingMode(ConfigEnum::ScalingMode mode) { @@ -569,8 +585,23 @@ void Sdl2Ui::ToggleVsync() { } void Sdl2Ui::UpdateDisplay() { +#ifdef __WIIU__ + if (vcfg.scaling_mode.Get() == ConfigEnum::ScalingMode::Bilinear && window.scale > 0.f) { + // Workaround WiiU bug: Bilinear uses a render target and for these the format is not converted + void* target_pixels; + int target_pitch; + + SDL_LockTexture(sdl_texture_game, nullptr, &target_pixels, &target_pitch); + SDL_ConvertPixels(main_surface->width(), main_surface->height(), GetDefaultFormat(), main_surface->pixels(), + main_surface->pitch(), SDL_PIXELFORMAT_RGBA8888, target_pixels, target_pitch); + SDL_UnlockTexture(sdl_texture_game); + } else { + SDL_UpdateTexture(sdl_texture_game, nullptr, main_surface->pixels(), main_surface->pitch()); + } +#else // SDL_UpdateTexture was found to be faster than SDL_LockTexture / SDL_UnlockTexture. SDL_UpdateTexture(sdl_texture_game, nullptr, main_surface->pixels(), main_surface->pitch()); +#endif if (window.size_changed && window.width > 0 && window.height > 0) { // Based on SDL2 function UpdateLogicalSize @@ -1266,10 +1297,9 @@ void Sdl2Ui::vGetConfig(Game_ConfigVideo& cfg) const { cfg.pause_when_focus_lost.Lock(false); cfg.pause_when_focus_lost.SetOptionVisible(false); #elif defined(__WIIU__) - // FIXME: Some options below may crash, better disable for now + // Only makes the screen flicker cfg.fullscreen.SetOptionVisible(false); - cfg.window_zoom.SetOptionVisible(false); - cfg.vsync.SetOptionVisible(false); + // WiiU always pauses apps in the background cfg.pause_when_focus_lost.SetOptionVisible(false); #endif } diff --git a/src/platform/sdl/sdl2_ui.h b/src/platform/sdl/sdl2_ui.h index bbade7033d..cef74fe1fd 100644 --- a/src/platform/sdl/sdl2_ui.h +++ b/src/platform/sdl/sdl2_ui.h @@ -65,7 +65,7 @@ class Sdl2Ui final : public BaseUi { void UpdateDisplay() override; void SetTitle(const std::string &title) override; bool ShowCursor(bool flag) override; - void ProcessEvents() override; + bool ProcessEvents() override; void SetScalingMode(ConfigEnum::ScalingMode) override; void ToggleStretch() override; void ToggleVsync() override; diff --git a/src/platform/sdl/sdl_audio.cpp b/src/platform/sdl/sdl_audio.cpp index 063fcfc498..16d0a4ecfa 100644 --- a/src/platform/sdl/sdl_audio.cpp +++ b/src/platform/sdl/sdl_audio.cpp @@ -64,6 +64,7 @@ AudioDecoder::Format sdl_format_to_format(Uint16 format) { return AudioDecoder::Format::F32; #endif default: + Output::Warning("Couldn't find GenericAudio format for {:#x}", format); assert(false); } @@ -96,7 +97,7 @@ SdlAudio::SdlAudio(const Game_ConfigAudio& cfg) : SDL_AudioSpec want = {}; SDL_AudioSpec have = {}; want.freq = frequency; - want.format = AUDIO_S16; + want.format = AUDIO_S16SYS; want.channels = 2; want.samples = 2048; want.callback = sdl_audio_callback; diff --git a/src/platform/sdl/sdl_ui.cpp b/src/platform/sdl/sdl_ui.cpp index 04961a612f..29fc05f7d2 100644 --- a/src/platform/sdl/sdl_ui.cpp +++ b/src/platform/sdl/sdl_ui.cpp @@ -404,7 +404,7 @@ void SdlUi::ToggleZoom() { EndDisplayModeChange(); } -void SdlUi::ProcessEvents() { +bool SdlUi::ProcessEvents() { SDL_Event evnt; // Poll SDL events and process them @@ -414,6 +414,8 @@ void SdlUi::ProcessEvents() { if (Player::exit_flag) break; } + + return true; } void SdlUi::UpdateDisplay() { diff --git a/src/platform/sdl/sdl_ui.h b/src/platform/sdl/sdl_ui.h index 775957ffa3..15c1797db5 100644 --- a/src/platform/sdl/sdl_ui.h +++ b/src/platform/sdl/sdl_ui.h @@ -63,7 +63,7 @@ class SdlUi final : public BaseUi { void UpdateDisplay() override; void SetTitle(const std::string &title) override; bool ShowCursor(bool flag) override; - void ProcessEvents() override; + bool ProcessEvents() override; void vGetConfig(Game_ConfigVideo& cfg) const override; #ifdef SUPPORT_AUDIO diff --git a/src/platform/switch/ui.cpp b/src/platform/switch/ui.cpp index 1291a15135..1ef3f28bd0 100644 --- a/src/platform/switch/ui.cpp +++ b/src/platform/switch/ui.cpp @@ -390,7 +390,7 @@ NxUi::~NxUi() { appletUnhook(&applet_hook_cookie); } -void NxUi::ProcessEvents() { +bool NxUi::ProcessEvents() { // handle system events appletMainLoop(); @@ -453,6 +453,8 @@ void NxUi::ProcessEvents() { } } } + + return true; } void NxUi::UpdateDisplay() { diff --git a/src/platform/switch/ui.h b/src/platform/switch/ui.h index 4c6ccf0027..d289f0d029 100644 --- a/src/platform/switch/ui.h +++ b/src/platform/switch/ui.h @@ -48,7 +48,7 @@ class NxUi final : public BaseUi { */ /** @{ */ void UpdateDisplay() override; - void ProcessEvents() override; + bool ProcessEvents() override; void ToggleStretch() override; void ToggleTouchUi() override; void vGetConfig(Game_ConfigVideo& cfg) const override; diff --git a/src/platform/wiiu/input_buttons.cpp b/src/platform/wiiu/input_buttons.cpp index b90ea8f3c0..60eb42b161 100644 --- a/src/platform/wiiu/input_buttons.cpp +++ b/src/platform/wiiu/input_buttons.cpp @@ -27,10 +27,10 @@ Input::ButtonMappingArray Input::GetDefaultButtonMappings() { {DOWN, Keys::JOY_DPAD_DOWN}, {LEFT, Keys::JOY_DPAD_LEFT}, {RIGHT, Keys::JOY_DPAD_RIGHT}, - {DECISION, Keys::JOY_A}, - {CANCEL, Keys::JOY_B}, - {CANCEL, Keys::JOY_X}, - {SHIFT, Keys::JOY_Y}, + {DECISION, Keys::JOY_B}, + {CANCEL, Keys::JOY_A}, + {CANCEL, Keys::JOY_Y}, + {SHIFT, Keys::JOY_X}, {N0, Keys::JOY_LSTICK}, {N5, Keys::JOY_RSTICK}, {DEBUG_ABORT_EVENT, Keys::JOY_SHOULDER_LEFT}, @@ -65,17 +65,18 @@ Input::ButtonMappingArray Input::GetDefaultButtonMappings() { } Input::KeyNamesArray Input::GetInputKeyNames() { - // FIXME: Wiimote mapping is broken, consider removing + // FIXME: The mapping is named in terms of WiiU Gamepad / Controller + // For Wiimote the reported buttons change depending whether a Nunchuck is connected return { - {Keys::JOY_A, "A"}, // 2 (Wiimote) - {Keys::JOY_B, "B"}, // 1 (Wiimote) - {Keys::JOY_X, "X"}, // (Pad/CC/Pro) / B (Wiimote) / Z (Wiimote+Nunchuck) - {Keys::JOY_Y, "Y"}, // (Pad/CC/Pro) / A (Wiimote) / C (Wiimote+Nunchuck) + {Keys::JOY_B, "A"}, // 2 (Wiimote) / A (Wiimote+Nunchuck) + {Keys::JOY_A, "B"}, // 1 (Wiimote) / B (Wiimote+Nunchuck) + {Keys::JOY_Y, "X"}, // (Pad/CC/Pro) / B (Wiimote) / Z (Wiimote+Nunchuck) + {Keys::JOY_X, "Y"}, // (Pad/CC/Pro) / A (Wiimote) / C (Wiimote+Nunchuck) {Keys::JOY_BACK, "-"}, {Keys::JOY_START, "+"}, - {Keys::JOY_GUIDE, "Home"}, // FIXME: not mapped at all, maybe use custom trigger - {Keys::JOY_SHOULDER_LEFT, "L"}, - {Keys::JOY_SHOULDER_RIGHT, "R"}, + {Keys::JOY_GUIDE, "Home"}, // The Home Key is not notified + {Keys::JOY_SHOULDER_LEFT, "L"}, // 1 (Wiimote+Nunchuck) + {Keys::JOY_SHOULDER_RIGHT, "R"}, // 2 (Wiimote+Nunchuck) {Keys::JOY_LTRIGGER_FULL, "ZL"}, {Keys::JOY_RTRIGGER_FULL, "ZR"}, diff --git a/src/platform/wiiu/main.cpp b/src/platform/wiiu/main.cpp new file mode 100644 index 0000000000..02a93fc89f --- /dev/null +++ b/src/platform/wiiu/main.cpp @@ -0,0 +1,163 @@ +/* + * This file is part of EasyRPG Player. + * + * EasyRPG Player is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Player is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Player. If not, see . + */ + +#include +#include +#include +#include +#include +#include "player.h" +#include "utils.h" +#include "output.h" + +#ifdef USE_SDL // SDL might wrap main() +# include +#endif + +#include +#include +#include +#include + +using namespace std::chrono_literals; + +static bool procUiExited = false; + +#ifdef NDEBUG +// stubbed +static void initLogging() {} +static void deinitLogging() {} +#else +#include +#include +#include +#include + +static bool moduleLogInit = false; +static bool cafeLogInit = false; +static bool udpLogInit = false; + +static void initLogging() { + if (!(moduleLogInit = WHBLogModuleInit())) { + cafeLogInit = WHBLogCafeInit(); + udpLogInit = WHBLogUdpInit(); + } +} + +static void deinitLogging() { + if (moduleLogInit) { + WHBLogModuleDeinit(); + moduleLogInit = false; + } + if (cafeLogInit) { + WHBLogCafeDeinit(); + cafeLogInit = false; + } + if (udpLogInit) { + WHBLogUdpDeinit(); + udpLogInit = false; + } +} +#endif + +static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserData /* userdata */) { + std::string m = std::string("[" GAME_TITLE "] ") + + Output::LogLevelToString(lvl) + ": " + msg; + +#ifdef NDEBUG + OSReport("%s\n", m.c_str()); +#else + WHBLogPrintf("%s\n", m.c_str()); +#endif +} + +static uint32_t SaveCallback(void*) { + OSSavesDone_ReadyToRelease(); + return 0; +} + +bool WiiU_ProcessProcUI() { + ProcUIStatus status = ProcUIProcessMessages(TRUE); + if (status == PROCUI_STATUS_EXITING) { + procUiExited = true; + return false; + } else if (status == PROCUI_STATUS_RELEASE_FOREGROUND) { + ProcUIDrawDoneRelease(); + } + return true; +} + +void WiiU_Exit() { + Output::Debug("Shutdown Reason: {}", procUiExited ? "HOME Menu" : "Player Exit"); + + if (!procUiExited) { + // Exit was not through the Home Menu + // Manually launch the system menu + SYSLaunchMenu(); + Game_Clock::SleepFor(10ms); + while (WiiU_ProcessProcUI()) {} + } + + ProcUIShutdown(); + + deinitLogging(); +} + +/** + * If the main function ever needs to change, be sure to update the `main()` + * functions of the other platforms as well. + */ +extern "C" int main(int argc, char* argv[]) { + std::vector args{argv, argv + argc}; + + initLogging(); + ProcUIInitEx(SaveCallback, nullptr); + + Output::SetLogCallback(LogCallback); + + const char *default_dir = "fs:/vol/external01/wiiu/apps/easyrpg-player"; + + char working_dir[256]; + getcwd(working_dir, 255); + + // Check if wuhb has some files inside or not + if(::access("fs:/vol/content/RPG_RT.lmt", F_OK) == 0) { + Output::Debug("Running packaged game from wuhb."); + std::string cafe_dir = "fs:/vol/content"; + + args.push_back("--project-path"); + args.push_back(cafe_dir); + + // Save directory is where the wuhb is located + args.push_back("--save-path"); + args.push_back(working_dir); + } else if(::access(default_dir, F_OK) == 0) { + chdir(default_dir); + } else { + // fall back to current working directory + args.push_back("--project-path"); + args.push_back(working_dir); + } + + // Setup teardown code + atexit(WiiU_Exit); + + Player::Init(std::move(args)); + Player::Run(); + + return Player::exit_code; +} diff --git a/src/platform/wiiu/main.h b/src/platform/wiiu/main.h new file mode 100644 index 0000000000..35525cf4aa --- /dev/null +++ b/src/platform/wiiu/main.h @@ -0,0 +1,18 @@ +/* + * This file is part of EasyRPG Player. + * + * EasyRPG Player is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Player is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Player. If not, see . + */ + +bool WiiU_ProcessProcUI(); diff --git a/src/player.cpp b/src/player.cpp index ae4120e39a..7645c3f16b 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -229,10 +229,22 @@ void Player::MainLoop() { Player::UpdateInput(); + if (!DisplayUi->ProcessEvents()) { + Scene::PopUntil(Scene::Null); + Player::Exit(); + return; + } + int num_updates = 0; while (Game_Clock::NextGameTimeStep()) { if (num_updates > 0) { Player::UpdateInput(); + + if (!DisplayUi->ProcessEvents()) { + Scene::PopUntil(Scene::Null); + Player::Exit(); + return; + } } Scene::old_instances.clear(); @@ -306,9 +318,6 @@ void Player::UpdateInput() { if (Main_Data::game_quit) { reset_flag |= Main_Data::game_quit->ShouldQuit(); } - - // Update Logic: - DisplayUi->ProcessEvents(); } void Player::Update(bool update_scene) { diff --git a/src/system.h b/src/system.h index c2f627d2c7..3b8e1aa5f5 100644 --- a/src/system.h +++ b/src/system.h @@ -60,17 +60,21 @@ #elif defined(__3DS__) # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS +# define USE_CUSTOM_FILEBUF 4 * 1024 #elif defined(__vita__) # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS +# define USE_CUSTOM_FILEBUF 4 * 1024 #elif defined(__wii__) # include # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS +# define USE_CUSTOM_FILEBUF 4 * 1024 #elif defined(__WIIU__) # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS # define SUPPORT_TOUCH +# define USE_CUSTOM_FILEBUF 16 * 1024 #elif defined(_WIN32) # define SUPPORT_ZOOM # define SUPPORT_MOUSE @@ -81,6 +85,7 @@ #elif defined(__SWITCH__) # define SUPPORT_JOYSTICK # define SUPPORT_JOYSTICK_AXIS +# define USE_CUSTOM_FILEBUF 16 * 1024 #elif defined(PLAYER_AMIGA) && !defined(__AROS__) # define SUPPORT_ZOOM # define SUPPORT_MOUSE