diff --git a/CMakeLists.txt b/CMakeLists.txt index 724ca120..38ce8ef1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -553,6 +553,7 @@ if (ISLE_BUILD_APP) ISLE/emscripten/events.cpp ISLE/emscripten/filesystem.cpp ISLE/emscripten/messagebox.cpp + ISLE/emscripten/window.cpp ) target_compile_definitions(isle PRIVATE "ISLE_EMSCRIPTEN_HOST=\"${ISLE_EMSCRIPTEN_HOST}\"") set_property(TARGET isle PROPERTY SUFFIX ".html") diff --git a/ISLE/emscripten/config.cpp b/ISLE/emscripten/config.cpp index 7d9cdb31..58a42704 100644 --- a/ISLE/emscripten/config.cpp +++ b/ISLE/emscripten/config.cpp @@ -1,6 +1,7 @@ #include "config.h" #include "filesystem.h" +#include "window.h" #include #include @@ -16,6 +17,10 @@ void Emscripten_SetupDefaultConfigOverrides(dictionary* p_dictionary) iniparser_set(p_dictionary, "isle:Full Screen", "false"); iniparser_set(p_dictionary, "isle:Flip Surfaces", "true"); + // Emscripten-only for now + Emscripten_SetScaleAspect(iniparser_getboolean(p_dictionary, "isle:Original Aspect Ratio", true)); + Emscripten_SetOriginalResolution(iniparser_getboolean(p_dictionary, "isle:Original Resolution", true)); + // clang-format off MAIN_THREAD_EM_ASM({JSEvents.fullscreenEnabled = function() { return false; }}); // clang-format on diff --git a/ISLE/emscripten/emscripten.patch b/ISLE/emscripten/emscripten.patch index 7e9ad611..a24a67bd 100644 --- a/ISLE/emscripten/emscripten.patch +++ b/ISLE/emscripten/emscripten.patch @@ -1,3 +1,28 @@ +diff --git a/src/lib/libhtml5.js b/src/lib/libhtml5.js +index da08765e7..24e5da22e 100644 +--- a/src/lib/libhtml5.js ++++ b/src/lib/libhtml5.js +@@ -1182,6 +1182,7 @@ var LibraryHTML5 = { + + $registerRestoreOldStyle__deps: ['$getCanvasElementSize', '$setCanvasElementSize', '$currentFullscreenStrategy'], + $registerRestoreOldStyle: (canvas) => { ++ return; + var canvasSize = getCanvasElementSize(canvas); + var oldWidth = canvasSize[0]; + var oldHeight = canvasSize[1]; +@@ -1326,9 +1327,9 @@ var LibraryHTML5 = { + var topMargin; + + if (inAspectRatioFixedFullscreenMode) { +- if (w*y < x*h) h = (w * y / x) | 0; +- else if (w*y > x*h) w = (h * x / y) | 0; +- topMargin = ((screenHeight - h) / 2) | 0; ++ if (w*y < x*h) h = Math.round(w * y / x) | 0; ++ else if (w*y > x*h) w = Math.round(h * x / y) | 0; ++ topMargin = Math.round((screenHeight - h) / 2) | 0; + } + + if (inPixelPerfectFullscreenMode) { diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js index 6d979627e..97e3f8684 100644 --- a/src/lib/libpthread.js diff --git a/ISLE/emscripten/window.cpp b/ISLE/emscripten/window.cpp new file mode 100644 index 00000000..6766490f --- /dev/null +++ b/ISLE/emscripten/window.cpp @@ -0,0 +1,98 @@ +#include "window.h" + +#include "mxtypes.h" + +#include +#include +#include + +double g_fullWidth; +double g_fullHeight; +bool g_scaleAspect = true; +bool g_originalResolution = true; + +extern MxS32 g_targetWidth; +extern MxS32 g_targetHeight; + +void Emscripten_SetupWindow(SDL_Window* p_window) +{ + EmscriptenFullscreenStrategy strategy; + strategy.scaleMode = g_scaleAspect ? EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; + strategy.canvasResizedCallbackUserData = p_window; + strategy.canvasResizedCallback = [](int eventType, const void* reserved, void* userData) -> bool { + int width, height; + emscripten_get_canvas_element_size("canvas", &width, &height); + emscripten_get_element_css_size("#canvas", &g_fullWidth, &g_fullHeight); + + if (g_originalResolution) { + SDL_SetWindowSize((SDL_Window*) userData, g_targetWidth, g_targetHeight); + } + else { + SDL_SetWindowSize((SDL_Window*) userData, width, height); + } + + SDL_Log( + "Emscripten: window size %dx%d, canvas size %dx%d, scale aspect %s, original resolution %s", + width, + height, + (int) g_fullWidth, + (int) g_fullHeight, + g_scaleAspect ? "TRUE" : "FALSE", + g_originalResolution ? "TRUE" : "FALSE" + ); + return true; + }; + + emscripten_enter_soft_fullscreen("canvas", &strategy); +} + +void Emscripten_SetScaleAspect(bool p_scaleAspect) +{ + g_scaleAspect = p_scaleAspect; +} + +void Emscripten_SetOriginalResolution(bool p_originalResolution) +{ + g_originalResolution = p_originalResolution; +} + +void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event) +{ + if (!g_scaleAspect) { + return; + } + + switch (event->type) { + case SDL_EVENT_MOUSE_MOTION: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->motion.x = (event->motion.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio; + event->motion.y = (event->motion.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio; + break; + } + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->button.x = (event->button.x - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / widthRatio; + event->button.y = (event->button.y - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / heightRatio; + break; + } + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: { + const float scale = std::min(g_fullWidth / g_targetWidth, g_fullHeight / g_targetHeight); + const float widthRatio = (g_targetWidth * scale) / g_fullWidth; + const float heightRatio = (g_targetHeight * scale) / g_fullHeight; + event->tfinger.x = (event->tfinger.x * g_targetWidth - (g_targetWidth * (1.0f - widthRatio) / 2.0f)) / + widthRatio / g_targetWidth; + event->tfinger.y = (event->tfinger.y * g_targetHeight - (g_targetHeight * (1.0f - heightRatio) / 2.0f)) / + heightRatio / g_targetHeight; + break; + } + } +} diff --git a/ISLE/emscripten/window.h b/ISLE/emscripten/window.h new file mode 100644 index 00000000..01b13ae4 --- /dev/null +++ b/ISLE/emscripten/window.h @@ -0,0 +1,11 @@ +#ifndef EMSCRIPTEN_WINDOW_H +#define EMSCRIPTEN_WINDOW_H + +#include + +void Emscripten_SetupWindow(SDL_Window* p_window); +void Emscripten_SetScaleAspect(bool p_scaleAspect); +void Emscripten_SetOriginalResolution(bool p_originalResolution); +void Emscripten_ConvertEventToRenderCoordinates(SDL_Event* event); + +#endif // EMSCRIPTEN_WINDOW_H diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index dbb3c9ff..d898e48b 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -53,6 +53,7 @@ #include "emscripten/events.h" #include "emscripten/filesystem.h" #include "emscripten/messagebox.h" +#include "emscripten/window.h" #endif #ifdef __3DS__ @@ -441,6 +442,10 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) if (device && !device->ConvertEventToRenderCoordinates(event)) { SDL_Log("Failed to convert event coordinates: %s", SDL_GetError()); } + +#ifdef __EMSCRIPTEN__ + Emscripten_ConvertEventToRenderCoordinates(event); +#endif break; } @@ -641,8 +646,8 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) #endif g_mousemoved = TRUE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; if (InputManager()) { InputManager()->QueueEvent(c_notificationMouseMove, LegoEventNotificationParam::c_lButtonState, x, y, 0); @@ -682,8 +687,8 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) #endif g_mousedown = TRUE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; if (InputManager()) { InputManager()->QueueEvent(c_notificationButtonDown, LegoEventNotificationParam::c_lButtonState, x, y, 0); @@ -729,8 +734,8 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) #endif g_mousedown = FALSE; - float x = SDL_clamp(event->tfinger.x, 0, 1) * 640; - float y = SDL_clamp(event->tfinger.y, 0, 1) * 480; + float x = SDL_clamp(event->tfinger.x, 0, 1) * g_targetWidth; + float y = SDL_clamp(event->tfinger.y, 0, 1) * g_targetHeight; if (InputManager()) { InputManager()->QueueEvent(c_notificationButtonUp, 0, x, y, 0); @@ -770,6 +775,11 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) if (!g_isle->GetGameStarted() && action && state == MxPresenter::e_ready && !SDL_strncmp(action->GetObjectName(), "Lego_Smk", 8)) { g_isle->SetGameStarted(TRUE); + +#ifdef __EMSCRIPTEN__ + Emscripten_SetupWindow((SDL_Window*) g_isle->GetWindowHandle()); +#endif + SDL_Log("Game started"); } } @@ -1413,8 +1423,8 @@ void IsleApp::MoveVirtualMouseViaJoystick() if (moveX != 0 || moveY != 0) { g_mousemoved = TRUE; - g_lastMouseX = SDL_clamp(g_lastMouseX + moveX, 0, 640); - g_lastMouseY = SDL_clamp(g_lastMouseY + moveY, 0, 480); + g_lastMouseX = SDL_clamp(g_lastMouseX + moveX, 0, g_targetWidth); + g_lastMouseY = SDL_clamp(g_lastMouseY + moveY, 0, g_targetHeight); if (InputManager()) { InputManager()->QueueEvent( diff --git a/miniwin/src/d3drm/d3drmdevice.cpp b/miniwin/src/d3drm/d3drmdevice.cpp index 25703f86..e3190692 100644 --- a/miniwin/src/d3drm/d3drmdevice.cpp +++ b/miniwin/src/d3drm/d3drmdevice.cpp @@ -173,31 +173,21 @@ bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event) break; } case SDL_EVENT_MOUSE_MOTION: { - int rawX = event->motion.x; - int rawY = event->motion.y; - float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; - float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; - event->motion.x = static_cast(x); - event->motion.y = static_cast(y); + event->motion.x = (event->motion.x - m_viewportTransform.offsetX) / m_viewportTransform.scale; + event->motion.y = (event->motion.y - m_viewportTransform.offsetY) / m_viewportTransform.scale; break; } case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - int rawX = event->button.x; - int rawY = event->button.y; - float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; - float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; - event->button.x = static_cast(x); - event->button.y = static_cast(y); + event->button.x = (event->button.x - m_viewportTransform.offsetX) / m_viewportTransform.scale; + event->button.y = (event->button.y - m_viewportTransform.offsetY) / m_viewportTransform.scale; break; } case SDL_EVENT_FINGER_MOTION: case SDL_EVENT_FINGER_DOWN: case SDL_EVENT_FINGER_UP: { - int rawX = event->tfinger.x * m_windowWidth; - int rawY = event->tfinger.y * m_windowHeight; - float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; - float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; + float x = (event->tfinger.x * m_windowWidth - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float y = (event->tfinger.y * m_windowHeight - m_viewportTransform.offsetY) / m_viewportTransform.scale; event->tfinger.x = x / m_virtualWidth; event->tfinger.y = y / m_virtualHeight; break;