Update submodules; changes for emscripten support

This commit is contained in:
Luke Street 2022-08-03 18:19:11 -04:00
parent 324d89693c
commit e2fbc0663f
16 changed files with 128 additions and 11 deletions

View File

@ -73,6 +73,9 @@ if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
set(TVOS ON) set(TVOS ON)
set(IOS OFF) set(IOS OFF)
endif () endif ()
if (EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX .html)
endif ()
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ATHENA_ARCH) string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" ATHENA_ARCH)
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" ATHENA_HOST_ARCH) string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" ATHENA_HOST_ARCH)

View File

@ -19,25 +19,50 @@ class CFileDvdRequest : public IDvdRequest {
u32 m_len; u32 m_len;
ESeekOrigin m_whence; ESeekOrigin m_whence;
int m_offset; int m_offset;
#ifdef HAS_DVD_THREAD
std::atomic_bool m_cancel = {false}; std::atomic_bool m_cancel = {false};
std::atomic_bool m_complete = {false}; std::atomic_bool m_complete = {false};
#else
bool m_cancel = false;
bool m_complete = false;
#endif
std::function<void(u32)> m_callback; std::function<void(u32)> m_callback;
public: public:
~CFileDvdRequest() override { CFileDvdRequest::PostCancelRequest(); } ~CFileDvdRequest() override { CFileDvdRequest::PostCancelRequest(); }
void WaitUntilComplete() override { void WaitUntilComplete() override {
#ifdef HAS_DVD_THREAD
while (!m_complete.load() && !m_cancel.load()) { while (!m_complete.load() && !m_cancel.load()) {
std::unique_lock lk{CDvdFile::m_WaitMutex}; std::unique_lock lk{CDvdFile::m_WaitMutex};
} }
#else
if (!m_complete && !m_cancel) {
CDvdFile::DoWork();
}
#endif
}
bool IsComplete() override {
#ifdef HAS_DVD_THREAD
return m_complete.load();
#else
if (!m_complete) {
CDvdFile::DoWork();
}
return m_complete;
#endif
} }
bool IsComplete() override { return m_complete.load(); }
void PostCancelRequest() override { void PostCancelRequest() override {
#ifdef HAS_DVD_THREAD
if (m_complete.load() || m_cancel.load()) { if (m_complete.load() || m_cancel.load()) {
return; return;
} }
std::unique_lock waitlk{CDvdFile::m_WaitMutex}; std::unique_lock waitlk{CDvdFile::m_WaitMutex};
m_cancel.store(true); m_cancel.store(true);
#else
m_cancel = true;
#endif
} }
[[nodiscard]] EMediaType GetMediaType() const override { return EMediaType::File; } [[nodiscard]] EMediaType GetMediaType() const override { return EMediaType::File; }
@ -53,9 +78,15 @@ public:
, m_callback(std::move(cb)) {} , m_callback(std::move(cb)) {}
void DoRequest() { void DoRequest() {
#ifdef HAS_DVD_THREAD
if (m_cancel.load()) { if (m_cancel.load()) {
return; return;
} }
#else
if (m_cancel) {
return;
}
#endif
u32 readLen = 0; u32 readLen = 0;
if (m_whence == ESeekOrigin::Cur && m_offset == 0) { if (m_whence == ESeekOrigin::Cur && m_offset == 0) {
readLen = m_reader->read(m_buf, m_len); readLen = m_reader->read(m_buf, m_len);
@ -84,15 +115,21 @@ public:
if (m_callback) { if (m_callback) {
m_callback(readLen); m_callback(readLen);
} }
#ifdef HAS_DVD_THREAD
m_complete.store(true); m_complete.store(true);
#else
m_complete = true;
#endif
} }
}; };
#ifdef HAS_DVD_THREAD
std::thread CDvdFile::m_WorkerThread; std::thread CDvdFile::m_WorkerThread;
std::mutex CDvdFile::m_WorkerMutex; std::mutex CDvdFile::m_WorkerMutex;
std::condition_variable CDvdFile::m_WorkerCV; std::condition_variable CDvdFile::m_WorkerCV;
std::mutex CDvdFile::m_WaitMutex; std::mutex CDvdFile::m_WaitMutex;
std::atomic_bool CDvdFile::m_WorkerRun = {false}; std::atomic_bool CDvdFile::m_WorkerRun = {false};
#endif
std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue; std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue;
std::string CDvdFile::m_rootDirectory; std::string CDvdFile::m_rootDirectory;
std::unique_ptr<u8[]> CDvdFile::m_dolBuf; std::unique_ptr<u8[]> CDvdFile::m_dolBuf;
@ -106,7 +143,17 @@ CDvdFile::CDvdFile(std::string_view path) : x18_path(path) {
} }
} }
// single-threaded hack
void CDvdFile::DoWork() {
for (std::shared_ptr<IDvdRequest>& req : m_RequestQueue) {
auto& concreteReq = static_cast<CFileDvdRequest&>(*req);
concreteReq.DoRequest();
}
m_RequestQueue.clear();
}
void CDvdFile::WorkerProc() { void CDvdFile::WorkerProc() {
#ifdef HAS_DVD_THREAD
logvisor::RegisterThreadName("CDvdFile"); logvisor::RegisterThreadName("CDvdFile");
OPTICK_THREAD("CDvdFile"); OPTICK_THREAD("CDvdFile");
@ -130,15 +177,20 @@ void CDvdFile::WorkerProc() {
} }
m_WorkerCV.wait(lk); m_WorkerCV.wait(lk);
} }
#endif
} }
std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off, std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off,
std::function<void(u32)>&& cb) { std::function<void(u32)>&& cb) {
std::shared_ptr<IDvdRequest> ret = std::make_shared<CFileDvdRequest>(*this, buf, len, whence, off, std::move(cb)); std::shared_ptr<IDvdRequest> ret = std::make_shared<CFileDvdRequest>(*this, buf, len, whence, off, std::move(cb));
#ifdef HAS_DVD_THREAD
std::unique_lock lk{m_WorkerMutex}; std::unique_lock lk{m_WorkerMutex};
#endif
m_RequestQueue.emplace_back(ret); m_RequestQueue.emplace_back(ret);
#ifdef HAS_DVD_THREAD
lk.unlock(); lk.unlock();
m_WorkerCV.notify_one(); m_WorkerCV.notify_one();
#endif
return ret; return ret;
} }
@ -205,20 +257,25 @@ nod::Node* CDvdFile::ResolvePath(std::string_view path) {
} }
bool CDvdFile::Initialize(const std::string_view& path) { bool CDvdFile::Initialize(const std::string_view& path) {
#ifdef HAS_DVD_THREAD
if (m_WorkerRun.load()) { if (m_WorkerRun.load()) {
return true; return true;
} }
#endif
m_DvdRoot = nod::OpenDiscFromImage(path); m_DvdRoot = nod::OpenDiscFromImage(path);
if (!m_DvdRoot) { if (!m_DvdRoot) {
return false; return false;
} }
m_dolBuf = m_DvdRoot->getDataPartition()->getDOLBuf(); m_dolBuf = m_DvdRoot->getDataPartition()->getDOLBuf();
#ifdef HAS_DVD_THREAD
m_WorkerRun.store(true); m_WorkerRun.store(true);
m_WorkerThread = std::thread(WorkerProc); m_WorkerThread = std::thread(WorkerProc);
#endif
return true; return true;
} }
void CDvdFile::Shutdown() { void CDvdFile::Shutdown() {
#ifdef HAS_DVD_THREAD
if (!m_WorkerRun.load()) { if (!m_WorkerRun.load()) {
return; return;
} }
@ -227,6 +284,7 @@ void CDvdFile::Shutdown() {
if (m_WorkerThread.joinable()) { if (m_WorkerThread.joinable()) {
m_WorkerThread.join(); m_WorkerThread.join();
} }
#endif
m_RequestQueue.clear(); m_RequestQueue.clear();
} }

View File

@ -15,6 +15,10 @@
#include <nod/nod.hpp> #include <nod/nod.hpp>
#include <nod/DiscBase.hpp> #include <nod/DiscBase.hpp>
#ifndef EMSCRIPTEN
#define HAS_DVD_THREAD
#endif
namespace metaforce { namespace metaforce {
enum class ESeekOrigin { Begin = 0, Cur = 1, End = 2 }; enum class ESeekOrigin { Begin = 0, Cur = 1, End = 2 };
@ -33,11 +37,13 @@ class CDvdFile {
friend class CFileDvdRequest; friend class CFileDvdRequest;
static std::unique_ptr<nod::DiscBase> m_DvdRoot; static std::unique_ptr<nod::DiscBase> m_DvdRoot;
// static std::unordered_map<std::string, std::string> m_caseInsensitiveMap; // static std::unordered_map<std::string, std::string> m_caseInsensitiveMap;
#ifdef HAS_DVD_THREAD
static std::thread m_WorkerThread; static std::thread m_WorkerThread;
static std::mutex m_WorkerMutex; static std::mutex m_WorkerMutex;
static std::condition_variable m_WorkerCV; static std::condition_variable m_WorkerCV;
static std::mutex m_WaitMutex; static std::mutex m_WaitMutex;
static std::atomic_bool m_WorkerRun; static std::atomic_bool m_WorkerRun;
#endif
static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue; static std::vector<std::shared_ptr<IDvdRequest>> m_RequestQueue;
static std::string m_rootDirectory; static std::string m_rootDirectory;
static std::unique_ptr<u8[]> m_dolBuf; static std::unique_ptr<u8[]> m_dolBuf;
@ -57,6 +63,7 @@ public:
static void SetRootDirectory(const std::string_view& rootDir); static void SetRootDirectory(const std::string_view& rootDir);
static void Shutdown(); static void Shutdown();
static u8* GetDolBuf() { return m_dolBuf.get(); } static u8* GetDolBuf() { return m_dolBuf.get(); }
static void DoWork();
CDvdFile(std::string_view path); CDvdFile(std::string_view path);
operator bool() const { return m_reader.operator bool(); } operator bool() const { return m_reader.operator bool(); }

View File

@ -367,6 +367,9 @@ public:
if (m_voiceEngine) { if (m_voiceEngine) {
m_voiceEngine->pumpAndMixVoices(); m_voiceEngine->pumpAndMixVoices();
} }
#ifdef EMSCRIPTEN
CDvdFile::DoWork();
#endif
CGraphics::TickRenderTimings(); CGraphics::TickRenderTimings();
++logvisor::FrameIndex; ++logvisor::FrameIndex;
} }
@ -433,12 +436,16 @@ static void SetupBasics() {
} }
static bool IsClientLoggingEnabled(int argc, char** argv) { static bool IsClientLoggingEnabled(int argc, char** argv) {
#ifdef EMSCRIPTEN
return true;
#else
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (!strncmp(argv[i], "-l", 2)) { if (!strncmp(argv[i], "-l", 2)) {
return true; return true;
} }
} }
return false; return false;
#endif
} }
static void SetupLogging() {} static void SetupLogging() {}

View File

@ -154,7 +154,7 @@ if (NOT GEKKO AND NOT NX AND NOT IOS AND NOT TVOS)
set(DISCORD_RPC_LIBRARY "discord-rpc") set(DISCORD_RPC_LIBRARY "discord-rpc")
endif() endif()
set(RUNTIME_LIBRARIES amuse zeus nod NESEmulator libjpeg-turbo jbus kabufuda logvisor OptickCore set(RUNTIME_LIBRARIES amuse zeus nod NESEmulator libjpeg-turbo jbus kabufuda logvisor OptickCore
imgui_support aurora::aurora SDL2::SDL2-static SDL2::SDL2main imgui_support aurora::aurora
boo # TODO move audiodev boo # TODO move audiodev
${DISCORD_RPC_LIBRARY} ${DISCORD_RPC_LIBRARY}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
@ -278,3 +278,6 @@ if (WINDOWS_STORE)
# This should match the Package.appxmanifest # This should match the Package.appxmanifest
set_property(TARGET metaforce PROPERTY VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION "10.0.14393.0") set_property(TARGET metaforce PROPERTY VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION "10.0.14393.0")
endif () endif ()
if (EMSCRIPTEN)
target_link_options(metaforce PRIVATE -sTOTAL_MEMORY=268435456 -sALLOW_MEMORY_GROWTH --preload-file "${CMAKE_SOURCE_DIR}/files@/")
endif ()

View File

@ -700,11 +700,17 @@ void ImGuiConsole::ShowAboutWindow(bool preLaunch) {
} }
} }
#endif #endif
#ifdef EMSCRIPTEN
if (ImGuiButtonCenter("Load Game")) {
m_gameDiscSelected = "game.iso";
}
#else
if (!m_lastDiscPath.empty()) { if (!m_lastDiscPath.empty()) {
if (ImGuiButtonCenter("Load Previous Game")) { if (ImGuiButtonCenter("Load Previous Game")) {
m_gameDiscSelected = m_lastDiscPath; m_gameDiscSelected = m_lastDiscPath;
} }
} }
#endif
ImGui::Dummy(padding); ImGui::Dummy(padding);
} }
if (m_errorString) { if (m_errorString) {
@ -828,7 +834,7 @@ void ImGuiConsole::ShowDebugOverlay() {
} }
hasPrevious = true; hasPrevious = true;
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {}\n"), metaforce::CGraphics::GetFPS())); ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.1f}\n"), io.Framerate));
} }
if (m_inGameTime && g_GameState != nullptr) { if (m_inGameTime && g_GameState != nullptr) {
if (hasPrevious) { if (hasPrevious) {

View File

@ -5,20 +5,31 @@
#include "Runtime/CBasics.hpp" #include "Runtime/CBasics.hpp"
#include "Runtime/CDvdRequest.hpp" #include "Runtime/CDvdRequest.hpp"
#ifndef EMSCRIPTEN
#define ENABLE_JBUS
#endif
#ifdef ENABLE_JBUS
#include <jbus/Endpoint.hpp> #include <jbus/Endpoint.hpp>
#include <jbus/Listener.hpp> #include <jbus/Listener.hpp>
#endif
namespace metaforce::MP1 { namespace metaforce::MP1 {
#ifdef ENABLE_JBUS
static jbus::Listener g_JbusListener; static jbus::Listener g_JbusListener;
static std::unique_ptr<jbus::Endpoint> g_JbusEndpoint; static std::unique_ptr<jbus::Endpoint> g_JbusEndpoint;
#endif
void CGBASupport::Initialize() { void CGBASupport::Initialize() {
#ifdef ENABLE_JBUS
jbus::Initialize(); jbus::Initialize();
g_JbusListener.start(); g_JbusListener.start();
#endif
} }
void CGBASupport::GlobalPoll() { void CGBASupport::GlobalPoll() {
#ifdef ENABLE_JBUS
if (g_JbusEndpoint && !g_JbusEndpoint->connected()) if (g_JbusEndpoint && !g_JbusEndpoint->connected())
g_JbusEndpoint.reset(); g_JbusEndpoint.reset();
if (!g_JbusEndpoint) { if (!g_JbusEndpoint) {
@ -26,6 +37,7 @@ void CGBASupport::GlobalPoll() {
if (g_JbusEndpoint) if (g_JbusEndpoint)
g_JbusEndpoint->setChan(3); g_JbusEndpoint->setChan(3);
} }
#endif
} }
CGBASupport::CGBASupport() : CDvdFile("client_pad.bin") { CGBASupport::CGBASupport() : CDvdFile("client_pad.bin") {
@ -56,6 +68,7 @@ u8 CGBASupport::CalculateFusionJBusChecksum(const u8* data, size_t len) {
} }
bool CGBASupport::PollResponse() { bool CGBASupport::PollResponse() {
#ifdef ENABLE_JBUS
if (!g_JbusEndpoint) if (!g_JbusEndpoint)
return false; return false;
@ -127,10 +140,13 @@ bool CGBASupport::PollResponse() {
if (x44_fusionLinked && (bytes[2] & 0x1) != 0) if (x44_fusionLinked && (bytes[2] & 0x1) != 0)
x45_fusionBeat = true; x45_fusionBeat = true;
#endif
return true; return true;
} }
#ifdef ENABLE_JBUS
static void JoyBootDone(jbus::ThreadLocalEndpoint& endpoint, jbus::EJoyReturn status) {} static void JoyBootDone(jbus::ThreadLocalEndpoint& endpoint, jbus::EJoyReturn status) {}
#endif
void CGBASupport::Update(float dt) { void CGBASupport::Update(float dt) {
switch (x34_phase) { switch (x34_phase) {
@ -144,6 +160,7 @@ void CGBASupport::Update(float dt) {
[[fallthrough]]; [[fallthrough]];
case EPhase::PollProbe: case EPhase::PollProbe:
#ifdef ENABLE_JBUS
/* SIProbe poll normally occurs here with 4 second timeout */ /* SIProbe poll normally occurs here with 4 second timeout */
if (!g_JbusEndpoint) { if (!g_JbusEndpoint) {
x34_phase = EPhase::Failed; x34_phase = EPhase::Failed;
@ -151,17 +168,23 @@ void CGBASupport::Update(float dt) {
} }
x40_siChan = g_JbusEndpoint->getChan(); x40_siChan = g_JbusEndpoint->getChan();
x34_phase = EPhase::StartJoyBusBoot; x34_phase = EPhase::StartJoyBusBoot;
#endif
[[fallthrough]]; [[fallthrough]];
case EPhase::StartJoyBusBoot: case EPhase::StartJoyBusBoot:
#ifdef ENABLE_JBUS
x34_phase = EPhase::PollJoyBusBoot; x34_phase = EPhase::PollJoyBusBoot;
if (!g_JbusEndpoint || g_JbusEndpoint->GBAJoyBootAsync(x40_siChan * 2, 2, x2c_buffer.get(), x28_fileSize, if (!g_JbusEndpoint || g_JbusEndpoint->GBAJoyBootAsync(x40_siChan * 2, 2, x2c_buffer.get(), x28_fileSize,
&x3c_status, JoyBootDone) != jbus::GBA_READY) { &x3c_status, JoyBootDone) != jbus::GBA_READY) {
x34_phase = EPhase::Failed; x34_phase = EPhase::Failed;
} }
#else
x34_phase = EPhase::Failed;
#endif
break; break;
case EPhase::PollJoyBusBoot: case EPhase::PollJoyBusBoot:
#ifdef ENABLE_JBUS
u8 percent; u8 percent;
if (g_JbusEndpoint && g_JbusEndpoint->GBAGetProcessStatus(percent) == jbus::GBA_BUSY) if (g_JbusEndpoint && g_JbusEndpoint->GBAGetProcessStatus(percent) == jbus::GBA_BUSY)
break; break;
@ -171,9 +194,13 @@ void CGBASupport::Update(float dt) {
} }
x38_timeout = 4.f; x38_timeout = 4.f;
x34_phase = EPhase::DataTransfer; x34_phase = EPhase::DataTransfer;
#else
x34_phase = EPhase::Failed;
#endif
break; break;
case EPhase::DataTransfer: case EPhase::DataTransfer:
#ifdef ENABLE_JBUS
if (PollResponse()) { if (PollResponse()) {
x34_phase = EPhase::Complete; x34_phase = EPhase::Complete;
break; break;
@ -181,6 +208,9 @@ void CGBASupport::Update(float dt) {
x38_timeout = std::max(0.f, x38_timeout - dt); x38_timeout = std::max(0.f, x38_timeout - dt);
if (x38_timeout == 0.f) if (x38_timeout == 0.f)
x34_phase = EPhase::Failed; x34_phase = EPhase::Failed;
#else
x34_phase = EPhase::Failed;
#endif
break; break;
default: default:

View File

@ -1,5 +1,5 @@
option(BUILD_ATHENA "Build Athena libraries from source" ON) option(BUILD_ATHENA "Build Athena libraries from source" ON)
if (WIN32 OR APPLE) if (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows OR CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
# Default to binary atdna on Windows & macOS # Default to binary atdna on Windows & macOS
option(BUILD_ATDNA "Build atdna utility from source (requires LLVM)" OFF) option(BUILD_ATDNA "Build atdna utility from source (requires LLVM)" OFF)
else () else ()
@ -8,7 +8,7 @@ endif ()
if (NOT BUILD_ATDNA) if (NOT BUILD_ATDNA)
set(ATHENA_BASE_URL "https://github.com/libAthena/athena/releases/download/latest") set(ATHENA_BASE_URL "https://github.com/libAthena/athena/releases/download/latest")
if (WIN32) if (CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(ATHENA_EXT 7z) set(ATHENA_EXT 7z)
else () else ()
set(ATHENA_EXT tar.gz) set(ATHENA_EXT tar.gz)

2
extern/athena vendored

@ -1 +1 @@
Subproject commit c6046d91507d2a9dca46e29564acc0421322f7e9 Subproject commit fa346ace4774e4ac66644be6d11908a80f0151b6

2
extern/aurora vendored

@ -1 +1 @@
Subproject commit 04590f30cd90814d70fa7d1fe4a5f1e814b177c2 Subproject commit 893cabe55a31a6f59c77854d503d891025204acb

2
extern/boo vendored

@ -1 +1 @@
Subproject commit 6e4030212c1a2a21a79a6d69660b6e7a52cf2885 Subproject commit 39eb95a82440e1e614533b702e1cda814e01f69c

2
extern/kabufuda vendored

@ -1 +1 @@
Subproject commit 32090b4d4ab70dbfa07f1f2994964f983ab43a69 Subproject commit 4f3fbc0d0df2ee90a760b2d2e2bb8e2126bd92cb

2
extern/zeus vendored

@ -1 +1 @@
Subproject commit ac7d83009dae97a28ba779d00188e3d76e9b9821 Subproject commit e9ec10a3823a3c734e70c99b4aa50ae2a7e7e81f

View File

@ -4,7 +4,7 @@ add_library(imgui_support
NotoMono.cpp NotoMono.cpp
MetaforceIcon.cpp MetaforceIcon.cpp
) )
target_link_libraries(imgui_support PUBLIC aurora::aurora imgui) target_link_libraries(imgui_support PUBLIC aurora::aurora imgui ${ZLIB_LIBRARIES})
target_include_directories(imgui_support PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(imgui_support PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(imgui_support PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories(imgui_support PRIVATE ${CMAKE_SOURCE_DIR})

View File

@ -1,6 +1,7 @@
#include "ImGuiEngine.hpp" #include "ImGuiEngine.hpp"
#include <aurora/imgui.h> #include <aurora/imgui.h>
#include <cmath>
#include "Runtime/Streams/CMemoryInStream.hpp" #include "Runtime/Streams/CMemoryInStream.hpp"
#include "Runtime/Streams/CZipInputStream.hpp" #include "Runtime/Streams/CZipInputStream.hpp"

View File

@ -13,6 +13,8 @@
#define METAFORCE_DLPACKAGE "metaforce-@METAFORCE_WC_DESCRIBE@-@PLATFORM_NAME@-x86_64-@METAFORCE_VECTOR_ISA@" #define METAFORCE_DLPACKAGE "metaforce-@METAFORCE_WC_DESCRIBE@-@PLATFORM_NAME@-x86_64-@METAFORCE_VECTOR_ISA@"
#elif defined(__aarch64__) || defined(_M_ARM64) #elif defined(__aarch64__) || defined(_M_ARM64)
#define METAFORCE_DLPACKAGE "metaforce-@METAFORCE_WC_DESCRIBE@-@PLATFORM_NAME@-arm64" #define METAFORCE_DLPACKAGE "metaforce-@METAFORCE_WC_DESCRIBE@-@PLATFORM_NAME@-arm64"
#elif defined(EMSCRIPTEN)
#define METAFORCE_DLPACKAGE "metaforce-@METAFORCE_WC_DESCRIBE@-@PLATFORM_NAME@-wasm"
#endif #endif
#endif #endif