iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💇

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:

https://qiita.com/okuoku/items/60ea7bb9c20b38505531

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:

https://github.com/okuoku/emtestapp/tree/fe2592e3388b9355626bc0abbaf0d854aa077aeb

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

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.

https://github.com/capricorn86/happy-dom/issues/142

... 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