iTranslated by AI
Running a WebGL App Built with Emscripten on Node.js
EDIT: Turns out Happy-DOM was actually unnecessary... https://github.com/okuoku/emtestapp/commit/a7dd4417b12d04db33f65f7666905ef6e91af740
Previous post:
Last time, I couldn't confirm any output, but this time, the images appeared properly. Screen display and I/O are not implemented yet.
In OpenGL, (0,0) is at the bottom-left, so simply copying the framebuffer results in it being flipped vertically.
It's rendering correctly. (The code being executed is the ImGUI Emscripten sample: https://github.com/ocornut/imgui/tree/1fb26d18c42cf90d4fb3f99da453912cccb6c3d3/examples/example_emscripten_opengl3 )
I've uploaded the code to GitHub:
Strategy
The strategy is the same as last time: load a DOM implementation library into Node.js and run it by faking a browser environment. The libraries used are also almost the same as before.
- Happy-DOM (
happy-dom) https://github.com/capricorn86/happy-dom - headless-gl (
gl) https://github.com/stackgl/headless-gl - pngjs (for screenshots)
Happy-DOM
This time, I tried using an implementation called Happy-DOM instead of the jsdom I used last time. I thought it might be useful for this purpose because Happy-DOM recently started to eval the contents of <script> tags.
... Unfortunately, this was a miss. While it is true that it gets eval-ed, it simply evals within the Node.js execution context, and since the global object doesn't become browser-like at all, it wasn't very useful. It's a bit disappointing because jsdom was well-considered in this regard.
Providing a Browser-like global
// Boot
const scr = wnd.document.createElement("script");
global.my_window = wnd;
global.my_fetch = fake_fetch;
global.my_doc = wnd.document;
global.my_module = my_module;
global.my_screen = my_screen;
global.fake_settimeout = fake_settimeout;
scr.textContent = "var window = global.my_window; var navigator = window.navigator; var fetch = global.my_fetch; var document = global.my_doc; var Module = global.my_module; var screen = global.my_screen; var setTimeout = global.fake_settimeout; \n" + bootstrap;
wnd.document.head.appendChild(scr);
Fortunately, or rather naturally, since eval is just the eval from the original Node.js environment, objects can be passed via global. So, this time, I took the approach of adding them as global variables using var at the beginning of the script to be executed.
Thoughts
Compared to Unity WebGL from last time (since Emscripten itself is originally intended to run on Node.js as well), it was really easy as it worked without doing much (KONAMI).
At this point, I feel like I might not even need a DOM implementation at all...
Discussion