summaryrefslogtreecommitdiff
path: root/src/video
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2020-12-05 21:57:47 +0100
committerPatric Stout <github@truebrain.nl>2020-12-15 15:46:39 +0100
commitd15dc9f40f5a20bff452547a2dcb15231f9f969d (patch)
tree7b8d88635c048d906cbb6358007fb26055e24410 /src/video
parent2da07f76154d841bcfe9aaff4833144550186deb (diff)
downloadopenttd-d15dc9f40f5a20bff452547a2dcb15231f9f969d.tar.xz
Add: support for emscripten (play-OpenTTD-in-the-browser)
Emscripten compiles to WASM, which can be loaded via HTML / JavaScript. This allows you to play OpenTTD inside a browser. Co-authored-by: milek7 <me@milek7.pl>
Diffstat (limited to 'src/video')
-rw-r--r--src/video/sdl2_v.cpp45
-rw-r--r--src/video/sdl2_v.h5
2 files changed, 46 insertions, 4 deletions
diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp
index 09d0e8a0b..68b0aa983 100644
--- a/src/video/sdl2_v.cpp
+++ b/src/video/sdl2_v.cpp
@@ -27,6 +27,10 @@
#include <mutex>
#include <condition_variable>
#include <algorithm>
+#ifdef __EMSCRIPTEN__
+# include <emscripten.h>
+# include <emscripten/html5.h>
+#endif
#include "../safeguards.h"
@@ -673,7 +677,19 @@ void VideoDriver_SDL::LoopOnce()
InteractiveRandom(); // randomness
while (PollEvent() == -1) {}
- if (_exit_game) return;
+ if (_exit_game) {
+#ifdef __EMSCRIPTEN__
+ /* Emscripten is event-driven, and as such the main loop is inside
+ * the browser. So if _exit_game goes true, the main loop ends (the
+ * cancel call), but we still have to call the cleanup that is
+ * normally done at the end of the main loop for non-Emscripten.
+ * After that, Emscripten just halts, and the HTML shows a nice
+ * "bye, see you next time" message. */
+ emscripten_cancel_main_loop();
+ MainLoopCleanup();
+#endif
+ return;
+ }
mod = SDL_GetModState();
keys = SDL_GetKeyboardState(&numkeys);
@@ -722,9 +738,17 @@ void VideoDriver_SDL::LoopOnce()
_local_palette = _cur_palette;
} else {
/* Release the thread while sleeping */
- if (_draw_mutex != nullptr) draw_lock.unlock();
- CSleep(1);
- if (_draw_mutex != nullptr) draw_lock.lock();
+ if (_draw_mutex != nullptr) {
+ draw_lock.unlock();
+ CSleep(1);
+ draw_lock.lock();
+ } else {
+/* Emscripten is running an event-based mainloop; there is already some
+ * downtime between each iteration, so no need to sleep. */
+#ifndef __EMSCRIPTEN__
+ CSleep(1);
+#endif
+ }
NetworkDrawChatMessage();
DrawMouseCursor();
@@ -778,6 +802,10 @@ void VideoDriver_SDL::MainLoop()
DEBUG(driver, 1, "SDL2: using %sthreads", _draw_threaded ? "" : "no ");
+#ifdef __EMSCRIPTEN__
+ /* Run the main loop event-driven, based on RequestAnimationFrame. */
+ emscripten_set_main_loop_arg(&this->EmscriptenLoop, this, 0, 1);
+#else
while (!_exit_game) {
LoopOnce();
}
@@ -803,6 +831,15 @@ void VideoDriver_SDL::MainLoopCleanup()
_draw_mutex = nullptr;
_draw_signal = nullptr;
}
+
+#ifdef __EMSCRIPTEN__
+ emscripten_exit_pointerlock();
+ /* In effect, the game ends here. As emscripten_set_main_loop() caused
+ * the stack to be unwound, the code after MainLoop() in
+ * openttd_main() is never executed. */
+ EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
+ EM_ASM(if (window["openttd_exit"]) openttd_exit());
+#endif
}
bool VideoDriver_SDL::ChangeResolution(int w, int h)
diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h
index 6318c403f..c2ac87a06 100644
--- a/src/video/sdl2_v.h
+++ b/src/video/sdl2_v.h
@@ -46,6 +46,11 @@ private:
void MainLoopCleanup();
bool CreateMainSurface(uint w, uint h, bool resize);
+#ifdef __EMSCRIPTEN__
+ /* Convert a constant pointer back to a non-constant pointer to a member function. */
+ static void EmscriptenLoop(void *self) { ((VideoDriver_SDL *)self)->LoopOnce(); }
+#endif
+
/**
* This is true to indicate that keyboard input is in text input mode, and SDL_TEXTINPUT events are enabled.
*/