Files
vpinball-wasm/patches/vpinball/0001-emscripten-cmake-target.patch
T

273 lines
10 KiB
Diff
Raw Normal View History

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1fcf242..bc8f7ff 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,6 +50,7 @@ set(_vpx_valid_combos
GL-windows
GL-macos
GL-linux
+ GL-emscripten
DX9-windows)
if(NOT "${RENDERER}-${PLATFORM}" IN_LIST _vpx_valid_combos)
string(REPLACE ";" "\n " _vpx_available "${_vpx_valid_combos}")
@@ -784,6 +785,124 @@ elseif(PLATFORM STREQUAL "linux")
endif()
endif()
+elseif(PLATFORM STREQUAL "emscripten")
+ # Static wasm32 dependency libs/headers staged by vpinball-wasm's
+ # scripts/build-deps.sh (SDL3/SDL3_image/SDL3_ttf/FreeImage/libwinevbs
+ # built via emcmake). No RPATH concept applies to a wasm binary.
+ if(NOT DEFINED VPINBALL_WASM_DEPS_DIR)
+ set(VPINBALL_WASM_DEPS_DIR "${CMAKE_SOURCE_DIR}/../build/deps-wasm32")
+ endif()
+
+ if(RENDERER STREQUAL "GL")
+ add_library(glad
+ third-party/include/glad/src/gles2.c
+ )
+ set_target_properties(glad PROPERTIES LINKER_LANGUAGE C)
+ target_include_directories(glad PUBLIC
+ third-party/include/glad/include
+ )
+ endif()
+
+ # No raw HID device access in a browser sandbox (real-hardware nudge/plunger
+ # boards) - hidapi-hidraw is not linked for this platform, so exclude its
+ # one consumer.
+ list(REMOVE_ITEM VPX_STANDALONE_SOURCES
+ src/input/OpenPinDevHandler.cpp
+ )
+
+ add_executable(vpinball
+ ${VPX_STANDALONE_SOURCES}
+ ${CMAKE_SOURCE_DIR}/src/core/EmscriptenBridge.cpp
+ )
+
+ target_include_directories(vpinball PUBLIC
+ ${CMAKE_SOURCE_DIR}/third-party/include
+ ${CMAKE_SOURCE_DIR}
+ ${VPINBALL_WASM_DEPS_DIR}/include
+ ${VPINBALL_WASM_DEPS_DIR}/include/libwinevbs/atl/include
+ ${VPINBALL_WASM_DEPS_DIR}/include/libwinevbs/atlmfc/include
+ ${VPINBALL_WASM_DEPS_DIR}/include/libwinevbs/wine/include
+ src
+ plugins
+ )
+
+ target_compile_definitions(vpinball PRIVATE
+ __STANDALONE__
+
+ __LIBWINEVBS__
+ __WINESRC__
+ WINE_UNICODE_NATIVE
+
+ "__forceinline=__attribute__((always_inline)) inline"
+ )
+
+ target_compile_definitions(vpinball PRIVATE
+ ENABLE_OPENGL
+ __OPENGLES__
+ )
+
+ target_compile_options(vpinball PUBLIC
+ -fdenormal-fp-math=preserve-sign
+ -freciprocal-math
+ -fassociative-math
+ -fapprox-func
+ -fno-math-errno
+ -fno-trapping-math
+ -ffp-contract=off
+ -Wno-shorten-64-to-32
+ )
+
+ target_link_directories(vpinball PUBLIC
+ "${VPINBALL_WASM_DEPS_DIR}/lib"
+ )
+
+ target_link_libraries(vpinball PUBLIC
+ SDL3
+ SDL3_image
+ SDL3_ttf
+ freetype
+ freeimage
+ winevbs
+ glad
+ )
+
+ set_target_properties(vpinball PROPERTIES
+ RUNTIME_OUTPUT_NAME "vpinball"
+ SUFFIX ".js"
+ )
+
+ set(RESOURCES_DIR "$<TARGET_FILE_DIR:vpinball>")
+ set(SHADER_DIR_NAME "shaders-${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
+ set(SHADER_DIR "${RESOURCES_DIR}/${SHADER_DIR_NAME}")
+
+ # PRE_LINK (not POST_BUILD): the --preload-file linker flags below run
+ # emscripten's file_packager as part of the link step itself, so the
+ # staged directories must exist *before* linking, not after.
+ add_custom_command(TARGET vpinball PRE_LINK
+ COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/src/assets" "${RESOURCES_DIR}/assets"
+ COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/scripts" "${RESOURCES_DIR}/scripts"
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${RESOURCES_DIR}/tables"
+ COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/tests/assets/test000-default-table.vpx" "${RESOURCES_DIR}/tables/default.vpx"
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${SHADER_DIR}"
+ )
+ foreach(_shader IN LISTS VPX_GL_SHADERS)
+ add_custom_command(TARGET vpinball PRE_LINK
+ COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/src/shaders/hlsl_glsl/${_shader}" "${SHADER_DIR}"
+ )
+ endforeach()
+
+ # Embed the staged assets/scripts/shaders/default table into the wasm
+ # build's virtual filesystem so the engine can open them with ordinary
+ # fopen()/std::ifstream calls, unmodified, exactly as it does natively.
+ # Mount points are relative (matching how the native build locates these
+ # directories next to the executable, i.e. relative to cwd "/" in MEMFS).
+ target_link_options(vpinball PRIVATE
+ "SHELL:--preload-file ${RESOURCES_DIR}/assets@assets"
+ "SHELL:--preload-file ${RESOURCES_DIR}/scripts@scripts"
+ "SHELL:--preload-file ${RESOURCES_DIR}/tables@tables"
+ "SHELL:--preload-file ${SHADER_DIR}@${SHADER_DIR_NAME}"
+ )
+
# iOS and Android libvpinball build
elseif(PLATFORM STREQUAL "ios" OR PLATFORM STREQUAL "ios-simulator" OR PLATFORM STREQUAL "android")
@@ -957,4 +1076,9 @@ elseif(PLATFORM STREQUAL "ios" OR PLATFORM STREQUAL "ios-simulator" OR PLATFORM
endif()
-include("${CMAKE_SOURCE_DIR}/make/CMakeLists_plugins.txt")
+# vpinball-wasm: plugins are all optional/native-hardware-integration-scoped
+# (PinMAME, DOF, B2S, FlexDMD, Inspector, FFmpeg-dependent, etc.) and don't
+# map to a browser sandbox for this project's v1 - see README's roadmap.
+if(NOT PLATFORM STREQUAL "emscripten")
+ include("${CMAKE_SOURCE_DIR}/make/CMakeLists_plugins.txt")
+endif()
diff --git a/src/core/def.h b/src/core/def.h
index 7335929..eb2c0b4 100644
--- a/src/core/def.h
+++ b/src/core/def.h
@@ -337,6 +337,9 @@ static const string platform_bits[2] = { "32"s, "64"s };
#elif defined(__ANDROID__) // leave here, as it also defines linux
#define GET_PLATFORM_OS_ENUM 1
#define GET_PLATFORM_OS "android"
+#elif defined(__EMSCRIPTEN__) // leave here, as it also defines linux on some toolchains
+ #define GET_PLATFORM_OS_ENUM 6
+ #define GET_PLATFORM_OS "emscripten"
#elif (defined(__linux) || defined(__linux__))
#define GET_PLATFORM_OS_ENUM 2
#define GET_PLATFORM_OS "linux"
@@ -352,7 +355,7 @@ static const string platform_bits[2] = { "32"s, "64"s };
#define GET_PLATFORM_OS "macos"
#endif
#endif
-static const string platform_os[6] = { "windows"s, "android"s, "linux"s, "ios"s, "tvos"s, "macos"s };
+static const string platform_os[7] = { "windows"s, "android"s, "linux"s, "ios"s, "tvos"s, "macos"s, "emscripten"s };
#if defined(ENABLE_BGFX)
#define GET_PLATFORM_RENDERER_ENUM 2
diff --git a/src/core/main.cpp b/src/core/main.cpp
index dafe6ee..0015268 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -228,13 +228,14 @@ extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
return retval;
}
-#if defined(__STANDALONE__) && ((defined(__linux__) && !defined(__ANDROID__)) || defined(__MINGW32__))
+#if defined(__STANDALONE__) && ((defined(__linux__) && !defined(__ANDROID__)) || defined(__MINGW32__) || defined(__EMSCRIPTEN__))
extern int g_argc;
extern const char **g_argv;
int main(int argc, const char** argv) {
#ifdef __MINGW32__
signal(SIGINT, OnSignalHandler);
-#else
+#elif !defined(__EMSCRIPTEN__)
+ // No meaningful SIGINT/process-signal equivalent in a browser sandbox.
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = OnSignalHandler;
sigemptyset(&sigIntHandler.sa_mask);
diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp
index 540b822..1af6bd8 100644
--- a/src/input/InputManager.cpp
+++ b/src/input/InputManager.cpp
@@ -20,7 +20,8 @@
#include "input/SDLInputHandler.h"
-#ifndef __LIBVPINBALL__
+#if !defined(__LIBVPINBALL__) && !defined(__EMSCRIPTEN__)
+ // No raw HID device access in a browser sandbox.
#include "input/OpenPinDevHandler.h"
#endif
@@ -82,7 +83,7 @@ InputManager::InputManager(Player* player)
// Initialize device handlers
m_inputHandlers.push_back(std::make_unique<SDLInputHandler>(*this));
m_sdlHandler = static_cast<SDLInputHandler*>(m_inputHandlers.back().get());
- #ifndef __LIBVPINBALL__
+ #if !defined(__LIBVPINBALL__) && !defined(__EMSCRIPTEN__)
m_inputHandlers.push_back(std::make_unique<OpenPinDevHandler>(*this));
#endif
diff --git a/src/physics/kdtree.cpp b/src/physics/kdtree.cpp
index 3f262a9..10ac63e 100644
--- a/src/physics/kdtree.cpp
+++ b/src/physics/kdtree.cpp
@@ -421,7 +421,7 @@ void HitKDNode::HitTestBall(const HitKD* hitoct, const HitBall* const pball, Col
if (pball->m_hitBBox.right >= vcenter)
m_children[1].HitTestBall(hitoct, pball, coll);
}
- else f (axis == 1)
+ else if (axis == 1)
{
const float vcenter = (m_rectbounds.top+m_rectbounds.bottom)*0.5f;
if (pball->m_hitBBox.top <= vcenter)
diff --git a/standalone/vpinball_standalone_i.h b/standalone/vpinball_standalone_i.h
index 29898aa..3bac681 100644
--- a/standalone/vpinball_standalone_i.h
+++ b/standalone/vpinball_standalone_i.h
@@ -3351,8 +3351,19 @@ ITableGlobal : public IDispatch
virtual HRESULT STDMETHODCALLTYPE put_ShowCursor(
VARIANT_BOOL show) = 0;
+ // vpinball-wasm: mirrors the #ifdef _WIN64 split already used by
+ // ScriptGlobalTable's own declaration/implementation of this method -
+ // this generated interface header previously hardcoded the 64-bit
+ // (SIZE_T) overload unconditionally, which made ScriptGlobalTable
+ // abstract (unable to override this pure virtual) on 32-bit targets
+ // like wasm32.
+#ifdef _WIN64
virtual HRESULT STDMETHODCALLTYPE get_GetPlayerHWnd(
SIZE_T *pVal) = 0;
+#else
+ virtual HRESULT STDMETHODCALLTYPE get_GetPlayerHWnd(
+ LONG *pVal) = 0;
+#endif
virtual HRESULT STDMETHODCALLTYPE StopSound(
BSTR Sound) = 0;
diff --git a/standalone/vpinball_standalone_i_proxy.cpp b/standalone/vpinball_standalone_i_proxy.cpp
index 72a2d2e..2fe1b73 100644
--- a/standalone/vpinball_standalone_i_proxy.cpp
+++ b/standalone/vpinball_standalone_i_proxy.cpp
@@ -3043,7 +3043,15 @@ STDMETHODIMP ScriptGlobalTable::Invoke(DISPID dispIdMember, REFIID /*riid*/, LCI
if (wFlags & DISPATCH_PROPERTYGET) {
// line 724: [propget, id(14), helpstring("property GetPlayerHWnd")] HRESULT GetPlayerHWnd([out, retval] SIZE_T *pVal);
V_VT(&res) = VT_UI4;
+ // vpinball-wasm: this generated proxy hardcodes the _WIN64 (SIZE_T)
+ // overload of get_GetPlayerHWnd; on a genuine 32-bit target (wasm32)
+ // the interface instead declares the LONG overload (see
+ // ScriptGlobalTable.h's #ifdef _WIN64), so match it here too.
+#ifdef _WIN64
hres = get_GetPlayerHWnd((SIZE_T*)&V_UI4(&res));
+#else
+ hres = get_GetPlayerHWnd((LONG*)&V_UI4(&res));
+#endif
}
break;
}