diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 926ed4a9..29af2648 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -86,7 +86,11 @@ jobs: run: | cd build ninja - + + - name: Prepare artifact + if: ${{ inputs.deploymode == 'release' }} + run: mv bin/Cemu_release bin/Cemu + - name: Upload artifact uses: actions/upload-artifact@v3 if: ${{ inputs.deploymode == 'release' }} @@ -188,10 +192,14 @@ jobs: run: | cd build cmake --build . --config ${{ env.BUILD_MODE }} -j 2 - + + - name: Prepare artifact + if: ${{ inputs.deploymode == 'release' }} + run: Rename-Item bin/Cemu_release.exe Cemu.exe + - name: Upload artifact uses: actions/upload-artifact@v3 if: ${{ inputs.deploymode == 'release' }} with: name: cemu-bin-windows-x64 - path: ./bin/Cemu.exe \ No newline at end of file + path: ./bin/Cemu.exe diff --git a/.github/workflows/deploy_experimental.yml b/.github/workflows/deploy_experimental.yml index 32000986..afe3dee7 100644 --- a/.github/workflows/deploy_experimental.yml +++ b/.github/workflows/deploy_experimental.yml @@ -63,4 +63,4 @@ jobs: wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz tar xvzf ghr.tar.gz; rm ghr.tar.gz echo "[INFO] Release tag: v${{ env.CEMU_VERSION }}" - ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "" "v${{ env.CEMU_VERSION }}" ./upload + ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "Cemu experimental release - [changelog](https://cemu.info/changelog.html)" "v${{ env.CEMU_VERSION }}" ./upload diff --git a/.gitignore b/.gitignore index 6feed97f..ce7f91c2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,14 +18,15 @@ build/ out/ .cache/ -bin/Cemu +bin/Cemu_* +bin/Cemu_*.exe # Cemu bin files bin/otp.bin bin/seeprom.bin bin/log.txt -bin/Cemu.pdb -bin/Cemu.ilk +bin/Cemu_*.pdb +bin/Cemu_*.ilk bin/Cemu.exe.backup bin/mlc01/* bin/settings.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index a47fe8af..e9f7458e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,15 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) if (MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin) # floating point model: precise, fiber safe optimizations - add_compile_options(/EHsc /fp:precise /GT) + add_compile_options(/EHsc /fp:precise) + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # Speeds up static linking (especially helpful in incremental compilation) + if((CMAKE_LINKER MATCHES ".*lld-link.*") AND (CMAKE_AR MATCHES ".*llvm-lib.*")) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY STATIC_LIBRARY_OPTIONS /llvmlibthin) + endif() + else() + add_compile_options(/GT) + endif() if (PUBLIC_RELEASE) message(STATUS "Using additional optimization flags for MSVC") add_compile_options(/Oi /Ot) # enable intrinsic functions, favor speed @@ -81,7 +89,7 @@ find_package(ZLIB REQUIRED) find_package(zstd MODULE REQUIRED) # MODULE so that zstd::zstd is available find_package(OpenSSL COMPONENTS Crypto SSL REQUIRED) find_package(glm REQUIRED) -find_package(fmt 7.0.0 REQUIRED) +find_package(fmt 9.1.0 REQUIRED) find_package(PNG REQUIRED) # glslang versions older than 11.11.0 define targets without a namespace diff --git a/dependencies/DirectX_2010/XAudio2.h b/dependencies/DirectX_2010/XAudio2.h index db0ebd8f..a42c0afc 100644 --- a/dependencies/DirectX_2010/XAudio2.h +++ b/dependencies/DirectX_2010/XAudio2.h @@ -48,10 +48,15 @@ //DEFINE_CLSID(XAudio2_Debug, 47199894, 7cc2, 444d, 98, 73, ce, d2, 56, 2c, c6, 0e); // XAudio 2.7 (June 2010 SDK) +#ifdef __clang__ +class __declspec(uuid("5a508685-a254-4fba-9b82-9a24b00306af")) XAudio2; extern "C" const GUID CLSID_XAudio2; +class __declspec(uuid("db05ea35-0329-4d4b-a53a-6dead03d3852")) XAudio2_Debug; extern "C" const GUID CLSID_XAudio2_Debug; +struct __declspec(uuid("8bcf1f58-9fe7-4583-8ac6-e2adc465c8bb")) IXAudio2; extern "C" const GUID IID_IXAudio2; +#else DEFINE_CLSID(XAudio2, 5a508685, a254, 4fba, 9b, 82, 9a, 24, b0, 03, 06, af); DEFINE_CLSID(XAudio2_Debug, db05ea35, 0329, 4d4b, a5, 3a, 6d, ea, d0, 3d, 38, 52); DEFINE_IID(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb); - +#endif // Ignore the rest of this header if only the GUID definitions were requested #ifndef GUID_DEFS_ONLY diff --git a/dependencies/ih264d/common/x86/ih264_platform_macros.h b/dependencies/ih264d/common/x86/ih264_platform_macros.h index 0b15cf5a..ebc1b106 100644 --- a/dependencies/ih264d/common/x86/ih264_platform_macros.h +++ b/dependencies/ih264d/common/x86/ih264_platform_macros.h @@ -40,6 +40,9 @@ #include #include +#if defined(_MSC_VER) && defined(__clang__) +#include +#endif #define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x)) #define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x)) @@ -71,7 +74,7 @@ /* For MSVC x64 */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) static inline int __builtin_clz(unsigned x) { diff --git a/dependencies/vcpkg_overlay_ports/fmt/portfile.cmake b/dependencies/vcpkg_overlay_ports/fmt/portfile.cmake index aef43b47..e3edc0f6 100644 --- a/dependencies/vcpkg_overlay_ports/fmt/portfile.cmake +++ b/dependencies/vcpkg_overlay_ports/fmt/portfile.cmake @@ -1,10 +1,10 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO fmtlib/fmt - REF 7bdf0628b1276379886c7f6dda2cef2b3b374f0b # v7.1.3 - SHA512 52ea8f9d2c0cb52ec3a740e38fcdfd6a0318566e3b599bd2e8d557168642d005c0a59bc213cff2641a88fed3bb771d15f46c39035ccd64809569af982aba47aa + REF a33701196adfad74917046096bf5a2aa0ab0bb50 # v9.1.0 + SHA512 0faf00e99b332fcb3d9fc50cc9649ddc004ca9035f3652c1a001facee725dab09f67b65a9dfcce0aedb47e76c74c45a9262a1fd6e250a9e9a27c7d021c8ee6b8 HEAD_REF master - PATCHES fix-warning4189.patch + # PATCHES fix-warning4189.patch ) vcpkg_cmake_configure( diff --git a/dist/linux/info.cemu.Cemu.metainfo.xml b/dist/linux/info.cemu.Cemu.metainfo.xml index 4fff800a..d270a8ab 100644 --- a/dist/linux/info.cemu.Cemu.metainfo.xml +++ b/dist/linux/info.cemu.Cemu.metainfo.xml @@ -21,7 +21,7 @@

Cemu ist ein Nintendo Wii U-Emulator, der die meisten Wii U Spiele und Homebrew in einem spielbaren Zustand ausführen kann. Erstellt von Exzap, und geschrieben in C/C++.

Cemu est un émulateur de Wii U capable de lancer la plupart des jeux Wii U et des homebrews en interface de jeu. Crée par Exzap, et développé en C/C++.

Cemu is een Nintendo Wii U emulator die de meeste Wii U en Homebrew games speelbaar kan runnen. Het project is begonnen door Exzap, en het is geschreven in C/C++.

-

Το Cemu είναι ένας προσομοιωτής της κονσόλας Nintendo Wii U που υποστηρίζει τεπίσημα παιχνίδια, καθώς και μη επίσημα προγράμματα ("homebrew"), για το Wii U. Δημιουργήθηκε από τον Exzap σε C/C++.

+

Το Cemu είναι ένας προσομοιωτής της κονσόλας Nintendo Wii U που προσομοιώνει επίσημα παιχνίδια, καθώς και μη επίσημα προγράμματα ("homebrew") του Wii U. Δημιουργήθηκε από τον Exzap σε C/C++.

Cemu es un emulador de Nintendo Wii U que es capaz de ejecutar la mayoría de los juegos de Wii U y homebrew en un estado jugable. Creado por Exzap, y escrito en C y C++.

Cemu é um emulador de Nintendo Wii U que é capaz de executar a maioría dos jogos de Wii U e homebrew em um estado jogavel. Criado por Exzap, e escrito em C e C++.

Cemu è un emulatore del Nintendo Wii U in grado di eseguire in stato giocabile la maggior parte dei giochi e homebrew per Wii U. Creato da Exzap, e scritto in C/C++.

@@ -30,7 +30,7 @@

Dieser Emulator zielt darauf ab, sowohl hohe Genauigkeit als auch Leistung zu bieten, und wird aktiv mit neuen Funktionen und Korrekturen weiterentwickelt, um Kompatibilität, Komfort und Benutzerfreundlichkeit zu verbessern.

Cet émulateur vise à la fois à offrir fidélité et performance, il est activement développé avec des nouvelles fonctionnalités et des correctifs pour augmenter la compatibilité, la commodité et la facilité d'utilisation.

De emulator richt zich op integriteit en snelheid, en wordt continu verder ontwikkeld met nieuwe toevoegingen en fixes om de compatibiliteit, het gemak en de gebruiksvriendelijkheid te verbeteren.

-

Ο προσομοιωτής αυτός στοχεύει τόσο στην ακρίβεια, όσο και στην ταχύτητα. Βελτιώνεται συνεχώς με νέες δυνατότητες και διορθώσεις που τον καθιστούν πιο βολικό, εύκολο στην χρήση και συμβατό με περισσότερα παιχνίδια.

+

Ο προσομοιωτής αυτός στοχεύει τόσο στην ακρίβεια, όσο και στην ταχύτητα, και βελτιώνεται συνεχώς με νέες δυνατότητες και διορθώσεις που τον καθιστούν πιο βολικό, εύκολο στην χρήση και συμβατό με περισσότερα παιχνίδια.

Este emulador tiene como objetivo proporcionar tanto alta precisión como rendimiento y se desarrolla activamente con nuevas características y correcciones para mejorar la compatibilidad, la comodidad y la usabilidad.

Esse emulador visa proporcionar tanto alta precisão como rendimento e está sendo ativamente desenvolvido com novas características e correções para melhorar a compatibilidade, a comodidade e a usabilidade.

Questo emulatore ha l'obiettivo di fornire sia alta precisione che alte prestazioni, ed è in continuo sviluppo con nuove funzionalità e correzioni per aumentare la compatibilità, la comodità e l'usabilità.

@@ -39,7 +39,7 @@

Er wird seit Anfang 2015 entwickelt.

Il a été écrit à partir de zéro et son développement a débuté vers le début de l'année 2015.

Ontwikkeling van Cemu begon ongeveer in het voorjaar van 2015.

-

Το Cemu βρίσκεται υπό ανάπτυξη από το 2015.

+

Αρχισε απο το τίποτα και βρίσκεται υπό ανάπτυξη από το 2015.

Fue escrito desde cero y el desarrollo del proyecto comenzó aproximadamente a principios de 2015.

Foi escrito do zero e o desenvolvimento do projeto começou aproximadamente a princípio de 2015.

È stato scritto da zero e lo sviluppo del progetto è cominciato intorno all'inizio del 2015.

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca677710..d3bf8aec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -75,8 +75,10 @@ endif() set_property(TARGET CemuBin PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") set_target_properties(CemuBin PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/" - OUTPUT_NAME "Cemu" + # multi-configuration generators will add a config subdirectory to RUNTIME_OUTPUT_DIRECTORY if no generator expression is used + # to get the same behavior everywhere we append an empty generator expression + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/$<1:>" + OUTPUT_NAME "Cemu_$>" ) target_link_libraries(CemuBin PRIVATE diff --git a/src/Cafe/HW/Espresso/PPCTimer.cpp b/src/Cafe/HW/Espresso/PPCTimer.cpp index bcf1a58d..2a1a7669 100644 --- a/src/Cafe/HW/Espresso/PPCTimer.cpp +++ b/src/Cafe/HW/Espresso/PPCTimer.cpp @@ -110,7 +110,8 @@ uint64 PPCTimer_tscToMicroseconds(uint64 us) uint64 remainder; -#if _MSC_VER < 1923 + +#if _MSC_VER < 1923 || defined(__clang__) const uint64 microseconds = udiv128(r.low, r.high, _rdtscFrequency, &remainder); #else const uint64 microseconds = _udiv128(r.high, r.low, _rdtscFrequency, &remainder); @@ -158,7 +159,7 @@ uint64 PPCTimer_getFromRDTSC() #endif uint64 remainder; -#if _MSC_VER < 1923 +#if _MSC_VER < 1923 || defined(__clang__) uint64 elapsedTick = udiv128(_rdtscAcc.low, _rdtscAcc.high, _rdtscFrequency, &remainder); #else uint64 elapsedTick = _udiv128(_rdtscAcc.high, _rdtscAcc.low, _rdtscFrequency, &remainder); diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index bcdaffa2..ebf425bc 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -441,9 +441,9 @@ void LatteShaderCache_ShowProgress(const std::function & loadUpdateF ImGui::ProgressBar(percentLoaded, { -1, 0 }, ""); if (isPipelines) - text = fmt::format("{}/{} ({}%%)", g_shaderCacheLoaderState.loadedPipelines, g_shaderCacheLoaderState.pipelineFileCount, (int)(percentLoaded * 100)); + text = fmt::format("{}/{} ({}%)", g_shaderCacheLoaderState.loadedPipelines, g_shaderCacheLoaderState.pipelineFileCount, (int)(percentLoaded * 100)); else - text = fmt::format("{}/{} ({}%%)", g_shaderCacheLoaderState.loadedShaderFiles, g_shaderCacheLoaderState.shaderFileCount, (int)(percentLoaded * 100)); + text = fmt::format("{}/{} ({}%)", g_shaderCacheLoaderState.loadedShaderFiles, g_shaderCacheLoaderState.shaderFileCount, (int)(percentLoaded * 100)); ImGui::SetCursorPosX(width - ImGui::CalcTextSize(text.c_str()).x / 2); ImGui::Text("%s", text.c_str()); ImGui::End(); diff --git a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp index 151f0661..2caa2cd0 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp @@ -145,7 +145,7 @@ uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture) bool isCompressedFormat = hostTexture->IsCompressedFormat(); if( isCompressedFormat == false ) { - #if BOOST_OS_WINDOWS +#if BOOST_OS_WINDOWS if (_cpuExtension_AVX2) { __m256i h256 = { 0 }; @@ -157,7 +157,11 @@ uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture) readPtr += (288 / 32); h256 = _mm256_xor_si256(h256, temp); } +#ifdef __clang__ + hashVal = h256[0] + h256[1] + h256[2] + h256[3] + h256[4] + h256[5] + h256[6] + h256[7]; +#else hashVal = h256.m256i_u32[0] + h256.m256i_u32[1] + h256.m256i_u32[2] + h256.m256i_u32[3] + h256.m256i_u32[4] + h256.m256i_u32[5] + h256.m256i_u32[6] + h256.m256i_u32[7]; +#endif } #else if( false ) {} diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index 80c72918..269f30e8 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -378,7 +378,7 @@ void OpenGLRenderer::GetVendorInformation() forceLog_printf("GL_RENDERER: %s", glRendererString ? glRendererString : "unknown"); forceLog_printf("GL_VERSION: %s", glVersionString ? glVersionString : "unknown"); - if(boost::icontains(glVersionString, "Mesa") || IsRunningInWine()) + if(boost::icontains(glVersionString, "Mesa")) { m_vendor = GfxVendor::Mesa; return; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index e033d954..7c81a3c9 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -197,7 +197,9 @@ void VulkanRenderer::DetermineVendor() break; } - if (IsRunningInWine()) + VkDriverId driverId = driverProperties.driverID; + + if(driverId == VK_DRIVER_ID_MESA_RADV || driverId == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA) m_vendor = GfxVendor::Mesa; forceLog_printf("Using GPU: %s", properties.properties.deviceName); @@ -216,7 +218,7 @@ void VulkanRenderer::DetermineVendor() else { forceLog_printf("Driver version (as stored in device info): %08X", properties.properties.driverVersion); - + if(m_vendor == GfxVendor::Nvidia) { // if the driver does not support the extension, diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index 4c99f5df..22c11eba 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -219,7 +219,7 @@ namespace iosu template curl_slist* append_header_param(struct curl_slist* list, const char* format, TArgs&& ... args) { - return curl_slist_append(list, fmt::format(format, std::forward(args)...).c_str()); + return curl_slist_append(list, fmt::format(fmt::runtime(format), std::forward(args)...).c_str()); } bool starts_with(const char* str, const char* pre) diff --git a/src/Cafe/IOSU/legacy/iosu_fpd.cpp b/src/Cafe/IOSU/legacy/iosu_fpd.cpp index 678c187f..ec8733ab 100644 --- a/src/Cafe/IOSU/legacy/iosu_fpd.cpp +++ b/src/Cafe/IOSU/legacy/iosu_fpd.cpp @@ -84,7 +84,7 @@ namespace iosu name = tmp; } - g_friend_notifications.emplace_back(fmt::format(msg_format, name), 5000); + g_friend_notifications.emplace_back(fmt::format(fmt::runtime(msg_format), name), 5000); } } } diff --git a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp index d15f6683..085a2e69 100644 --- a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp +++ b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp @@ -28,7 +28,7 @@ namespace H264 // both of these are required to allow Breath of the Wild to playback the higher res (1080p) videos from the Switch version // we mirror these hacks for user convenience and because there are no downsides uint64 currentTitleId = CafeSystem::GetForegroundTitleId(); - if (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x0005000e101c9300) + if (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x00050000101c9300) return true; return false; } diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index 4238b638..d89d9cec 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -36,7 +36,8 @@ enum class LogType : sint32 template <> struct fmt::formatter : formatter { template - auto format(std::u8string_view v, FormatContext& ctx) { + auto format(std::u8string_view v, FormatContext& ctx) + { string_view s((char*)v.data(), v.size()); return formatter::format(s, ctx); } @@ -52,17 +53,39 @@ bool cemuLog_log(LogType type, std::u8string_view text); bool cemuLog_log(LogType type, std::wstring_view text); void cemuLog_waitForFlush(); // wait until all log lines are written -template -bool cemuLog_log(LogType type, TFmt format, TArgs&&... args) +template +auto ForwardEnum(T t) +{ + if constexpr (std::is_enum_v) + return fmt::underlying(t); + else + return std::forward(t); +} + +template +auto ForwardEnum(std::tuple t) +{ + return std::apply([](auto... x) { return std::make_tuple(ForwardEnum(x)...); }, t); +} + +template +bool cemuLog_log(LogType type, std::basic_string format, TArgs&&... args) { if (!cemuLog_isLoggingEnabled(type)) return false; - const auto format_view = fmt::to_string_view(format); - const auto text = fmt::vformat(format_view, fmt::make_args_checked(format_view, args...)); + const auto format_view = fmt::basic_string_view(format); + const auto text = fmt::vformat(format_view, fmt::make_format_args>(ForwardEnum(args)...)); cemuLog_log(type, std::basic_string_view(text.data(), text.size())); return true; } + +template +bool cemuLog_log(LogType type, const T* format, TArgs&&... args) +{ + auto format_str=std::basic_string(format); + return cemuLog_log(type, format_str, std::forward(args)...); +} // same as cemuLog_log, but only outputs in debug/release mode template diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp index 45b66eed..f953844a 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp @@ -242,7 +242,7 @@ bool DownloadManager::_connect_queryAccountStatusAndServiceURLs() NAPI::NAPI_ECSGetAccountStatus_Result accountStatusResult = NAPI::ECS_GetAccountStatus(authInfo); if (accountStatusResult.apiError != NAPI_RESULT::SUCCESS) { - cemuLog_log(LogType::Force, fmt::format("ECS - Failed to query account status (error: {0} {1})", accountStatusResult.apiError, accountStatusResult.serviceError)); + cemuLog_log(LogType::Force, "ECS - Failed to query account status (error: {0} {1})", accountStatusResult.apiError, accountStatusResult.serviceError); return false; } if (accountStatusResult.accountStatus == NAPI::NAPI_ECSGetAccountStatus_Result::AccountStatus::UNREGISTERED) diff --git a/src/config/ActiveSettings.h b/src/config/ActiveSettings.h index 44b5f509..95ceae16 100644 --- a/src/config/ActiveSettings.h +++ b/src/config/ActiveSettings.h @@ -30,7 +30,7 @@ public: [[nodiscard]] static fs::path GetPath(std::string_view format, TArgs&&... args) { cemu_assert_debug(format.empty() || (format[0] != '/' && format[0] != '\\')); - std::string tmpPathStr = fmt::format(format, std::forward(args)...); + std::string tmpPathStr = fmt::format(fmt::runtime(format), std::forward(args)...); std::basic_string_view s((const char8_t*)tmpPathStr.data(), tmpPathStr.size()); return s_path / fs::path(s); } @@ -46,7 +46,7 @@ public: [[nodiscard]] static fs::path GetMlcPath(std::string_view format, TArgs&&... args) { cemu_assert_debug(format.empty() || (format[0] != '/' && format[0] != '\\')); - auto tmp = fmt::format(format, std::forward(args)...); + auto tmp = fmt::format(fmt::runtime(format), std::forward(args)...); return GetMlcPath() / fs::path(_asUtf8(tmp)); } @@ -54,7 +54,7 @@ public: [[nodiscard]] static fs::path GetMlcPath(std::wstring_view format, TArgs&&... args) { cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); - return GetMlcPath() / fmt::format(format, std::forward(args)...); + return GetMlcPath() / fmt::format(fmt::runtime(format), std::forward(args)...); } // get mlc path to default cemu root dir/mlc01 diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 0cbd3c97..bc1f9f97 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -160,15 +160,15 @@ void CemuConfig::Load(XMLConfigParser& parser) { GameEntry entry{}; entry.rpx_file = boost::nowide::widen(rpx); - entry.title_id = element.get("title_id", 0LL); + entry.title_id = element.get("title_id"); entry.legacy_name = boost::nowide::widen(element.get("name", "")); entry.custom_name = element.get("custom_name", ""); entry.legacy_region = element.get("region", 0); entry.legacy_version = element.get("version", 0); entry.legacy_update_version = element.get("version", 0); entry.legacy_dlc_version = element.get("dlc_version", 0); - entry.legacy_time_played = element.get("time_played", 0ULL); - entry.legacy_last_played = element.get("last_played", 0ULL); + entry.legacy_time_played = element.get("time_played"); + entry.legacy_last_played = element.get("last_played"); entry.favorite = element.get("favorite", false); game_cache_entries.emplace_back(entry); diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index 17e31f7a..e78b30b3 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -217,7 +217,7 @@ void CemuApp::CreateDefaultFiles(bool first_start) // check for mlc01 folder missing if custom path has been set if (!fs::exists(mlc) && !first_start) { - const std::wstring message = fmt::format(_(L"Your mlc01 folder seems to be missing.\n\nThis is where Cemu stores save files, game updates and other Wii U files.\n\nThe expected path is:\n{}\n\nDo you want to create the folder at the expected path?").ToStdWstring(), mlc); + const std::wstring message = fmt::format(fmt::runtime(_(L"Your mlc01 folder seems to be missing.\n\nThis is where Cemu stores save files, game updates and other Wii U files.\n\nThe expected path is:\n{}\n\nDo you want to create the folder at the expected path?").ToStdWstring()), mlc); wxMessageDialog dialog(nullptr, message, "Error", wxCENTRE | wxYES_NO | wxCANCEL| wxICON_WARNING); dialog.SetYesNoCancelLabels(_("Yes"), _("No"), _("Select a custom path")); @@ -293,7 +293,7 @@ void CemuApp::CreateDefaultFiles(bool first_start) catch (const std::exception& ex) { std::stringstream errorMsg; - errorMsg << fmt::format(_("Couldn't create a required mlc01 subfolder or file!\n\nError: {0}\nTarget path:\n{1}").ToStdString(), ex.what(), boost::nowide::narrow(mlc)); + errorMsg << fmt::format(fmt::runtime(_("Couldn't create a required mlc01 subfolder or file!\n\nError: {0}\nTarget path:\n{1}").ToStdString()), ex.what(), boost::nowide::narrow(mlc)); #if BOOST_OS_WINDOWS const DWORD lastError = GetLastError(); @@ -319,7 +319,7 @@ void CemuApp::CreateDefaultFiles(bool first_start) catch (const std::exception& ex) { std::stringstream errorMsg; - errorMsg << fmt::format(_("Couldn't create a required cemu directory or file!\n\nError: {0}").ToStdString(), ex.what()); + errorMsg << fmt::format(fmt::runtime(_("Couldn't create a required cemu directory or file!\n\nError: {0}").ToStdString()), ex.what()); #if BOOST_OS_WINDOWS const DWORD lastError = GetLastError(); diff --git a/src/gui/ChecksumTool.cpp b/src/gui/ChecksumTool.cpp index 74422c9b..b8393330 100644 --- a/src/gui/ChecksumTool.cpp +++ b/src/gui/ChecksumTool.cpp @@ -4,6 +4,7 @@ #include "gui/helpers/wxCustomEvents.h" #include "util/helpers/helpers.h" #include "gui/helpers/wxHelpers.h" +#include "gui/wxHelper.h" #include "Cafe/Filesystem/WUD/wud.h" #include @@ -518,7 +519,7 @@ void ChecksumTool::VerifyJsonEntry(const rapidjson::Document& doc) file.flush(); file.close(); - wxLaunchDefaultBrowser(fmt::format("file:{}", path)); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", path))); } else wxMessageBox(_("Can't open file to write!"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); diff --git a/src/gui/GameUpdateWindow.cpp b/src/gui/GameUpdateWindow.cpp index a42d4087..c689dd6f 100644 --- a/src/gui/GameUpdateWindow.cpp +++ b/src/gui/GameUpdateWindow.cpp @@ -63,7 +63,7 @@ bool GameUpdateWindow::ParseUpdate(const fs::path& metaPath) std::string typeStrCurrentlyInstalled = _GetTitleIdTypeStr(tmp.GetAppTitleId()); std::string wxMsg = wxHelper::MakeUTF8(_("It seems that there is already a title installed at the target location but it has a different type.\nCurrently installed: \'{}\' Installing: \'{}\'\n\nThis can happen for titles which were installed with very old Cemu versions.\nDo you still want to continue with the installation? It will replace the currently installed title.")); - wxMessageDialog dialog(this, fmt::format(wxMsg, typeStrCurrentlyInstalled, typeStrToInstall), _("Warning"), wxCENTRE | wxYES_NO | wxICON_EXCLAMATION); + wxMessageDialog dialog(this, fmt::format(fmt::runtime(wxMsg), typeStrCurrentlyInstalled, typeStrToInstall), _("Warning"), wxCENTRE | wxYES_NO | wxICON_EXCLAMATION); if (dialog.ShowModal() != wxID_YES) return false; } diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 012b8557..78e1feec 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -1110,7 +1110,7 @@ void GeneralSettings2::OnAccountDelete(wxCommandEvent& event) auto& account = obj->GetAccount(); const std::wstring format_str = _("Are you sure you want to delete the account {} with id {:x}?").ToStdWstring(); - const std::wstring msg = fmt::format(format_str, + const std::wstring msg = fmt::format(fmt::runtime(format_str), std::wstring{ account.GetMiiName() }, account.GetPersistentId()); const int answer = wxMessageBox(msg, _("Confirmation"), wxYES_NO | wxCENTRE | wxICON_QUESTION, this); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index b23a5ca7..ec821ce5 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1803,7 +1803,7 @@ public: void AddHeaderInfo(wxWindow* parent, wxSizer* sizer) { - auto versionString = fmt::format(_("Cemu\nVersion {0}\nCompiled on {1}\nOriginal authors: {2}").ToStdString(), BUILD_VERSION_STRING, BUILD_DATE, "Exzap, Petergov"); + auto versionString = fmt::format(fmt::runtime(_("Cemu\nVersion {0}\nCompiled on {1}\nOriginal authors: {2}").ToStdString()), BUILD_VERSION_STRING, BUILD_DATE, "Exzap, Petergov"); sizer->Add(new wxStaticText(parent, wxID_ANY, versionString), wxSizerFlags().Border(wxALL, 3).Border(wxTOP, 10)); sizer->Add(new wxHyperlinkCtrl(parent, -1, "https://cemu.info", "https://cemu.info"), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 3)); @@ -1945,7 +1945,7 @@ public: "/*****************************************************************************/\r\n" ); delete fs; - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(tempPath))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(tempPath)))); }); lineSizer->Add(noticeLink, 0); lineSizer->Add(new wxStaticText(parent, -1, ")"), 0); diff --git a/src/gui/TitleManager.cpp b/src/gui/TitleManager.cpp index 370786b6..b643ab8f 100644 --- a/src/gui/TitleManager.cpp +++ b/src/gui/TitleManager.cpp @@ -5,6 +5,7 @@ #include "Cafe/TitleList/GameInfo.h" #include "util/helpers/helpers.h" #include "gui/helpers/wxHelpers.h" +#include "gui/wxHelper.h" #include "gui/components/wxTitleManagerList.h" #include "gui/components/wxDownloadManagerList.h" #include "gui/GameUpdateWindow.h" @@ -479,7 +480,7 @@ void TitleManager::OnSaveOpenDirectory(wxCommandEvent& event) if (!fs::exists(target) || !fs::is_directory(target)) return; - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(target))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(target)))); } void TitleManager::OnSaveDelete(wxCommandEvent& event) diff --git a/src/gui/canvas/VulkanCanvas.cpp b/src/gui/canvas/VulkanCanvas.cpp index dfad8c9a..b8faa8c7 100644 --- a/src/gui/canvas/VulkanCanvas.cpp +++ b/src/gui/canvas/VulkanCanvas.cpp @@ -27,7 +27,7 @@ VulkanCanvas::VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_wi } catch(const std::exception& ex) { - const auto msg = fmt::format(_("Error when initializing Vulkan renderer:\n{}").ToStdString(), ex.what()); + const auto msg = fmt::format(fmt::runtime(_("Error when initializing Vulkan renderer:\n{}").ToStdString()), ex.what()); forceLog_printf(const_cast(msg.c_str())); wxMessageDialog dialog(this, msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR); dialog.ShowModal(); diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index a9d2946c..87eb5cdd 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -51,11 +51,18 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id) : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList) { CreateListColumns(); - + + const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0}; + wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth); + blank.UseAlpha(true); + m_image_list = new wxImageList(kIconWidth, kIconWidth); + m_image_list->Add(blank); wxListCtrl::SetImageList(m_image_list, wxIMAGE_LIST_NORMAL); m_image_list_small = new wxImageList(kListIconWidth, kListIconWidth); + wxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth}); + m_image_list_small->Add(blank); wxListCtrl::SetImageList(m_image_list_small, wxIMAGE_LIST_SMALL); m_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER); @@ -556,7 +563,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event) { fs::path path(gameInfo.GetBase().GetPath()); _stripPathFilename(path); - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(path))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(path)))); break; } case kWikiPage: @@ -570,28 +577,28 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event) wxASSERT(!tokens.empty()); const std::string company_code = gameInfo.GetBase().GetMetaInfo()->GetCompanyCode(); wxASSERT(company_code.size() >= 2); - wxLaunchDefaultBrowser(fmt::format("https://wiki.cemu.info/wiki/{}{}", *tokens.rbegin(), company_code.substr(company_code.size() - 2).c_str())); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("https://wiki.cemu.info/wiki/{}{}", *tokens.rbegin(), company_code.substr(company_code.size() - 2).c_str()))); } break; } case kContextMenuSaveFolder: { - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(gameInfo.GetSaveFolder()))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(gameInfo.GetSaveFolder())))); break; } case kContextMenuUpdateFolder: { fs::path path(gameInfo.GetUpdate().GetPath()); _stripPathFilename(path); - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(path))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(path)))); break; } case kContextMenuDLCFolder: { fs::path path(gameInfo.GetAOC().front().GetPath()); _stripPathFilename(path); - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(path))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(path)))); break; } case kContextMenuEditGraphicPacks: @@ -857,15 +864,14 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event) isNewEntry = true; } - int icon = 0; - int icon_small = 0; - bool hasIcon = QueryIconForTitle(baseTitleId, icon, icon_small); + int icon = 0; /* 0 is the default empty icon */ + int icon_small = 0; /* 0 is the default empty icon */ + QueryIconForTitle(baseTitleId, icon, icon_small); if (m_style == Style::kList) { - if(hasIcon) - SetItemColumnImage(index, ColumnIcon, icon_small); - + SetItemColumnImage(index, ColumnIcon, icon_small); + SetItem(index, ColumnName, wxHelper::FromUtf8(GetNameByTitleId(baseTitleId))); SetItem(index, ColumnVersion, fmt::format("{}", gameInfo.GetVersion())); @@ -912,13 +918,11 @@ void wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event) } else if (m_style == Style::kIcons) { - if(hasIcon) - SetItemImage(index, icon); + SetItemImage(index, icon); } else if (m_style == Style::kSmallIcons) { - if (hasIcon) - SetItemImage(index, icon_small); + SetItemImage(index, icon_small); } if (isNewEntry) UpdateItemColors(index); diff --git a/src/gui/components/wxTitleManagerList.cpp b/src/gui/components/wxTitleManagerList.cpp index 9ac31bce..99e6ed94 100644 --- a/src/gui/components/wxTitleManagerList.cpp +++ b/src/gui/components/wxTitleManagerList.cpp @@ -293,23 +293,23 @@ void wxTitleManagerList::OnConvertToCompressedFormat(uint64 titleId) std::string msg = wxHelper::MakeUTF8(_("The following content will be converted to a compressed Wii U archive file (.wua):\n \n")); if (titleInfo_base.IsValid()) - msg.append(fmt::format(wxHelper::MakeUTF8(_("Base game: {}")), _utf8Wrapper(titleInfo_base.GetPath()))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("Base game: {}"))), _utf8Wrapper(titleInfo_base.GetPath()))); else - msg.append(fmt::format(wxHelper::MakeUTF8(_("Base game: Not installed")))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("Base game: Not installed"))))); msg.append("\n"); if (titleInfo_update.IsValid()) - msg.append(fmt::format(wxHelper::MakeUTF8(_("Update: {}")), _utf8Wrapper(titleInfo_update.GetPath()))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("Update: {}"))), _utf8Wrapper(titleInfo_update.GetPath()))); else - msg.append(fmt::format(wxHelper::MakeUTF8(_("Update: Not installed")))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("Update: Not installed"))))); msg.append("\n"); if (titleInfo_aoc.IsValid()) - msg.append(fmt::format(wxHelper::MakeUTF8(_("DLC: {}")), _utf8Wrapper(titleInfo_aoc.GetPath()))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("DLC: {}"))), _utf8Wrapper(titleInfo_aoc.GetPath()))); else - msg.append(fmt::format(wxHelper::MakeUTF8(_("DLC: Not installed")))); + msg.append(fmt::format(fmt::runtime(wxHelper::MakeUTF8(_("DLC: Not installed"))))); const int answer = wxMessageBox(wxString::FromUTF8(msg), _("Confirmation"), wxOK | wxCANCEL | wxCENTRE | wxICON_QUESTION, this); if (answer != wxOK) @@ -852,7 +852,7 @@ void wxTitleManagerList::OnContextMenuSelected(wxCommandEvent& event) case kContextMenuOpenDirectory: { const auto path = fs::is_directory(entry->path) ? entry->path : entry->path.parent_path(); - wxLaunchDefaultBrowser(fmt::format("file:{}", _utf8Wrapper(path))); + wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _utf8Wrapper(path)))); } break; case kContextMenuDelete: diff --git a/src/gui/dialogs/CreateAccount/wxCreateAccountDialog.cpp b/src/gui/dialogs/CreateAccount/wxCreateAccountDialog.cpp index 49e7f5ec..71b56637 100644 --- a/src/gui/dialogs/CreateAccount/wxCreateAccountDialog.cpp +++ b/src/gui/dialogs/CreateAccount/wxCreateAccountDialog.cpp @@ -71,7 +71,7 @@ void wxCreateAccountDialog::OnOK(wxCommandEvent& event) const auto id = GetPersistentId(); if(id < Account::kMinPersistendId) { - wxMessageBox(fmt::format(_("The persistent id must be greater than {:x}!").ToStdString(), Account::kMinPersistendId), + wxMessageBox(fmt::format(fmt::runtime(_("The persistent id must be greater than {:x}!").ToStdString()), Account::kMinPersistendId), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); return; } @@ -79,7 +79,7 @@ void wxCreateAccountDialog::OnOK(wxCommandEvent& event) const auto& account = Account::GetAccount(id); if(account.GetPersistentId() == id) { - const std::wstring msg = fmt::format(_("The persistent id {:x} is already in use by account {}!").ToStdWstring(), + const std::wstring msg = fmt::format(fmt::runtime(_("The persistent id {:x} is already in use by account {}!").ToStdWstring()), account.GetPersistentId(), std::wstring{ account.GetMiiName() }); wxMessageBox(msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); return; diff --git a/src/gui/helpers/wxHelpers.h b/src/gui/helpers/wxHelpers.h index 96c8dcfa..8fd0f8a9 100644 --- a/src/gui/helpers/wxHelpers.h +++ b/src/gui/helpers/wxHelpers.h @@ -48,13 +48,13 @@ template wxString wxStringFormat2(const wxString& format, TArgs&&...args) { // ignores locale? - return fmt::format(format.ToStdString(), std::forward(args)...); + return fmt::format(fmt::runtime(format.ToStdString()), std::forward(args)...); } template wxString wxStringFormat2W(const wxString& format, TArgs&&...args) { - return fmt::format(format.ToStdWstring(), std::forward(args)...); + return fmt::format(fmt::runtime(format.ToStdWstring()), std::forward(args)...); } // executes a function when destroying the obj diff --git a/src/resource/cemu.rc b/src/resource/cemu.rc index 4781111d..9ff27732 100644 Binary files a/src/resource/cemu.rc and b/src/resource/cemu.rc differ diff --git a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp index aab2c49e..0b0c2dc5 100644 --- a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp +++ b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp @@ -35,7 +35,7 @@ public: void appendFmt(const char* format_str, Args... args) { char* buf = (char*)(m_strBuffer + m_offsetEnd); - char* r = fmt::format_to(buf, format_str, std::forward(args)...); + char* r = fmt::format_to(buf, fmt::runtime(format_str), std::forward(args)...); cemu_assert_debug(r <= (char*)(m_strBuffer + N)); m_offsetEnd += (uint32)(r - buf); } diff --git a/src/util/helpers/StringBuf.h b/src/util/helpers/StringBuf.h index 3744caa4..8c7b1645 100644 --- a/src/util/helpers/StringBuf.h +++ b/src/util/helpers/StringBuf.h @@ -20,7 +20,7 @@ public: template void addFmt(const TFmt& format, TArgs&&... args) { - auto r = fmt::vformat_to_n((char*)(this->str + this->length), (size_t)(this->limit - this->length), fmt::to_string_view(format), fmt::make_args_checked(format, args...)); + auto r = fmt::vformat_to_n((char*)(this->str + this->length), (size_t)(this->limit - this->length), fmt::detail::to_string_view(format), fmt::make_format_args(args...)); this->length += (uint32)r.size; }