Browse Source

emscripten: Let SDL hints be set by URL parameters.

Any parameters (key/value pairs after the '?' in a URL) that have a keyname
that starts with `SDL_` will be put into Emscripten's environment variable
emulation table at startup, before SDL_main runs.

This lets users set hints the same way they might set them from a shell's
command line on a desktop platform:

For example:

`https://example.com/my_sdl3_application.html?SDL_RENDER_DRIVER=software`

Fixes #10154.
Ryan C. Gordon 1 year ago
parent
commit
f338fa20dd
3 changed files with 68 additions and 0 deletions
  1. 2 0
      CMakeLists.txt
  2. 10 0
      include/SDL3/SDL_main.h
  3. 56 0
      src/core/emscripten/SDL_emscripten.c

+ 2 - 0
CMakeLists.txt

@@ -1480,6 +1480,8 @@ elseif(EMSCRIPTEN)
   # project. Uncomment at will for verbose cross-compiling -I/../ path info.
   # project. Uncomment at will for verbose cross-compiling -I/../ path info.
   sdl_compile_options(PRIVATE "-Wno-warn-absolute-paths")
   sdl_compile_options(PRIVATE "-Wno-warn-absolute-paths")
 
 
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/emscripten/*.c")
+
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/emscripten/*.c")
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/emscripten/*.c")
   set(HAVE_SDL_MAIN_CALLBACKS TRUE)
   set(HAVE_SDL_MAIN_CALLBACKS TRUE)
 
 

+ 10 - 0
include/SDL3/SDL_main.h

@@ -94,6 +94,16 @@
         /* We need to export SDL_main so it can be launched from Java */
         /* We need to export SDL_main so it can be launched from Java */
         #define SDLMAIN_DECLSPEC    SDL_DECLSPEC
         #define SDLMAIN_DECLSPEC    SDL_DECLSPEC
 
 
+    #elif defined(SDL_PLATFORM_EMSCRIPTEN)
+        /* On Emscripten, SDL provides a main function that converts URL
+           parameters that start with "SDL_" to environment variables, so
+           they can be used as SDL hints, etc.
+
+           This is 100% optional, so if you don't want this to happen, you may
+           define SDL_MAIN_HANDLED
+         */
+        #define SDL_MAIN_AVAILABLE
+
     #elif defined(SDL_PLATFORM_PSP)
     #elif defined(SDL_PLATFORM_PSP)
         /* On PSP SDL provides a main function that sets the module info,
         /* On PSP SDL provides a main function that sets the module info,
            activates the GPU and starts the thread required to be able to exit
            activates the GPU and starts the thread required to be able to exit

+ 56 - 0
src/core/emscripten/SDL_emscripten.c

@@ -0,0 +1,56 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2024 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifdef SDL_PLATFORM_EMSCRIPTEN
+
+#include <emscripten/emscripten.h>
+
+EM_JS_DEPS(sdlrunapp, "$dynCall,$stringToNewUTF8");
+
+int SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
+{
+    (void)reserved;
+
+    // Move any URL params that start with "SDL_" over to environment
+    //  variables, so the hint system can pick them up, etc, much like a user
+    //  can set them from a shell prompt on a desktop machine. Ignore all
+    //  other params, in case the app wants to use them for something.
+    MAIN_THREAD_EM_ASM({
+        var parms = new URLSearchParams(window.location.search);
+        for (const [key, value] of parms) {
+            if (key.startsWith("SDL_")) {
+                var ckey = stringToNewUTF8(key);
+                var cvalue = stringToNewUTF8(value);
+                if ((ckey != 0) && (cvalue != 0)) {
+                    //console.log("Setting SDL env var '" + key + "' to '" + value + "' ...");
+                    dynCall('iiii', $0, [ckey, cvalue, 1]);
+                }
+                _free(ckey);  // these must use free(), not SDL_free()!
+                _free(cvalue);
+            }
+        }
+    }, SDL_setenv);
+
+    return mainFunction(argc, argv);
+}
+
+#endif