diff options
author | Matthew Kosarek <matt.kosarek@canonical.com> | 2025-02-19 09:30:25 -0500 |
---|---|---|
committer | Matthew Kosarek <matt.kosarek@canonical.com> | 2025-02-19 09:30:25 -0500 |
commit | 3a996038684ed3d358259de6cde2f166dddaa04a (patch) | |
tree | 73b1978efb2ecdb39936b804920e3006c32f07f2 | |
parent | 5875b89ed114ee7a912167b5a609d1cf1da54a53 (diff) |
-rw-r--r-- | README.md | 29 | ||||
-rw-r--r-- | index.html | 6 | ||||
-rw-r--r-- | themes/compile_commands.json | 98 | ||||
-rw-r--r-- | themes/dist/output.js | 1913 | ||||
-rwxr-xr-x | themes/dist/output.wasm | bin | 157180 -> 171370 bytes | |||
-rw-r--r-- | themes/src/MainLoop.h | 2 | ||||
-rw-r--r-- | themes/src/main.cpp | 7 |
7 files changed, 1025 insertions, 1030 deletions
@@ -9,26 +9,27 @@ If you are on Github, this is a mirror of: https://git.matthewkosarek.xyz/matthe firefox localhost:8080 ``` -## Building +## Build Themes +1. Install emscripten: https://emscripten.org/docs/getting_started/downloads.html -### Themes -```sh -# Compile the shaders -cd themes/src -node tools/shaders.js - -# Build the project -cd .. -./compile-commands.sh -make -``` +2. Compile the shaders + ```sh + cd themes/src + node tools/shaders.js + ``` +3. Build the project + ```sh + cd .. + ./compile-commands.sh + make + ``` -### Posts +## Update Posts ```sh ./publish.sh ``` -## Upload +## Publish New Version ```sh ./upload.sh ``` @@ -62,9 +62,9 @@ <h2>About Me</h2> <p> Hi there 🌊 My name is Matthew Kosarek. - I am a computer programmer from northern New Jersey and I currently live Philadelphia, PA. I work at Canonical on the - <a href="https://github.com/canonical/mir">Mir display server</a> and I am currently building - <a href="https://github.com/mattkae/miracle-wm">miracle-wm</a>, a Mir-based tiling window manager. + I am a computer programmer from northern New Jersey and I currently live in Philadelphia, PA. I work at Canonical on + <a href="https://github.com/canonical/mir">Mir</a> and I am currently building + <a href="https://github.com/miracle-wm-org/miracle-wm">miracle-wm</a>, a Mir-based tiling window manager. </p> </section> <section> diff --git a/themes/compile_commands.json b/themes/compile_commands.json index bcf5405..020d53e 100644 --- a/themes/compile_commands.json +++ b/themes/compile_commands.json @@ -1,127 +1,127 @@ [ { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/MainLoop.cpp -o dist/./src/MainLoop.cpp.o", - "file": "dist/./src/MainLoop.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shader_fetcher.cpp -o dist/./src/shader_fetcher.cpp.o", + "file": "dist/./src/shader_fetcher.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/spring/SpringTheme.cpp -o dist/./src/spring/SpringTheme.cpp.o", - "file": "dist/./src/spring/SpringTheme.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/winter/WinterTheme.cpp -o dist/./src/winter/WinterTheme.cpp.o", + "file": "dist/./src/winter/WinterTheme.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/spring/GrassRenderer.cpp -o dist/./src/spring/GrassRenderer.cpp.o", - "file": "dist/./src/spring/GrassRenderer.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/winter/Windfield.cpp -o dist/./src/winter/Windfield.cpp.o", + "file": "dist/./src/winter/Windfield.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/mathlib.cpp -o dist/./src/mathlib.cpp.o", - "file": "dist/./src/mathlib.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/winter/Snowflake.cpp -o dist/./src/winter/Snowflake.cpp.o", + "file": "dist/./src/winter/Snowflake.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/renderer3d_frag.cpp -o dist/./src/shaders/renderer3d_frag.cpp.o", - "file": "dist/./src/shaders/renderer3d_frag.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/autumn/LeafParticleRender.cpp -o dist/./src/autumn/LeafParticleRender.cpp.o", + "file": "dist/./src/autumn/LeafParticleRender.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/sun_frag.cpp -o dist/./src/shaders/sun_frag.cpp.o", - "file": "dist/./src/shaders/sun_frag.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/autumn/AutumnTheme.cpp -o dist/./src/autumn/AutumnTheme.cpp.o", + "file": "dist/./src/autumn/AutumnTheme.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/renderer3d_vert.cpp -o dist/./src/shaders/renderer3d_vert.cpp.o", - "file": "dist/./src/shaders/renderer3d_vert.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/autumn/TreeShape.cpp -o dist/./src/autumn/TreeShape.cpp.o", + "file": "dist/./src/autumn/TreeShape.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/renderer2d_frag.cpp -o dist/./src/shaders/renderer2d_frag.cpp.o", - "file": "dist/./src/shaders/renderer2d_frag.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/Logger.cpp -o dist/./src/Logger.cpp.o", + "file": "dist/./src/Logger.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/sun_vert.cpp -o dist/./src/shaders/sun_vert.cpp.o", + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/sun_vert.cpp -o dist/./src/shaders/sun_vert.cpp.o", "file": "dist/./src/shaders/sun_vert.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shaders/renderer2d_vert.cpp -o dist/./src/shaders/renderer2d_vert.cpp.o", - "file": "dist/./src/shaders/renderer2d_vert.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/renderer2d_frag.cpp -o dist/./src/shaders/renderer2d_frag.cpp.o", + "file": "dist/./src/shaders/renderer2d_frag.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shader_fetcher.cpp -o dist/./src/shader_fetcher.cpp.o", - "file": "dist/./src/shader_fetcher.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/renderer3d_frag.cpp -o dist/./src/shaders/renderer3d_frag.cpp.o", + "file": "dist/./src/shaders/renderer3d_frag.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/Logger.cpp -o dist/./src/Logger.cpp.o", - "file": "dist/./src/Logger.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/sun_frag.cpp -o dist/./src/shaders/sun_frag.cpp.o", + "file": "dist/./src/shaders/sun_frag.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/Renderer3d.cpp -o dist/./src/Renderer3d.cpp.o", - "file": "dist/./src/Renderer3d.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/renderer2d_vert.cpp -o dist/./src/shaders/renderer2d_vert.cpp.o", + "file": "dist/./src/shaders/renderer2d_vert.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/Shader.cpp -o dist/./src/Shader.cpp.o", - "file": "dist/./src/Shader.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shaders/renderer3d_vert.cpp -o dist/./src/shaders/renderer3d_vert.cpp.o", + "file": "dist/./src/shaders/renderer3d_vert.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/summer/SummerTheme.cpp -o dist/./src/summer/SummerTheme.cpp.o", - "file": "dist/./src/summer/SummerTheme.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/shapes_2d.cpp -o dist/./src/shapes_2d.cpp.o", + "file": "dist/./src/shapes_2d.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/winter/Windfield.cpp -o dist/./src/winter/Windfield.cpp.o", - "file": "dist/./src/winter/Windfield.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/WebglContext.cpp -o dist/./src/WebglContext.cpp.o", + "file": "dist/./src/WebglContext.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/winter/WinterTheme.cpp -o dist/./src/winter/WinterTheme.cpp.o", - "file": "dist/./src/winter/WinterTheme.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/main.cpp -o dist/./src/main.cpp.o", + "file": "dist/./src/main.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/winter/Snowflake.cpp -o dist/./src/winter/Snowflake.cpp.o", - "file": "dist/./src/winter/Snowflake.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/Renderer2d.cpp -o dist/./src/Renderer2d.cpp.o", + "file": "dist/./src/Renderer2d.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/autumn/AutumnTheme.cpp -o dist/./src/autumn/AutumnTheme.cpp.o", - "file": "dist/./src/autumn/AutumnTheme.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/summer/SummerTheme.cpp -o dist/./src/summer/SummerTheme.cpp.o", + "file": "dist/./src/summer/SummerTheme.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/autumn/TreeShape.cpp -o dist/./src/autumn/TreeShape.cpp.o", - "file": "dist/./src/autumn/TreeShape.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/spring/SpringTheme.cpp -o dist/./src/spring/SpringTheme.cpp.o", + "file": "dist/./src/spring/SpringTheme.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/autumn/LeafParticleRender.cpp -o dist/./src/autumn/LeafParticleRender.cpp.o", - "file": "dist/./src/autumn/LeafParticleRender.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/spring/GrassRenderer.cpp -o dist/./src/spring/GrassRenderer.cpp.o", + "file": "dist/./src/spring/GrassRenderer.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/shapes_2d.cpp -o dist/./src/shapes_2d.cpp.o", - "file": "dist/./src/shapes_2d.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/Renderer3d.cpp -o dist/./src/Renderer3d.cpp.o", + "file": "dist/./src/Renderer3d.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/Renderer2d.cpp -o dist/./src/Renderer2d.cpp.o", - "file": "dist/./src/Renderer2d.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/mathlib.cpp -o dist/./src/mathlib.cpp.o", + "file": "dist/./src/mathlib.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/main.cpp -o dist/./src/main.cpp.o", - "file": "dist/./src/main.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/Shader.cpp -o dist/./src/Shader.cpp.o", + "file": "dist/./src/Shader.cpp.o" }, { "directory": ".", - "command": "g++ -I./src -I./src/spring -I./src/shaders -I./src/tools -I./src/summer -I./src/winter -I./src/autumn -I./src/_shaders -MMD -MP -c src/WebglContext.cpp -o dist/./src/WebglContext.cpp.o", - "file": "dist/./src/WebglContext.cpp.o" + "command": "g++ -I./src -I./src/winter -I./src/autumn -I./src/shaders -I./src/tools -I./src/_shaders -I./src/summer -I./src/spring -MMD -MP -c src/MainLoop.cpp -o dist/./src/MainLoop.cpp.o", + "file": "dist/./src/MainLoop.cpp.o" } ] diff --git a/themes/dist/output.js b/themes/dist/output.js index 13d1675..9ff02be 100644 --- a/themes/dist/output.js +++ b/themes/dist/output.js @@ -2,7 +2,7 @@ // The Module object: Our interface to the outside world. We import // and export values on it. There are various ways Module can be used: // 1. Not defined. We create it here -// 2. A function parameter, function(Module) { ..generated code.. } +// 2. A function parameter, function(moduleArg) => Promise<Module> // 3. pre-run appended it, var Module = {}; ..generated code.. // 4. External script tag defines var Module. // We need to check if Module already exists (e.g. case 3 above). @@ -14,6 +14,21 @@ // can continue to use Module afterwards as well. var Module = typeof Module != 'undefined' ? Module : {}; +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). + +// Attempt to auto-detect the environment +var ENVIRONMENT_IS_WEB = typeof window == 'object'; +var ENVIRONMENT_IS_WORKER = typeof WorkerGlobalScope != 'undefined'; +// N.b. Electron.js environment is simultaneously a NODE-environment, but +// also a web environment. +var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string' && process.type != 'renderer'; +var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; + +if (ENVIRONMENT_IS_NODE) { + +} + // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) @@ -31,21 +46,6 @@ var quit_ = (status, toThrow) => { throw toThrow; }; -// Determine the runtime environment we are in. You can customize this by -// setting the ENVIRONMENT setting at compile time (see settings.js). - -// Attempt to auto-detect the environment -var ENVIRONMENT_IS_WEB = typeof window == 'object'; -var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'; -// N.b. Electron.js environment is simultaneously a NODE-environment, but -// also a web environment. -var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string'; -var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; - -if (Module['ENVIRONMENT']) { - throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); -} - // `/` should be present at the end if `scriptDirectory` is not empty var scriptDirectory = ''; function locateFile(path) { @@ -56,9 +56,7 @@ function locateFile(path) { } // Hooks that are implemented differently in different runtime environments. -var read_, - readAsync, - readBinary; +var readAsync, readBinary; if (ENVIRONMENT_IS_NODE) { if (typeof process == 'undefined' || !process.release || process.release.name !== 'node') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); @@ -71,45 +69,28 @@ if (ENVIRONMENT_IS_NODE) { throw new Error('This emscripten-generated code requires node v16.0.0 (detected v' + nodeVersion + ')'); } - // `require()` is no-op in an ESM module, use `createRequire()` to construct - // the require()` function. This is only necessary for multi-environment - // builds, `-sENVIRONMENT=node` emits a static import declaration instead. - // TODO: Swap all `require()`'s with `import()`'s? // These modules will usually be used on Node.js. Load them eagerly to avoid // the complexity of lazy-loading. var fs = require('fs'); var nodePath = require('path'); - if (ENVIRONMENT_IS_WORKER) { - scriptDirectory = nodePath.dirname(scriptDirectory) + '/'; - } else { - scriptDirectory = __dirname + '/'; - } + scriptDirectory = __dirname + '/'; // include: node_shell_read.js -read_ = (filename, binary) => { - // We need to re-wrap `file://` strings to URLs. Normalizing isn't - // necessary in that case, the path should already be absolute. - filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); - return fs.readFileSync(filename, binary ? undefined : 'utf8'); -}; - readBinary = (filename) => { - var ret = read_(filename, true); - if (!ret.buffer) { - ret = new Uint8Array(ret); - } - assert(ret.buffer); + // We need to re-wrap `file://` strings to URLs. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename); + assert(Buffer.isBuffer(ret)); return ret; }; -readAsync = (filename, onload, onerror, binary = true) => { - // See the comment in the `read_` function. - filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); - fs.readFile(filename, binary ? undefined : 'utf8', (err, data) => { - if (err) onerror(err); - else onload(binary ? data.buffer : data); - }); +readAsync = async (filename, binary = true) => { + // See the comment in the `readBinary` function. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename, binary ? undefined : 'utf8'); + assert(binary ? Buffer.isBuffer(ret) : typeof ret == 'string'); + return ret; }; // end include: node_shell_read.js if (!Module['thisProgram'] && process.argv.length > 1) { @@ -122,88 +103,15 @@ readAsync = (filename, onload, onerror, binary = true) => { module['exports'] = Module; } - process.on('uncaughtException', (ex) => { - // suppress ExitStatus exceptions from showing an error - if (ex !== 'unwind' && !(ex instanceof ExitStatus) && !(ex.context instanceof ExitStatus)) { - throw ex; - } - }); - quit_ = (status, toThrow) => { process.exitCode = status; throw toThrow; }; - Module['inspect'] = () => '[Emscripten Module object]'; - } else if (ENVIRONMENT_IS_SHELL) { - if ((typeof process == 'object' && typeof require === 'function') || typeof window == 'object' || typeof importScripts == 'function') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); - - if (typeof read != 'undefined') { - read_ = read; - } - - readBinary = (f) => { - if (typeof readbuffer == 'function') { - return new Uint8Array(readbuffer(f)); - } - let data = read(f, 'binary'); - assert(typeof data == 'object'); - return data; - }; - - readAsync = (f, onload, onerror) => { - setTimeout(() => onload(readBinary(f))); - }; - - if (typeof clearTimeout == 'undefined') { - globalThis.clearTimeout = (id) => {}; - } - - if (typeof setTimeout == 'undefined') { - // spidermonkey lacks setTimeout but we use it above in readAsync. - globalThis.setTimeout = (f) => (typeof f == 'function') ? f() : abort(); - } - - if (typeof scriptArgs != 'undefined') { - arguments_ = scriptArgs; - } else if (typeof arguments != 'undefined') { - arguments_ = arguments; - } - - if (typeof quit == 'function') { - quit_ = (status, toThrow) => { - // Unlike node which has process.exitCode, d8 has no such mechanism. So we - // have no way to set the exit code and then let the program exit with - // that code when it naturally stops running (say, when all setTimeouts - // have completed). For that reason, we must call `quit` - the only way to - // set the exit code - but quit also halts immediately. To increase - // consistency with node (and the web) we schedule the actual quit call - // using a setTimeout to give the current stack and any exception handlers - // a chance to run. This enables features such as addOnPostRun (which - // expected to be able to run code after main returns). - setTimeout(() => { - if (!(toThrow instanceof ExitStatus)) { - let toLog = toThrow; - if (toThrow && typeof toThrow == 'object' && toThrow.stack) { - toLog = [toThrow, toThrow.stack]; - } - err(`exiting due to exception: ${toLog}`); - } - quit(status); - }); - throw toThrow; - }; - } - - if (typeof print != 'undefined') { - // Prefer to use print/printErr where they exist, as they usually work better. - if (typeof console == 'undefined') console = /** @type{!Console} */({}); - console.log = /** @type{!function(this:Console, ...*): undefined} */ (print); - console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr != 'undefined' ? printErr : print); - } + if ((typeof process == 'object' && typeof require === 'function') || typeof window == 'object' || typeof WorkerGlobalScope != 'undefined') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); } else @@ -222,26 +130,17 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { // and scriptDirectory will correctly be replaced with an empty string. // If scriptDirectory contains a query (starting with ?) or a fragment (starting with #), // they are removed because they could contain a slash. - if (scriptDirectory.indexOf('blob:') !== 0) { - scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf('/')+1); - } else { + if (scriptDirectory.startsWith('blob:')) { scriptDirectory = ''; + } else { + scriptDirectory = scriptDirectory.slice(0, scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/')+1); } - if (!(typeof window == 'object' || typeof importScripts == 'function')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); + if (!(typeof window == 'object' || typeof WorkerGlobalScope != 'undefined')) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)'); - // Differentiate the Web Worker from the Node Worker case, as reading must - // be done differently. { // include: web_or_worker_shell_read.js -read_ = (url) => { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.send(null); - return xhr.responseText; - } - - if (ENVIRONMENT_IS_WORKER) { +if (ENVIRONMENT_IS_WORKER) { readBinary = (url) => { var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); @@ -251,21 +150,33 @@ read_ = (url) => { }; } - readAsync = (url, onload, onerror) => { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = 'arraybuffer'; - xhr.onload = () => { - if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 - onload(xhr.response); - return; - } - onerror(); - }; - xhr.onerror = onerror; - xhr.send(null); - } - + readAsync = async (url) => { + // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. + // See https://github.com/github/fetch/pull/92#issuecomment-140665932 + // Cordova or Electron apps are typically loaded from a file:// url. + // So use XHR on webview if URL is a file URL. + if (isFileURI(url)) { + return new Promise((resolve, reject) => { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'arraybuffer'; + xhr.onload = () => { + if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0 + resolve(xhr.response); + return; + } + reject(xhr.status); + }; + xhr.onerror = reject; + xhr.send(null); + }); + } + var response = await fetch(url, { credentials: 'same-origin' }); + if (response.ok) { + return response.arrayBuffer(); + } + throw new Error(response.status + ' : ' + response.url); + }; // end include: web_or_worker_shell_read.js } } else @@ -279,7 +190,7 @@ var err = Module['printErr'] || console.error.bind(console); // Merge back in the overrides Object.assign(Module, moduleOverrides); // Free the object hierarchy contained in the overrides, this lets the GC -// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. +// reclaim data used. moduleOverrides = null; checkIncomingModuleAPI(); @@ -292,21 +203,18 @@ if (Module['arguments']) arguments_ = Module['arguments'];legacyModuleProp('argu if (Module['thisProgram']) thisProgram = Module['thisProgram'];legacyModuleProp('thisProgram', 'thisProgram'); -if (Module['quit']) quit_ = Module['quit'];legacyModuleProp('quit', 'quit_'); - // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message // Assertions on removed incoming Module JS APIs. assert(typeof Module['memoryInitializerPrefixURL'] == 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['pthreadMainPrefixURL'] == 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['cdInitializerPrefixURL'] == 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead'); assert(typeof Module['filePackagePrefixURL'] == 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead'); -assert(typeof Module['read'] == 'undefined', 'Module.read option was removed (modify read_ in JS)'); +assert(typeof Module['read'] == 'undefined', 'Module.read option was removed'); assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)'); assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify emscripten_set_window_title in JS)'); assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); legacyModuleProp('asm', 'wasmExports'); -legacyModuleProp('read', 'read_'); legacyModuleProp('readAsync', 'readAsync'); legacyModuleProp('readBinary', 'readBinary'); legacyModuleProp('setWindowTitle', 'setWindowTitle'); @@ -320,10 +228,10 @@ var OPFS = 'OPFS is no longer included by default; build with -lopfs.js'; var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js'; -assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at build time. Add 'shell' to `-sENVIRONMENT` to enable."); - +assert(!ENVIRONMENT_IS_SHELL, 'shell environment detected but not enabled at build time. Add `shell` to `-sENVIRONMENT` to enable.'); // end include: shell.js + // include: preamble.js // === Preamble library stuff === @@ -335,12 +243,10 @@ assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at bui // An online HTML version (which may be of a different version of Emscripten) // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html -var wasmBinary; -if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); -var noExitRuntime = Module['noExitRuntime'] || true;legacyModuleProp('noExitRuntime', 'noExitRuntime'); +var wasmBinary = Module['wasmBinary'];legacyModuleProp('wasmBinary', 'wasmBinary'); if (typeof WebAssembly != 'object') { - abort('no native wasm support detected'); + err('no native wasm support detected'); } // Wasm globals @@ -360,6 +266,10 @@ var ABORT = false; // but only when noExitRuntime is false. var EXITSTATUS; +// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we +// don't define it at all in release modes. This matches the behaviour of +// MINIMAL_RUNTIME. +// TODO(sbc): Make this the default even without STRICT enabled. /** @type {function(*, string=)} */ function assert(condition, text) { if (!condition) { @@ -387,30 +297,24 @@ var HEAP, HEAPU32, /** @type {!Float32Array} */ HEAPF32, +/* BigInt64Array type is not correctly defined in closure +/** not-@type {!BigInt64Array} */ + HEAP64, +/* BigUint64Array type is not correctly defined in closure +/** not-t@type {!BigUint64Array} */ + HEAPU64, /** @type {!Float64Array} */ HEAPF64; -function updateMemoryViews() { - var b = wasmMemory.buffer; - Module['HEAP8'] = HEAP8 = new Int8Array(b); - Module['HEAP16'] = HEAP16 = new Int16Array(b); - Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); - Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); - Module['HEAP32'] = HEAP32 = new Int32Array(b); - Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); - Module['HEAPF32'] = HEAPF32 = new Float32Array(b); - Module['HEAPF64'] = HEAPF64 = new Float64Array(b); -} - -assert(!Module['STACK_SIZE'], 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time') - -assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined, - 'JS engine does not provide full typed array support'); +var runtimeInitialized = false; -// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY -assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); -assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ +var isFileURI = (filename) => filename.startsWith('file://'); +// include: runtime_shared.js // include: runtime_stack_check.js // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { @@ -449,30 +353,153 @@ function checkStackCookie() { } } // end include: runtime_stack_check.js -// include: runtime_assertions.js +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js // Endianness check -(function() { +(() => { var h16 = new Int16Array(1); var h8 = new Int8Array(h16.buffer); h16[0] = 0x6373; if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -sSUPPORT_BIG_ENDIAN to bypass)'; })(); -// end include: runtime_assertions.js -var __ATPRERUN__ = []; // functions called before the runtime is initialized -var __ATINIT__ = []; // functions called during startup -var __ATMAIN__ = []; // functions called when main() is to be run -var __ATEXIT__ = []; // functions called during shutdown -var __ATPOSTRUN__ = []; // functions called after the main() is called +if (Module['ENVIRONMENT']) { + throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node)'); +} -var runtimeInitialized = false; +function legacyModuleProp(prop, newName, incoming=true) { + if (!Object.getOwnPropertyDescriptor(Module, prop)) { + Object.defineProperty(Module, prop, { + configurable: true, + get() { + let extra = incoming ? ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)' : ''; + abort(`\`Module.${prop}\` has been replaced by \`${newName}\`` + extra); + + } + }); + } +} + +function ignoredModuleProp(prop) { + if (Object.getOwnPropertyDescriptor(Module, prop)) { + abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); + } +} + +// forcing the filesystem exports a few things by default +function isExportedByForceFilesystem(name) { + return name === 'FS_createPath' || + name === 'FS_createDataFile' || + name === 'FS_createPreloadedFile' || + name === 'FS_unlink' || + name === 'addRunDependency' || + // The old FS has some functionality that WasmFS lacks. + name === 'FS_createLazyFile' || + name === 'FS_createDevice' || + name === 'removeRunDependency'; +} -var runtimeKeepaliveCounter = 0; +/** + * Intercept access to a global symbol. This enables us to give informative + * warnings/errors when folks attempt to use symbols they did not include in + * their build, or no symbols that no longer exist. + */ +function hookGlobalSymbolAccess(sym, func) { + if (typeof globalThis != 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { + Object.defineProperty(globalThis, sym, { + configurable: true, + get() { + func(); + return undefined; + } + }); + } +} -function keepRuntimeAlive() { - return noExitRuntime || runtimeKeepaliveCounter > 0; +function missingGlobal(sym, msg) { + hookGlobalSymbolAccess(sym, () => { + warnOnce(`\`${sym}\` is not longer defined by emscripten. ${msg}`); + }); } +missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); +missingGlobal('asm', 'Please use wasmExports instead'); + +function missingLibrarySymbol(sym) { + hookGlobalSymbolAccess(sym, () => { + // Can't `abort()` here because it would break code that does runtime + // checks. e.g. `if (typeof SDL === 'undefined')`. + var msg = `\`${sym}\` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line`; + // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in + // library.js, which means $name for a JS name with no prefix, or name + // for a JS name like _name. + var librarySymbol = sym; + if (!librarySymbol.startsWith('_')) { + librarySymbol = '$' + sym; + } + msg += ` (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='${librarySymbol}')`; + if (isExportedByForceFilesystem(sym)) { + msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; + } + warnOnce(msg); + }); + + // Any symbol that is not included from the JS library is also (by definition) + // not exported on the Module object. + unexportedRuntimeSymbol(sym); +} + +function unexportedRuntimeSymbol(sym) { + if (!Object.getOwnPropertyDescriptor(Module, sym)) { + Object.defineProperty(Module, sym, { + configurable: true, + get() { + var msg = `'${sym}' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)`; + if (isExportedByForceFilesystem(sym)) { + msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; + } + abort(msg); + } + }); + } +} + +// Used by XXXXX_DEBUG settings to output debug messages. +function dbg(...args) { + // TODO(sbc): Make this configurable somehow. Its not always convenient for + // logging to show up as warnings. + console.warn(...args); +} +// end include: runtime_debug.js +// include: memoryprofiler.js +// end include: memoryprofiler.js + + +function updateMemoryViews() { + var b = wasmMemory.buffer; + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); + Module['HEAP32'] = HEAP32 = new Int32Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + Module['HEAPF32'] = HEAPF32 = new Float32Array(b); + Module['HEAPF64'] = HEAPF64 = new Float64Array(b); + Module['HEAP64'] = HEAP64 = new BigInt64Array(b); + Module['HEAPU64'] = HEAPU64 = new BigUint64Array(b); +} + +// end include: runtime_shared.js +assert(!Module['STACK_SIZE'], 'STACK_SIZE can no longer be set at runtime. Use -sSTACK_SIZE at link time') + +assert(typeof Int32Array != 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray != undefined && Int32Array.prototype.set != undefined, + 'JS engine does not provide full typed array support'); + +// If memory is defined in wasm, the user can't provide it, or set INITIAL_MEMORY +assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -sIMPORTED_MEMORY to define wasmMemory externally'); +assert(!Module['INITIAL_MEMORY'], 'Detected runtime INITIAL_MEMORY setting. Use -sIMPORTED_MEMORY to define wasmMemory dynamically'); + function preRun() { if (Module['preRun']) { if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; @@ -480,7 +507,7 @@ function preRun() { addOnPreRun(Module['preRun'].shift()); } } - callRuntimeCallbacks(__ATPRERUN__); + callRuntimeCallbacks(onPreRuns); } function initRuntime() { @@ -490,13 +517,15 @@ function initRuntime() { checkStackCookie(); - callRuntimeCallbacks(__ATINIT__); + + wasmExports['__wasm_call_ctors'](); + + } function preMain() { checkStackCookie(); - callRuntimeCallbacks(__ATMAIN__); } function postRun() { @@ -509,42 +538,9 @@ function postRun() { } } - callRuntimeCallbacks(__ATPOSTRUN__); -} - -function addOnPreRun(cb) { - __ATPRERUN__.unshift(cb); + callRuntimeCallbacks(onPostRuns); } -function addOnInit(cb) { - __ATINIT__.unshift(cb); -} - -function addOnPreMain(cb) { - __ATMAIN__.unshift(cb); -} - -function addOnExit(cb) { -} - -function addOnPostRun(cb) { - __ATPOSTRUN__.unshift(cb); -} - -// include: runtime_math.js -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc - -assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill'); -// end include: runtime_math.js // A counter of dependencies for calling run(). If we need to // do asynchronous work before running, increment this and // decrement it. Incrementing must happen in a place like @@ -553,9 +549,9 @@ assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGAC // it happens right before run - run will be postponed until // the dependencies are met. var runDependencies = 0; -var runDependencyWatcher = null; var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled var runDependencyTracking = {}; +var runDependencyWatcher = null; function getUniqueRunDependency(id) { var orig = id; @@ -568,9 +564,7 @@ function getUniqueRunDependency(id) { function addRunDependency(id) { runDependencies++; - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); - } + Module['monitorRunDependencies']?.(runDependencies); if (id) { assert(!runDependencyTracking[id]); @@ -604,9 +598,7 @@ function addRunDependency(id) { function removeRunDependency(id) { runDependencies--; - if (Module['monitorRunDependencies']) { - Module['monitorRunDependencies'](runDependencies); - } + Module['monitorRunDependencies']?.(runDependencies); if (id) { assert(runDependencyTracking[id]); @@ -629,9 +621,7 @@ function removeRunDependency(id) { /** @param {string|number=} what */ function abort(what) { - if (Module['onAbort']) { - Module['onAbort'](what); - } + Module['onAbort']?.(what); what = 'Aborted(' + what + ')'; // TODO(sbc): Should we remove printing and leave it up to whoever @@ -639,7 +629,6 @@ function abort(what) { err(what); ABORT = true; - EXITSTATUS = 1; // Use a wasm runtime error, because a JS error might be seen as a foreign // exception, which means we'd run destructors on it. We need the error to @@ -651,7 +640,7 @@ function abort(what) { // allows this in the wasm spec. // Suppress closure compiler warning here. Closure compiler's builtin extern - // defintion for WebAssembly.RuntimeError claims it takes no arguments even + // definition for WebAssembly.RuntimeError claims it takes no arguments even // though it can. // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. /** @suppress {checkTypes} */ @@ -663,8 +652,6 @@ function abort(what) { throw e; } -// include: memoryprofiler.js -// end include: memoryprofiler.js // show errors on likely calls to FS when it was not included var FS = { error() { @@ -684,37 +671,21 @@ var FS = { Module['FS_createDataFile'] = FS.createDataFile; Module['FS_createPreloadedFile'] = FS.createPreloadedFile; -// include: URIUtils.js -// Prefix of data URIs emitted by SINGLE_FILE and related options. -var dataURIPrefix = 'data:application/octet-stream;base64,'; - -// Indicates whether filename is a base64 data URI. -function isDataURI(filename) { - // Prefix of data URIs emitted by SINGLE_FILE and related options. - return filename.startsWith(dataURIPrefix); -} - -// Indicates whether filename is delivered via file protocol (as opposed to http/https) -function isFileURI(filename) { - return filename.startsWith('file://'); -} -// end include: URIUtils.js -function createExportWrapper(name) { - return function() { +function createExportWrapper(name, nargs) { + return (...args) => { assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`); var f = wasmExports[name]; assert(f, `exported native function \`${name}\` not found`); - return f.apply(null, arguments); + // Only assert for too many arguments. Too few can be valid since the missing arguments will be zero filled. + assert(args.length <= nargs, `native function \`${name}\` called with ${args.length} args but expects ${nargs}`); + return f(...args); }; } -// include: runtime_exceptions.js -// end include: runtime_exceptions.js var wasmBinaryFile; - wasmBinaryFile = 'output.wasm'; - if (!isDataURI(wasmBinaryFile)) { - wasmBinaryFile = locateFile(wasmBinaryFile); - } +function findWasmBinary() { + return locateFile('output.wasm'); +} function getBinarySync(file) { if (file == wasmBinaryFile && wasmBinary) { @@ -723,45 +694,31 @@ function getBinarySync(file) { if (readBinary) { return readBinary(file); } - throw "both async and sync fetching of the wasm failed"; + throw 'both async and sync fetching of the wasm failed'; } -function getBinaryPromise(binaryFile) { - // If we don't have the binary yet, try to load it asynchronously. - // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. - // See https://github.com/github/fetch/pull/92#issuecomment-140665932 - // Cordova or Electron apps are typically loaded from a file:// url. - // So use fetch if it is available and the url is not a file, otherwise fall back to XHR. - if (!wasmBinary - && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { - if (typeof fetch == 'function' - && !isFileURI(binaryFile) - ) { - return fetch(binaryFile, { credentials: 'same-origin' }).then((response) => { - if (!response['ok']) { - throw "failed to load wasm binary file at '" + binaryFile + "'"; - } - return response['arrayBuffer'](); - }).catch(() => getBinarySync(binaryFile)); - } - else if (readAsync) { - // fetch is not available or url is file => try XHR (readAsync uses XHR internally) - return new Promise((resolve, reject) => { - readAsync(binaryFile, (response) => resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))), reject) - }); +async function getWasmBinary(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary) { + // Fetch the binary using readAsync + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch { + // Fall back to getBinarySync below; } } // Otherwise, getBinarySync should be able to get it synchronously - return Promise.resolve().then(() => getBinarySync(binaryFile)); + return getBinarySync(binaryFile); } -function instantiateArrayBuffer(binaryFile, imports, receiver) { - return getBinaryPromise(binaryFile).then((binary) => { - return WebAssembly.instantiate(binary, imports); - }).then((instance) => { +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); return instance; - }).then(receiver, (reason) => { + } catch (reason) { err(`failed to asynchronously prepare wasm: ${reason}`); // Warn on some common problems. @@ -769,53 +726,47 @@ function instantiateArrayBuffer(binaryFile, imports, receiver) { err(`warning: Loading from a file URI (${wasmBinaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`); } abort(reason); - }); + } } -function instantiateAsync(binary, binaryFile, imports, callback) { - if (!binary && - typeof WebAssembly.instantiateStreaming == 'function' && - !isDataURI(binaryFile) && +async function instantiateAsync(binary, binaryFile, imports) { + if (!binary && typeof WebAssembly.instantiateStreaming == 'function' // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously. - !isFileURI(binaryFile) && + && !isFileURI(binaryFile) // Avoid instantiateStreaming() on Node.js environment for now, as while // Node.js v18.1.0 implements it, it does not have a full fetch() // implementation yet. // // Reference: // https://github.com/emscripten-core/emscripten/pull/16917 - !ENVIRONMENT_IS_NODE && - typeof fetch == 'function') { - return fetch(binaryFile, { credentials: 'same-origin' }).then((response) => { - // Suppress closure warning here since the upstream definition for - // instantiateStreaming only allows Promise<Repsponse> rather than - // an actual Response. - // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed. - /** @suppress {checkTypes} */ - var result = WebAssembly.instantiateStreaming(response, imports); - - return result.then( - callback, - function(reason) { - // We expect the most common failure cause to be a bad MIME type for the binary, - // in which case falling back to ArrayBuffer instantiation should work. - err(`wasm streaming compile failed: ${reason}`); - err('falling back to ArrayBuffer instantiation'); - return instantiateArrayBuffer(binaryFile, imports, callback); - }); - }); - } - return instantiateArrayBuffer(binaryFile, imports, callback); + && !ENVIRONMENT_IS_NODE + ) { + try { + var response = fetch(binaryFile, { credentials: 'same-origin' }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err('falling back to ArrayBuffer instantiation'); + // fall back of instantiateArrayBuffer below + }; + } + return instantiateArrayBuffer(binaryFile, imports); } -// Create the wasm instance. -// Receives the wasm imports, returns the exports. -function createWasm() { +function getWasmImports() { // prepare imports - var info = { + return { 'env': wasmImports, 'wasi_snapshot_preview1': wasmImports, - }; + } +} + +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +async function createWasm() { // Load the wasm module and create an instance of using native support in the JS engine. // handle a generated wasm instance, receiving its exports and // performing other necessary setup @@ -827,18 +778,12 @@ function createWasm() { wasmMemory = wasmExports['memory']; - assert(wasmMemory, "memory not found in wasm exports"); - // This assertion doesn't hold when emscripten is run in --post-link - // mode. - // TODO(sbc): Read INITIAL_MEMORY out of the wasm file in post-link mode. - //assert(wasmMemory.buffer.byteLength === 16777216); + assert(wasmMemory, 'memory not found in wasm exports'); updateMemoryViews(); wasmTable = wasmExports['__indirect_function_table']; - assert(wasmTable, "table not found in wasm exports"); - - addOnInit(wasmExports['__wasm_call_ctors']); + assert(wasmTable, 'table not found in wasm exports'); removeRunDependency('wasm-instantiate'); return wasmExports; @@ -858,9 +803,11 @@ function createWasm() { trueModule = null; // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line. // When the regression is fixed, can restore the above PTHREADS-enabled path. - receiveInstance(result['instance']); + return receiveInstance(result['instance']); } + var info = getWasmImports(); + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback // to manually instantiate the Wasm module themselves. This allows pages to // run the instantiation parallel to any other async startup actions they are @@ -868,131 +815,36 @@ function createWasm() { // Also pthreads and wasm workers initialize the wasm instance through this // path. if (Module['instantiateWasm']) { - - try { - return Module['instantiateWasm'](info, receiveInstance); - } catch(e) { - err(`Module.instantiateWasm callback failed with error: ${e}`); - return false; - } - } - - instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult); - return {}; // no exports yet; we'll fill them in later -} - -// Globals used by JS i64 conversions (see makeSetValue) -var tempDouble; -var tempI64; - -// include: runtime_debug.js -function legacyModuleProp(prop, newName, incomming=true) { - if (!Object.getOwnPropertyDescriptor(Module, prop)) { - Object.defineProperty(Module, prop, { - configurable: true, - get() { - let extra = incomming ? ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)' : ''; - abort(`\`Module.${prop}\` has been replaced by \`${newName}\`` + extra); - - } - }); - } -} - -function ignoredModuleProp(prop) { - if (Object.getOwnPropertyDescriptor(Module, prop)) { - abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); - } -} - -// forcing the filesystem exports a few things by default -function isExportedByForceFilesystem(name) { - return name === 'FS_createPath' || - name === 'FS_createDataFile' || - name === 'FS_createPreloadedFile' || - name === 'FS_unlink' || - name === 'addRunDependency' || - // The old FS has some functionality that WasmFS lacks. - name === 'FS_createLazyFile' || - name === 'FS_createDevice' || - name === 'removeRunDependency'; -} - -function missingGlobal(sym, msg) { - if (typeof globalThis !== 'undefined') { - Object.defineProperty(globalThis, sym, { - configurable: true, - get() { - warnOnce('`' + sym + '` is not longer defined by emscripten. ' + msg); - return undefined; + return new Promise((resolve, reject) => { + try { + Module['instantiateWasm'](info, (mod, inst) => { + receiveInstance(mod, inst); + resolve(mod.exports); + }); + } catch(e) { + err(`Module.instantiateWasm callback failed with error: ${e}`); + reject(e); } }); } -} -missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); -missingGlobal('asm', 'Please use wasmExports instead'); - -function missingLibrarySymbol(sym) { - if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { - Object.defineProperty(globalThis, sym, { - configurable: true, - get() { - // Can't `abort()` here because it would break code that does runtime - // checks. e.g. `if (typeof SDL === 'undefined')`. - var msg = '`' + sym + '` is a library symbol and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line'; - // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE requires the name as it appears in - // library.js, which means $name for a JS name with no prefix, or name - // for a JS name like _name. - var librarySymbol = sym; - if (!librarySymbol.startsWith('_')) { - librarySymbol = '$' + sym; - } - msg += " (e.g. -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='" + librarySymbol + "')"; - if (isExportedByForceFilesystem(sym)) { - msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; - } - warnOnce(msg); - return undefined; - } - }); - } - // Any symbol that is not included from the JS libary is also (by definition) - // not exported on the Module object. - unexportedRuntimeSymbol(sym); -} + wasmBinaryFile ??= findWasmBinary(); -function unexportedRuntimeSymbol(sym) { - if (!Object.getOwnPropertyDescriptor(Module, sym)) { - Object.defineProperty(Module, sym, { - configurable: true, - get() { - var msg = "'" + sym + "' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the Emscripten FAQ)"; - if (isExportedByForceFilesystem(sym)) { - msg += '. Alternatively, forcing filesystem support (-sFORCE_FILESYSTEM) can export this for you'; - } - abort(msg); - } - }); - } + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; } -// Used by XXXXX_DEBUG settings to output debug messages. -function dbg(text) { - // TODO(sbc): Make this configurable somehow. Its not always convenient for - // logging to show up as warnings. - console.warn.apply(console, arguments); -} -// end include: runtime_debug.js // === Body === - // end include: preamble.js - /** @constructor */ - function ExitStatus(status) { - this.name = 'ExitStatus'; - this.message = `Program terminated with exit(${status})`; - this.status = status; + + class ExitStatus { + name = 'ExitStatus'; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } } var callRuntimeCallbacks = (callbacks) => { @@ -1001,6 +853,12 @@ function dbg(text) { callbacks.shift()(Module); } }; + var onPostRuns = []; + var addOnPostRun = (cb) => onPostRuns.unshift(cb); + + var onPreRuns = []; + var addOnPreRun = (cb) => onPreRuns.unshift(cb); + /** @@ -1010,11 +868,11 @@ function dbg(text) { function getValue(ptr, type = 'i8') { if (type.endsWith('*')) type = '*'; switch (type) { - case 'i1': return HEAP8[((ptr)>>0)]; - case 'i8': return HEAP8[((ptr)>>0)]; + case 'i1': return HEAP8[ptr]; + case 'i8': return HEAP8[ptr]; case 'i16': return HEAP16[((ptr)>>1)]; case 'i32': return HEAP32[((ptr)>>2)]; - case 'i64': abort('to do getValue(i64) use WASM_BIGINT'); + case 'i64': return HEAP64[((ptr)>>3)]; case 'float': return HEAPF32[((ptr)>>2)]; case 'double': return HEAPF64[((ptr)>>3)]; case '*': return HEAPU32[((ptr)>>2)]; @@ -1022,6 +880,8 @@ function dbg(text) { } } + var noExitRuntime = Module['noExitRuntime'] || true; + var ptrToString = (ptr) => { assert(typeof ptr === 'number'); // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. @@ -1038,11 +898,11 @@ function dbg(text) { function setValue(ptr, value, type = 'i8') { if (type.endsWith('*')) type = '*'; switch (type) { - case 'i1': HEAP8[((ptr)>>0)] = value; break; - case 'i8': HEAP8[((ptr)>>0)] = value; break; + case 'i1': HEAP8[ptr] = value; break; + case 'i8': HEAP8[ptr] = value; break; case 'i16': HEAP16[((ptr)>>1)] = value; break; case 'i32': HEAP32[((ptr)>>2)] = value; break; - case 'i64': abort('to do setValue(i64) use WASM_BIGINT'); + case 'i64': HEAP64[((ptr)>>3)] = BigInt(value); break; case 'float': HEAPF32[((ptr)>>2)] = value; break; case 'double': HEAPF64[((ptr)>>3)] = value; break; case '*': HEAPU32[((ptr)>>2)] = value; break; @@ -1050,8 +910,12 @@ function dbg(text) { } } + var stackRestore = (val) => __emscripten_stack_restore(val); + + var stackSave = () => _emscripten_stack_get_current(); + var warnOnce = (text) => { - if (!warnOnce.shown) warnOnce.shown = {}; + warnOnce.shown ||= {}; if (!warnOnce.shown[text]) { warnOnce.shown[text] = 1; if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text; @@ -1059,20 +923,10 @@ function dbg(text) { } }; - function __emscripten_fetch_free(id) { - if (Fetch.xhrs.has(id)) { - var xhr = Fetch.xhrs.get(id); - Fetch.xhrs.free(id); - // check if fetch is still in progress and should be aborted - if (xhr.readyState > 0 && xhr.readyState < 4) { - xhr.abort(); - } - } - } + var __abort_js = () => + abort('native code called abort()'); - var isLeapYear = (year) => { - return year%4 === 0 && (year%100 !== 0 || year%400 === 0); - }; + var isLeapYear = (year) => year%4 === 0 && (year%100 !== 0 || year%400 === 0); var MONTH_DAYS_LEAP_CUMULATIVE = [0,31,60,91,121,152,182,213,244,274,305,335]; @@ -1085,13 +939,12 @@ function dbg(text) { return yday; }; - var convertI32PairToI53Checked = (lo, hi) => { - assert(lo == (lo >>> 0) || lo == (lo|0)); // lo should either be a i32 or a u32 - assert(hi === (hi|0)); // hi should be a i32 - return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; - }; - function __localtime_js(time_low, time_high,tmPtr) { - var time = convertI32PairToI53Checked(time_low, time_high);; + var INT53_MAX = 9007199254740992; + + var INT53_MIN = -9007199254740992; + var bigintToI53Checked = (num) => (num < INT53_MIN || num > INT53_MAX) ? NaN : Number(num); + function __localtime_js(time, tmPtr) { + time = bigintToI53Checked(time); var date = new Date(time*1000); @@ -1116,29 +969,8 @@ function dbg(text) { ; } - var lengthBytesUTF8 = (str) => { - var len = 0; - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var c = str.charCodeAt(i); // possibly a lead surrogate - if (c <= 0x7F) { - len++; - } else if (c <= 0x7FF) { - len += 2; - } else if (c >= 0xD800 && c <= 0xDFFF) { - len += 4; ++i; - } else { - len += 3; - } - } - return len; - }; - var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { - assert(typeof str === 'string'); + assert(typeof str === 'string', `stringToUTF8Array expects a string (got ${typeof str})`); // Parameter maxBytesToWrite is not optional. Negative values, 0, null, // undefined and false each don't write out any bytes. if (!(maxBytesToWrite > 0)) @@ -1189,13 +1021,27 @@ function dbg(text) { return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); }; - var stringToNewUTF8 = (str) => { - var size = lengthBytesUTF8(str) + 1; - var ret = _malloc(size); - if (ret) stringToUTF8(str, ret, size); - return ret; + var lengthBytesUTF8 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); // possibly a lead surrogate + if (c <= 0x7F) { + len++; + } else if (c <= 0x7FF) { + len += 2; + } else if (c >= 0xD800 && c <= 0xDFFF) { + len += 4; ++i; + } else { + len += 3; + } + } + return len; }; - var __tzset_js = (timezone, daylight, tzname) => { + var __tzset_js = (timezone, daylight, std_name, dst_name) => { // TODO: Use (malleable) environment variables instead of system settings. var currentYear = new Date().getFullYear(); var winter = new Date(currentYear, 0, 1); @@ -1203,9 +1049,12 @@ function dbg(text) { var winterOffset = winter.getTimezoneOffset(); var summerOffset = summer.getTimezoneOffset(); - // Local standard timezone offset. Local standard time is not adjusted for daylight savings. - // This code uses the fact that getTimezoneOffset returns a greater value during Standard Time versus Daylight Saving Time (DST). - // Thus it determines the expected output during Standard Time, and it compares whether the output of the given date the same (Standard) or less (DST). + // Local standard timezone offset. Local standard time is not adjusted for + // daylight savings. This code uses the fact that getTimezoneOffset returns + // a greater value during Standard Time versus Daylight Saving Time (DST). + // Thus it determines the expected output during Standard Time, and it + // compares whether the output of the given date the same (Standard) or less + // (DST). var stdTimezoneOffset = Math.max(winterOffset, summerOffset); // timezone is specified as seconds west of UTC ("The external variable @@ -1217,51 +1066,60 @@ function dbg(text) { HEAP32[((daylight)>>2)] = Number(winterOffset != summerOffset); - function extractZone(date) { - var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/); - return match ? match[1] : "GMT"; - }; - var winterName = extractZone(winter); - var summerName = extractZone(summer); - var winterNamePtr = stringToNewUTF8(winterName); - var summerNamePtr = stringToNewUTF8(summerName); + var extractZone = (timezoneOffset) => { + // Why inverse sign? + // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + var sign = timezoneOffset >= 0 ? "-" : "+"; + + var absOffset = Math.abs(timezoneOffset) + var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); + var minutes = String(absOffset % 60).padStart(2, "0"); + + return `UTC${sign}${hours}${minutes}`; + } + + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); + assert(winterName); + assert(summerName); + assert(lengthBytesUTF8(winterName) <= 16, `timezone name truncated to fit in TZNAME_MAX (${winterName})`); + assert(lengthBytesUTF8(summerName) <= 16, `timezone name truncated to fit in TZNAME_MAX (${summerName})`); if (summerOffset < winterOffset) { // Northern hemisphere - HEAPU32[((tzname)>>2)] = winterNamePtr; - HEAPU32[(((tzname)+(4))>>2)] = summerNamePtr; + stringToUTF8(winterName, std_name, 17); + stringToUTF8(summerName, dst_name, 17); } else { - HEAPU32[((tzname)>>2)] = summerNamePtr; - HEAPU32[(((tzname)+(4))>>2)] = winterNamePtr; + stringToUTF8(winterName, dst_name, 17); + stringToUTF8(summerName, std_name, 17); } }; - var _abort = () => { - abort('native code called abort()'); - }; - var _emscripten_date_now = () => Date.now(); - var withStackSave = (f) => { - var stack = stackSave(); - var ret = f(); - stackRestore(stack); - return ret; - }; + function _emscripten_fetch_free(id) { + if (Fetch.xhrs.has(id)) { + var xhr = Fetch.xhrs.get(id); + Fetch.xhrs.free(id); + // check if fetch is still in progress and should be aborted + if (xhr.readyState > 0 && xhr.readyState < 4) { + xhr.abort(); + } + } + } + + var onExits = []; + var addOnExit = (cb) => onExits.unshift(cb); var JSEvents = { - inEventHandler:0, + memcpy(target, src, size) { + HEAP8.set(HEAP8.subarray(src, src + size), target); + }, removeAllEventListeners() { - for (var i = JSEvents.eventHandlers.length-1; i >= 0; --i) { - JSEvents._removeHandler(i); + while (JSEvents.eventHandlers.length) { + JSEvents._removeHandler(JSEvents.eventHandlers.length - 1); } - JSEvents.eventHandlers = []; JSEvents.deferredCalls = []; }, - registerRemoveEventListeners() { - if (!JSEvents.removeEventListenersRegistered) { - __ATEXIT__.push(JSEvents.removeAllEventListeners); - JSEvents.removeEventListenersRegistered = true; - } - }, + inEventHandler:0, deferredCalls:[], deferCall(targetFunction, precedence, argsList) { function arraysHaveEqualContent(arrA, arrB) { @@ -1273,8 +1131,7 @@ function dbg(text) { return true; } // Test if the given call was already queued, and if so, don't add it again. - for (var i in JSEvents.deferredCalls) { - var call = JSEvents.deferredCalls[i]; + for (var call of JSEvents.deferredCalls) { if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { return; } @@ -1288,12 +1145,7 @@ function dbg(text) { JSEvents.deferredCalls.sort((x,y) => x.precedence < y.precedence); }, removeDeferredCalls(targetFunction) { - for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { - if (JSEvents.deferredCalls[i].targetFunction == targetFunction) { - JSEvents.deferredCalls.splice(i, 1); - --i; - } - } + JSEvents.deferredCalls = JSEvents.deferredCalls.filter((call) => call.targetFunction != targetFunction); }, canPerformEventHandlerRequests() { if (navigator.userActivation) { @@ -1311,11 +1163,10 @@ function dbg(text) { if (!JSEvents.canPerformEventHandlerRequests()) { return; } - for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { - var call = JSEvents.deferredCalls[i]; - JSEvents.deferredCalls.splice(i, 1); - --i; - call.targetFunction.apply(null, call.argsList); + var deferredCalls = JSEvents.deferredCalls; + JSEvents.deferredCalls = []; + for (var call of deferredCalls) { + call.targetFunction(...call.argsList); } }, eventHandlers:[], @@ -1338,25 +1189,25 @@ function dbg(text) { console.dir(eventHandler); return -4; } - var jsEventHandler = function jsEventHandler(event) { - // Increment nesting count for the event handler. - ++JSEvents.inEventHandler; - JSEvents.currentEventHandler = eventHandler; - // Process any old deferred calls the user has placed. - JSEvents.runDeferredCalls(); - // Process the actual event, calls back to user C code handler. - eventHandler.handlerFunc(event); - // Process any new deferred calls that were placed right now from this event handler. - JSEvents.runDeferredCalls(); - // Out of event handler - restore nesting count. - --JSEvents.inEventHandler; - }; - if (eventHandler.callbackfunc) { - eventHandler.eventListenerFunc = jsEventHandler; - eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); + eventHandler.eventListenerFunc = function(event) { + // Increment nesting count for the event handler. + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; + // Process any old deferred calls the user has placed. + JSEvents.runDeferredCalls(); + // Process the actual event, calls back to user C code handler. + eventHandler.handlerFunc(event); + // Process any new deferred calls that were placed right now from this event handler. + JSEvents.runDeferredCalls(); + // Out of event handler - restore nesting count. + --JSEvents.inEventHandler; + }; + + eventHandler.target.addEventListener(eventHandler.eventTypeString, + eventHandler.eventListenerFunc, + eventHandler.useCapture); JSEvents.eventHandlers.push(eventHandler); - JSEvents.registerRemoveEventListeners(); } else { for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { if (JSEvents.eventHandlers[i].target == eventHandler.target @@ -1371,7 +1222,7 @@ function dbg(text) { if (!target) return ''; if (target == window) return '#window'; if (target == screen) return '#screen'; - return (target && target.nodeName) ? target.nodeName : ''; + return target?.nodeName || ''; }, fullscreenEnabled() { return document.fullscreenEnabled @@ -1382,25 +1233,25 @@ function dbg(text) { }, }; - var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; + var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined; /** * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given * array that contains uint8 values, returns a copy of that string as a * Javascript String object. * heapOrArray is either a regular array, or a JavaScript typed array view. - * @param {number} idx + * @param {number=} idx * @param {number=} maxBytesToRead * @return {string} */ - var UTF8ArrayToString = (heapOrArray, idx, maxBytesToRead) => { + var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => { var endIdx = idx + maxBytesToRead; var endPtr = idx; // TextDecoder needs to know the byte length in advance, it doesn't stop on // null terminator by itself. Also, use the length info to avoid running tiny // strings through TextDecoder, since .subarray() allocates garbage. // (As a tiny code save trick, compare endPtr against endIdx using a negation, - // so that undefined means Infinity) + // so that undefined/NaN means Infinity) while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { @@ -1452,7 +1303,7 @@ function dbg(text) { * @return {string} */ var UTF8ToString = (ptr, maxBytesToRead) => { - assert(typeof ptr == 'number'); + assert(typeof ptr == 'number', `UTF8ToString expects a number (got ${typeof ptr})`); return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; }; var maybeCStringToJsString = (cString) => { @@ -1463,10 +1314,11 @@ function dbg(text) { return cString > 2 ? UTF8ToString(cString) : cString; }; + /** @type {Object} */ var specialHTMLTargets = [0, typeof document != 'undefined' ? document : 0, typeof window != 'undefined' ? window : 0]; var findEventTarget = (target) => { target = maybeCStringToJsString(target); - var domElement = specialHTMLTargets[target] || (typeof document != 'undefined' ? document.querySelector(target) : undefined); + var domElement = specialHTMLTargets[target] || (typeof document != 'undefined' ? document.querySelector(target) : null); return domElement; }; @@ -1485,18 +1337,19 @@ function dbg(text) { var _emscripten_is_main_browser_thread = () => !ENVIRONMENT_IS_WORKER; - var _emscripten_memcpy_js = (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num); - var wasmTableMirror = []; + /** @type {WebAssembly.Table} */ var wasmTable; var getWasmTableEntry = (funcPtr) => { var func = wasmTableMirror[funcPtr]; if (!func) { if (funcPtr >= wasmTableMirror.length) wasmTableMirror.length = funcPtr + 1; + /** @suppress {checkTypes} */ wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); } - assert(wasmTable.get(funcPtr) == func, "JavaScript-side Wasm function table mirror is out of date!"); + /** @suppress {checkTypes} */ + assert(wasmTable.get(funcPtr) == func, 'JavaScript-side Wasm function table mirror is out of date!'); return func; }; var _emscripten_request_animation_frame_loop = (cb, userData) => { @@ -1515,9 +1368,14 @@ function dbg(text) { // casing all heap size related code to treat 0 specially. 2147483648; + var alignMemory = (size, alignment) => { + assert(alignment, "alignment argument is required"); + return Math.ceil(size / alignment) * alignment; + }; + var growMemory = (size) => { var b = wasmMemory.buffer; - var pages = (size - b.byteLength + 65535) / 65536; + var pages = ((size - b.byteLength + 65535) / 65536) | 0; try { // round size grow request up to wasm page size (fixed 64KB per spec) wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size @@ -1562,8 +1420,6 @@ function dbg(text) { return false; } - var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; - // Loop through potential heap size increases. If we attempt a too eager // reservation that fails, cut down on the attempted size and reserve a // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) @@ -1572,7 +1428,7 @@ function dbg(text) { // but limit overreserving (default to capping at +96MB overgrowth at most) overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); - var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); + var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)); var replacement = growMemory(newSize); if (replacement) { @@ -1585,7 +1441,7 @@ function dbg(text) { }; - var findCanvasEventTarget = (target) => findEventTarget(target); + var findCanvasEventTarget = findEventTarget; var _emscripten_set_canvas_element_size = (target, width, height) => { var canvas = findCanvasEventTarget(target); if (!canvas) return -4; @@ -1600,34 +1456,35 @@ function dbg(text) { var fillMouseEventData = (eventStruct, e, target) => { assert(eventStruct % 4 == 0); HEAPF64[((eventStruct)>>3)] = e.timeStamp; - var idx = eventStruct >> 2; + var idx = ((eventStruct)>>2); HEAP32[idx + 2] = e.screenX; HEAP32[idx + 3] = e.screenY; HEAP32[idx + 4] = e.clientX; HEAP32[idx + 5] = e.clientY; - HEAP32[idx + 6] = e.ctrlKey; - HEAP32[idx + 7] = e.shiftKey; - HEAP32[idx + 8] = e.altKey; - HEAP32[idx + 9] = e.metaKey; - HEAP16[idx*2 + 20] = e.button; - HEAP16[idx*2 + 21] = e.buttons; - - HEAP32[idx + 11] = e["movementX"] + HEAP8[eventStruct + 24] = e.ctrlKey; + HEAP8[eventStruct + 25] = e.shiftKey; + HEAP8[eventStruct + 26] = e.altKey; + HEAP8[eventStruct + 27] = e.metaKey; + HEAP16[idx*2 + 14] = e.button; + HEAP16[idx*2 + 15] = e.buttons; + + HEAP32[idx + 8] = e["movementX"] ; - HEAP32[idx + 12] = e["movementY"] + HEAP32[idx + 9] = e["movementY"] ; + // Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway) var rect = getBoundingClientRect(target); - HEAP32[idx + 13] = e.clientX - rect.left; - HEAP32[idx + 14] = e.clientY - rect.top; + HEAP32[idx + 10] = e.clientX - (rect.left | 0); + HEAP32[idx + 11] = e.clientY - (rect.top | 0); }; var registerMouseEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { - if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc(72); + JSEvents.mouseEvent ||= _malloc(64); target = findEventTarget(target); var mouseEventHandlerFunc = (e = event) => { @@ -1654,7 +1511,7 @@ function dbg(text) { var registerUiEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { - if (!JSEvents.uiEvent) JSEvents.uiEvent = _malloc(36); + JSEvents.uiEvent ||= _malloc(36); target = findEventTarget(target); @@ -1672,15 +1529,15 @@ function dbg(text) { return; } var uiEvent = JSEvents.uiEvent; - HEAP32[((uiEvent)>>2)] = e.detail; + HEAP32[((uiEvent)>>2)] = 0; // always zero for resize and scroll HEAP32[(((uiEvent)+(4))>>2)] = b.clientWidth; HEAP32[(((uiEvent)+(8))>>2)] = b.clientHeight; HEAP32[(((uiEvent)+(12))>>2)] = innerWidth; HEAP32[(((uiEvent)+(16))>>2)] = innerHeight; HEAP32[(((uiEvent)+(20))>>2)] = outerWidth; HEAP32[(((uiEvent)+(24))>>2)] = outerHeight; - HEAP32[(((uiEvent)+(28))>>2)] = pageXOffset; - HEAP32[(((uiEvent)+(32))>>2)] = pageYOffset; + HEAP32[(((uiEvent)+(28))>>2)] = pageXOffset | 0; // scroll offsets are float + HEAP32[(((uiEvent)+(32))>>2)] = pageYOffset | 0; if (getWasmTableEntry(callbackfunc)(eventTypeId, uiEvent, userData)) e.preventDefault(); }; @@ -1698,40 +1555,36 @@ function dbg(text) { - function handleAllocatorInit() { - Object.assign(HandleAllocator.prototype, /** @lends {HandleAllocator.prototype} */ { - get(id) { - assert(this.allocated[id] !== undefined, `invalid handle: ${id}`); - return this.allocated[id]; - }, - has(id) { - return this.allocated[id] !== undefined; - }, - allocate(handle) { - var id = this.freelist.pop() || this.allocated.length; - this.allocated[id] = handle; - return id; - }, - free(id) { - assert(this.allocated[id] !== undefined); - // Set the slot to `undefined` rather than using `delete` here since - // apparently arrays with holes in them can be less efficient. - this.allocated[id] = undefined; - this.freelist.push(id); - } - }); - } - /** @constructor */ - function HandleAllocator() { - // Reserve slot 0 so that 0 is always an invalid handle - this.allocated = [undefined]; - this.freelist = []; + class HandleAllocator { + allocated = [undefined]; + freelist = []; + get(id) { + assert(this.allocated[id] !== undefined, `invalid handle: ${id}`); + return this.allocated[id]; + } + has(id) { + return this.allocated[id] !== undefined; + } + allocate(handle) { + var id = this.freelist.pop() || this.allocated.length; + this.allocated[id] = handle; + return id; + } + free(id) { + assert(this.allocated[id] !== undefined); + // Set the slot to `undefined` rather than using `delete` here since + // apparently arrays with holes in them can be less efficient. + this.allocated[id] = undefined; + this.freelist.push(id); + } } var Fetch = { openDatabase(dbname, dbversion, onsuccess, onerror) { try { var openRequest = indexedDB.open(dbname, dbversion); - } catch (e) { return onerror(e); } + } catch (e) { + return onerror(e); + } openRequest.onupgradeneeded = (event) => { var db = /** @type {IDBDatabase} */ (event.target.result); @@ -1741,7 +1594,7 @@ function dbg(text) { db.createObjectStore('FILES'); }; openRequest.onsuccess = (event) => onsuccess(event.target.result); - openRequest.onerror = (error) => onerror(error); + openRequest.onerror = onerror; }, init() { Fetch.xhrs = new HandleAllocator(); @@ -1768,9 +1621,9 @@ function dbg(text) { } var url_ = UTF8ToString(url); - var fetch_attr = fetch + 112; + var fetch_attr = fetch + 108; var requestMethod = UTF8ToString(fetch_attr + 0); - if (!requestMethod) requestMethod = 'GET'; + requestMethod ||= 'GET'; var timeoutMsecs = HEAPU32[(((fetch_attr)+(56))>>2)]; var userName = HEAPU32[(((fetch_attr)+(68))>>2)]; var password = HEAPU32[(((fetch_attr)+(72))>>2)]; @@ -1788,7 +1641,7 @@ function dbg(text) { var passwordStr = password ? UTF8ToString(password) : undefined; var xhr = new XMLHttpRequest(); - xhr.withCredentials = !!HEAPU8[(((fetch_attr)+(60))>>0)];; + xhr.withCredentials = !!HEAPU8[(fetch_attr)+(60)];; xhr.open(requestMethod, url_, !fetchAttrSynchronous, userNameStr, passwordStr); if (!fetchAttrSynchronous) xhr.timeout = timeoutMsecs; // XHR timeout field is only accessible in async XHRs, and must be set after .open() but before .send(). xhr.url_ = url_; // Save the url for debugging purposes (and for comparing to the responseURL that server side advertised) @@ -1824,7 +1677,7 @@ function dbg(text) { function saveResponseAndStatus() { var ptr = 0; var ptrLen = 0; - if (xhr.response && fetchAttrLoadToMemory && HEAPU32[fetch + 12 >> 2] === 0) { + if (xhr.response && fetchAttrLoadToMemory && HEAPU32[(((fetch)+(12))>>2)] === 0) { ptrLen = xhr.response.byteLength; } if (ptrLen > 0) { @@ -1833,7 +1686,7 @@ function dbg(text) { ptr = _malloc(ptrLen); HEAPU8.set(new Uint8Array(/** @type{Array<number>} */(xhr.response)), ptr); } - HEAPU32[fetch + 12 >> 2] = ptr; + HEAPU32[(((fetch)+(12))>>2)] = ptr writeI53ToI64(fetch + 16, ptrLen); writeI53ToI64(fetch + 24, 0); var len = xhr.response ? xhr.response.byteLength : 0; @@ -1843,8 +1696,8 @@ function dbg(text) { // the most recent XHR.onprogress handler. writeI53ToI64(fetch + 32, len); } - HEAPU16[fetch + 40 >> 1] = xhr.readyState; - HEAPU16[fetch + 42 >> 1] = xhr.status; + HEAP16[(((fetch)+(40))>>1)] = xhr.readyState + HEAP16[(((fetch)+(42))>>1)] = xhr.status if (xhr.statusText) stringToUTF8(xhr.statusText, fetch + 44, 64); } @@ -1855,9 +1708,9 @@ function dbg(text) { } saveResponseAndStatus(); if (xhr.status >= 200 && xhr.status < 300) { - if (onsuccess) onsuccess(fetch, xhr, e); + onsuccess?.(fetch, xhr, e); } else { - if (onerror) onerror(fetch, xhr, e); + onerror?.(fetch, xhr, e); } }; xhr.onerror = (e) => { @@ -1866,14 +1719,14 @@ function dbg(text) { return; } saveResponseAndStatus(); - if (onerror) onerror(fetch, xhr, e); + onerror?.(fetch, xhr, e); }; xhr.ontimeout = (e) => { // check if xhr was aborted by user and don't try to call back if (!Fetch.xhrs.has(id)) { return; } - if (onerror) onerror(fetch, xhr, e); + onerror?.(fetch, xhr, e); }; xhr.onprogress = (e) => { // check if xhr was aborted by user and don't try to call back @@ -1888,16 +1741,16 @@ function dbg(text) { ptr = _malloc(ptrLen); HEAPU8.set(new Uint8Array(/** @type{Array<number>} */(xhr.response)), ptr); } - HEAPU32[fetch + 12 >> 2] = ptr; + HEAPU32[(((fetch)+(12))>>2)] = ptr writeI53ToI64(fetch + 16, ptrLen); writeI53ToI64(fetch + 24, e.loaded - ptrLen); writeI53ToI64(fetch + 32, e.total); - HEAPU16[fetch + 40 >> 1] = xhr.readyState; + HEAP16[(((fetch)+(40))>>1)] = xhr.readyState // If loading files from a source that does not give HTTP status code, assume success if we get data bytes if (xhr.readyState >= 3 && xhr.status === 0 && e.loaded > 0) xhr.status = 200; - HEAPU16[fetch + 42 >> 1] = xhr.status; + HEAP16[(((fetch)+(42))>>1)] = xhr.status if (xhr.statusText) stringToUTF8(xhr.statusText, fetch + 44, 64); - if (onprogress) onprogress(fetch, xhr, e); + onprogress?.(fetch, xhr, e); if (ptr) { _free(ptr); } @@ -1908,16 +1761,16 @@ function dbg(text) { return; } - HEAPU16[fetch + 40 >> 1] = xhr.readyState; + HEAP16[(((fetch)+(40))>>1)] = xhr.readyState if (xhr.readyState >= 2) { - HEAPU16[fetch + 42 >> 1] = xhr.status; + HEAP16[(((fetch)+(42))>>1)] = xhr.status } - if (onreadystatechange) onreadystatechange(fetch, xhr, e); + onreadystatechange?.(fetch, xhr, e); }; try { xhr.send(data); } catch(e) { - if (onerror) onerror(fetch, xhr, e); + onerror?.(fetch, xhr, e); } } @@ -1940,29 +1793,18 @@ function dbg(text) { }; - var SYSCALLS = { - varargs:undefined, - get() { - assert(SYSCALLS.varargs != undefined); - // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. - var ret = HEAP32[((+SYSCALLS.varargs)>>2)]; - SYSCALLS.varargs += 4; - return ret; - }, - getp() { return SYSCALLS.get() }, - getStr(ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, - }; + var runtimeKeepaliveCounter = 0; + var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; var _proc_exit = (code) => { EXITSTATUS = code; if (!keepRuntimeAlive()) { - if (Module['onExit']) Module['onExit'](code); + Module['onExit']?.(code); ABORT = true; } quit_(code, new ExitStatus(code)); }; + + /** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => { @@ -1980,6 +1822,7 @@ function dbg(text) { }; var _exit = exitJS; + var maybeExit = () => { if (!keepRuntimeAlive()) { try { @@ -2025,9 +1868,9 @@ function dbg(text) { return; } - var fetch_attr = fetch + 112; - var destinationPath = HEAPU32[fetch_attr + 64 >> 2]; - if (!destinationPath) destinationPath = HEAPU32[fetch + 8 >> 2]; + var fetch_attr = fetch + 108; + var destinationPath = HEAPU32[(((fetch_attr)+(64))>>2)]; + destinationPath ||= HEAPU32[(((fetch)+(8))>>2)]; var destinationPathStr = UTF8ToString(destinationPath); try { @@ -2035,8 +1878,8 @@ function dbg(text) { var packages = transaction.objectStore('FILES'); var putRequest = packages.put(data, destinationPathStr); putRequest.onsuccess = (event) => { - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 200 // Mimic XHR HTTP status code 200 "OK" stringToUTF8("OK", fetch + 44, 64); onsuccess(fetch, 0, destinationPathStr); }; @@ -2044,8 +1887,8 @@ function dbg(text) { // Most likely we got an error if IndexedDB is unwilling to store any more data for this page. // TODO: Can we identify and break down different IndexedDB-provided errors and convert those // to more HTTP status codes for more information? - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 413; // Mimic XHR HTTP status code 413 "Payload Too Large" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 413 // Mimic XHR HTTP status code 413 "Payload Too Large" stringToUTF8("Payload Too Large", fetch + 44, 64); onerror(fetch, 0, error); }; @@ -2060,9 +1903,9 @@ function dbg(text) { return; } - var fetch_attr = fetch + 112; - var path = HEAPU32[fetch_attr + 64 >> 2]; - if (!path) path = HEAPU32[fetch + 8 >> 2]; + var fetch_attr = fetch + 108; + var path = HEAPU32[(((fetch_attr)+(64))>>2)]; + path ||= HEAPU32[(((fetch)+(8))>>2)]; var pathStr = UTF8ToString(path); try { @@ -2077,25 +1920,25 @@ function dbg(text) { // freed when emscripten_fetch_close() is called. var ptr = _malloc(len); HEAPU8.set(new Uint8Array(value), ptr); - HEAPU32[fetch + 12 >> 2] = ptr; + HEAPU32[(((fetch)+(12))>>2)] = ptr; writeI53ToI64(fetch + 16, len); writeI53ToI64(fetch + 24, 0); writeI53ToI64(fetch + 32, len); - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 200 // Mimic XHR HTTP status code 200 "OK" stringToUTF8("OK", fetch + 44, 64); onsuccess(fetch, 0, value); } else { // Succeeded to load, but the load came back with the value of undefined, treat that as an error since we never store undefined in db. - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 404 // Mimic XHR HTTP status code 404 "Not Found" stringToUTF8("Not Found", fetch + 44, 64); onerror(fetch, 0, 'no data'); } }; getRequest.onerror = (error) => { - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 404 // Mimic XHR HTTP status code 404 "Not Found" stringToUTF8("Not Found", fetch + 44, 64); onerror(fetch, 0, error); }; @@ -2110,9 +1953,10 @@ function dbg(text) { return; } - var fetch_attr = fetch + 112; - var path = HEAPU32[fetch_attr + 64 >> 2]; - if (!path) path = HEAPU32[fetch + 8 >> 2]; + var fetch_attr = fetch + 108; + var path = HEAPU32[(((fetch_attr)+(64))>>2)]; + path ||= HEAPU32[(((fetch)+(8))>>2)]; + var pathStr = UTF8ToString(path); try { @@ -2121,18 +1965,20 @@ function dbg(text) { var request = packages.delete(pathStr); request.onsuccess = (event) => { var value = event.target.result; - HEAPU32[fetch + 12 >> 2] = 0; + HEAPU32[(((fetch)+(12))>>2)] = 0; writeI53ToI64(fetch + 16, 0); writeI53ToI64(fetch + 24, 0); writeI53ToI64(fetch + 32, 0); - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" + // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(40))>>1)] = 4; + // Mimic XHR HTTP status code 200 "OK" + HEAP16[(((fetch)+(42))>>1)] = 200; stringToUTF8("OK", fetch + 44, 64); onsuccess(fetch, 0, value); }; request.onerror = (error) => { - HEAPU16[fetch + 40 >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' - HEAPU16[fetch + 42 >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" + HEAP16[(((fetch)+(40))>>1)] = 4 // Mimic XHR readyState 4 === 'DONE: The operation is complete' + HEAP16[(((fetch)+(42))>>1)] = 404 // Mimic XHR HTTP status code 404 "Not Found" stringToUTF8("Not Found", fetch + 44, 64); onerror(fetch, 0, error); }; @@ -2147,12 +1993,12 @@ function dbg(text) { // response. - var fetch_attr = fetch + 112; - var onsuccess = HEAPU32[fetch_attr + 36 >> 2]; - var onerror = HEAPU32[fetch_attr + 40 >> 2]; - var onprogress = HEAPU32[fetch_attr + 44 >> 2]; - var onreadystatechange = HEAPU32[fetch_attr + 48 >> 2]; - var fetchAttributes = HEAPU32[fetch_attr + 52 >> 2]; + var fetch_attr = fetch + 108; + var onsuccess = HEAPU32[(((fetch_attr)+(36))>>2)]; + var onerror = HEAPU32[(((fetch_attr)+(40))>>2)]; + var onprogress = HEAPU32[(((fetch_attr)+(44))>>2)]; + var onreadystatechange = HEAPU32[(((fetch_attr)+(48))>>2)]; + var fetchAttributes = HEAPU32[(((fetch_attr)+(52))>>2)]; var fetchAttrSynchronous = !!(fetchAttributes & 64); function doCallback(f) { @@ -2167,14 +2013,14 @@ function dbg(text) { doCallback(() => { if (onsuccess) getWasmTableEntry(onsuccess)(fetch); - else if (successcb) successcb(fetch); + else successcb?.(fetch); }); }; var reportProgress = (fetch, xhr, e) => { doCallback(() => { if (onprogress) getWasmTableEntry(onprogress)(fetch); - else if (progresscb) progresscb(fetch); + else progresscb?.(fetch); }); }; @@ -2182,14 +2028,14 @@ function dbg(text) { doCallback(() => { if (onerror) getWasmTableEntry(onerror)(fetch); - else if (errorcb) errorcb(fetch); + else errorcb?.(fetch); }); }; var reportReadyStateChange = (fetch, xhr, e) => { doCallback(() => { if (onreadystatechange) getWasmTableEntry(onreadystatechange)(fetch); - else if (readystatechangecb) readystatechangecb(fetch); + else readystatechangecb?.(fetch); }); }; @@ -2202,14 +2048,14 @@ function dbg(text) { doCallback(() => { if (onsuccess) getWasmTableEntry(onsuccess)(fetch); - else if (successcb) successcb(fetch); + else successcb?.(fetch); }); }; var storeError = (fetch, xhr, e) => { doCallback(() => { if (onsuccess) getWasmTableEntry(onsuccess)(fetch); - else if (successcb) successcb(fetch); + else successcb?.(fetch); }); }; fetchCacheData(Fetch.dbInstance, fetch, xhr.response, storeSuccess, storeError); @@ -2240,9 +2086,14 @@ function dbg(text) { return fetch; } + var GLctx; + var webgl_enable_ANGLE_instanced_arrays = (ctx) => { // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. var ext = ctx.getExtension('ANGLE_instanced_arrays'); + // Because this extension is a core function in WebGL 2, assign the extension entry points in place of + // where the core functions will reside in WebGL 2. This way the calling code can call these without + // having to dynamically branch depending if running against WebGL 1 or WebGL 2. if (ext) { ctx['vertexAttribDivisor'] = (index, divisor) => ext['vertexAttribDivisorANGLE'](index, divisor); ctx['drawArraysInstanced'] = (mode, first, count, primcount) => ext['drawArraysInstancedANGLE'](mode, first, count, primcount); @@ -2281,9 +2132,77 @@ function dbg(text) { return !!(ctx.mdibvbi = ctx.getExtension('WEBGL_multi_draw_instanced_base_vertex_base_instance')); }; - var webgl_enable_WEBGL_multi_draw = (ctx) => { + var webgl_enable_EXT_polygon_offset_clamp = (ctx) => + !!(ctx.extPolygonOffsetClamp = ctx.getExtension('EXT_polygon_offset_clamp')); + + var webgl_enable_EXT_clip_control = (ctx) => + !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control')); + + var webgl_enable_WEBGL_polygon_mode = (ctx) => + !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode')); + + var webgl_enable_WEBGL_multi_draw = (ctx) => // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. - return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); + !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); + + var getEmscriptenSupportedExtensions = (ctx) => { + // Restrict the list of advertised extensions to those that we actually + // support. + var supportedExtensions = [ + // WebGL 1 extensions + 'ANGLE_instanced_arrays', + 'EXT_blend_minmax', + 'EXT_disjoint_timer_query', + 'EXT_frag_depth', + 'EXT_shader_texture_lod', + 'EXT_sRGB', + 'OES_element_index_uint', + 'OES_fbo_render_mipmap', + 'OES_standard_derivatives', + 'OES_texture_float', + 'OES_texture_half_float', + 'OES_texture_half_float_linear', + 'OES_vertex_array_object', + 'WEBGL_color_buffer_float', + 'WEBGL_depth_texture', + 'WEBGL_draw_buffers', + // WebGL 2 extensions + 'EXT_color_buffer_float', + 'EXT_conservative_depth', + 'EXT_disjoint_timer_query_webgl2', + 'EXT_texture_norm16', + 'NV_shader_noperspective_interpolation', + 'WEBGL_clip_cull_distance', + // WebGL 1 and WebGL 2 extensions + 'EXT_clip_control', + 'EXT_color_buffer_half_float', + 'EXT_depth_clamp', + 'EXT_float_blend', + 'EXT_polygon_offset_clamp', + 'EXT_texture_compression_bptc', + 'EXT_texture_compression_rgtc', + 'EXT_texture_filter_anisotropic', + 'KHR_parallel_shader_compile', + 'OES_texture_float_linear', + 'WEBGL_blend_func_extended', + 'WEBGL_compressed_texture_astc', + 'WEBGL_compressed_texture_etc', + 'WEBGL_compressed_texture_etc1', + 'WEBGL_compressed_texture_s3tc', + 'WEBGL_compressed_texture_s3tc_srgb', + 'WEBGL_debug_renderer_info', + 'WEBGL_debug_shaders', + 'WEBGL_lose_context', + 'WEBGL_multi_draw', + 'WEBGL_polygon_mode' + ]; + // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. + return (ctx.getSupportedExtensions() || []).filter(ext => supportedExtensions.includes(ext)); + }; + + var registerPreMainLoop = (f) => { + // Does nothing unless $MainLoop is included/used. + typeof MainLoop != 'undefined' && MainLoop.preMainLoop.push(f); }; @@ -2312,7 +2231,8 @@ function dbg(text) { stringiCache:{ }, unpackAlignment:4, - recordError:function recordError(errorCode) { + unpackRowLength:0, + recordError:(errorCode) => { if (!GL.lastError) { GL.lastError = errorCode; } @@ -2322,13 +2242,30 @@ function dbg(text) { for (var i = table.length; i < ret; i++) { table[i] = null; } + // Skip over any non-null elements that might have been created by + // glBindBuffer. + while (table[ret]) { + ret = GL.counter++; + } return ret; }, + genObject:(n, buffers, createFunction, objectTable + ) => { + for (var i = 0; i < n; i++) { + var buffer = GLctx[createFunction](); + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + } + HEAP32[(((buffers)+(i*4))>>2)] = id; + } + }, MAX_TEMP_BUFFER_SIZE:2097152, numTempVertexBuffersPerSize:64, - log2ceilLookup:(i) => { - return 32 - Math.clz32(i === 0 ? 0 : i - 1); - }, + log2ceilLookup:(i) => 32 - Math.clz32(i === 0 ? 0 : i - 1), generateTempBuffers:(quads, context) => { var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE); context.tempVertexBufferCounters1 = []; @@ -2379,7 +2316,7 @@ function dbg(text) { context.GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, null); } }, - getTempVertexBuffer:function getTempVertexBuffer(sizeBytes) { + getTempVertexBuffer:(sizeBytes) => { var idx = GL.log2ceilLookup(sizeBytes); var ringbuffer = GL.currentContext.tempVertexBuffers1[idx]; var nextFreeBufferIndex = GL.currentContext.tempVertexBufferCounters1[idx]; @@ -2395,7 +2332,7 @@ function dbg(text) { GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, prevVBO); return ringbuffer[nextFreeBufferIndex]; }, - getTempIndexBuffer:function getTempIndexBuffer(sizeBytes) { + getTempIndexBuffer:(sizeBytes) => { var idx = GL.log2ceilLookup(sizeBytes); var ibo = GL.currentContext.tempIndexBuffers[idx]; if (ibo) { @@ -2408,7 +2345,7 @@ function dbg(text) { GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, prevIBO); return GL.currentContext.tempIndexBuffers[idx]; }, - newRenderingFrameStarted:function newRenderingFrameStarted() { + newRenderingFrameStarted:() => { if (!GL.currentContext) { return; } @@ -2426,12 +2363,12 @@ function dbg(text) { getSource:(shader, count, string, length) => { var source = ''; for (var i = 0; i < count; ++i) { - var len = length ? HEAP32[(((length)+(i*4))>>2)] : -1; - source += UTF8ToString(HEAP32[(((string)+(i*4))>>2)], len < 0 ? undefined : len); + var len = length ? HEAPU32[(((length)+(i*4))>>2)] : undefined; + source += UTF8ToString(HEAPU32[(((string)+(i*4))>>2)], len); } return source; }, - calcBufLength:function calcBufLength(size, type, stride, count) { + calcBufLength:(size, type, stride, count) => { if (stride > 0) { return count * stride; // XXXvlad this is not exactly correct I don't think } @@ -2439,10 +2376,11 @@ function dbg(text) { return size * typeSize * count; }, usedTempBuffers:[], - preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count) { + preDrawHandleClientVertexAttribBindings:(count) => { GL.resetBufferBinding = false; - // TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib + // TODO: initial pass to detect ranges we need to upload, might not need + // an upload per attrib for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) { var cb = GL.currentContext.clientBuffers[i]; if (!cb.clientside || !cb.enabled) continue; @@ -2458,18 +2396,22 @@ function dbg(text) { cb.vertexAttribPointerAdaptor.call(GLctx, i, cb.size, cb.type, cb.normalized, cb.stride, 0); } }, - postDrawHandleClientVertexAttribBindings:function postDrawHandleClientVertexAttribBindings() { + postDrawHandleClientVertexAttribBindings:() => { if (GL.resetBufferBinding) { GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, GL.buffers[GLctx.currentArrayBufferBinding]); } }, createContext:(/** @type {HTMLCanvasElement} */ canvas, webGLContextAttributes) => { - // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL context on a canvas, - // calling .getContext() will always return that context independent of which 'webgl' or 'webgl2' - // context version was passed. See https://bugs.webkit.org/show_bug.cgi?id=222758 and - // https://github.com/emscripten-core/emscripten/issues/13295. - // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari version field in above check. + // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL + // context on a canvas, calling .getContext() will always return that + // context independent of which 'webgl' or 'webgl2' + // context version was passed. See: + // https://bugs.webkit.org/show_bug.cgi?id=222758 + // and: + // https://github.com/emscripten-core/emscripten/issues/13295. + // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari + // version field in above check. if (!canvas.getContextSafariWebGL2Fixed) { canvas.getContextSafariWebGL2Fixed = canvas.getContext; /** @type {function(this:HTMLCanvasElement, string, (Object|null)=): (Object|null)} */ @@ -2506,7 +2448,8 @@ function dbg(text) { GLctx: ctx }; - // Store the created context object so that we can access the context given a canvas without having to pass the parameters again. + // Store the created context object so that we can access the context + // given a canvas without having to pass the parameters again. if (ctx.canvas) ctx.canvas.GLctxObject = context; GL.contexts[handle] = context; if (typeof webGLContextAttributes.enableExtensionsByDefault == 'undefined' || webGLContextAttributes.enableExtensionsByDefault) { @@ -2516,7 +2459,16 @@ function dbg(text) { context.maxVertexAttribs = context.GLctx.getParameter(0x8869 /*GL_MAX_VERTEX_ATTRIBS*/); context.clientBuffers = []; for (var i = 0; i < context.maxVertexAttribs; i++) { - context.clientBuffers[i] = { enabled: false, clientside: false, size: 0, type: 0, normalized: 0, stride: 0, ptr: 0, vertexAttribPointerAdaptor: null }; + context.clientBuffers[i] = { + enabled: false, + clientside: false, + size: 0, + type: 0, + normalized: 0, + stride: 0, + ptr: 0, + vertexAttribPointerAdaptor: null, + }; } GL.generateTempBuffers(false, context); @@ -2525,31 +2477,51 @@ function dbg(text) { }, makeContextCurrent:(contextHandle) => { - GL.currentContext = GL.contexts[contextHandle]; // Active Emscripten GL layer context object. - Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx; // Active WebGL context object. + // Active Emscripten GL layer context object. + GL.currentContext = GL.contexts[contextHandle]; + // Active WebGL context object. + Module['ctx'] = GLctx = GL.currentContext?.GLctx; return !(contextHandle && !GLctx); }, getContext:(contextHandle) => { return GL.contexts[contextHandle]; }, deleteContext:(contextHandle) => { - if (GL.currentContext === GL.contexts[contextHandle]) GL.currentContext = null; - if (typeof JSEvents == 'object') JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); // Release all JS event handlers on the DOM element that the GL context is associated with since the context is now deleted. - if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; // Make sure the canvas object no longer refers to the context object so there are no GC surprises. + if (GL.currentContext === GL.contexts[contextHandle]) { + GL.currentContext = null; + } + if (typeof JSEvents == 'object') { + // Release all JS event handlers on the DOM element that the GL context is + // associated with since the context is now deleted. + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + } + // Make sure the canvas object no longer refers to the context object so + // there are no GC surprises. + if (GL.contexts[contextHandle]?.GLctx.canvas) { + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; + } GL.contexts[contextHandle] = null; }, initExtensions:(context) => { - // If this function is called without a specific context object, init the extensions of the currently active context. - if (!context) context = GL.currentContext; + // If this function is called without a specific context object, init the + // extensions of the currently active context. + context ||= GL.currentContext; if (context.initExtensionsDone) return; context.initExtensionsDone = true; var GLctx = context.GLctx; - // Detect the presence of a few extensions manually, ction GL interop layer itself will need to know if they exist. + // Detect the presence of a few extensions manually, ction GL interop + // layer itself will need to know if they exist. - // Extensions that are only available in WebGL 1 (the calls will be no-ops if called on a WebGL 2 context active) + // Extensions that are available in both WebGL 1 and WebGL 2 + webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_EXT_polygon_offset_clamp(GLctx); + webgl_enable_EXT_clip_control(GLctx); + webgl_enable_WEBGL_polygon_mode(GLctx); + // Extensions that are only available in WebGL 1 (the calls will be no-ops + // if called on a WebGL 2 context active) webgl_enable_ANGLE_instanced_arrays(GLctx); webgl_enable_OES_vertex_array_object(GLctx); webgl_enable_WEBGL_draw_buffers(GLctx); @@ -2572,12 +2544,9 @@ function dbg(text) { GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); } - webgl_enable_WEBGL_multi_draw(GLctx); - - // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. - var exts = GLctx.getSupportedExtensions() || []; - exts.forEach((ext) => { - // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders are not enabled by default. + getEmscriptenSupportedExtensions(GLctx).forEach((ext) => { + // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders + // are not enabled by default. if (!ext.includes('lose_context') && !ext.includes('debug')) { // Call .getExtension() to enable that extension permanently. GLctx.getExtension(ext); @@ -2587,33 +2556,38 @@ function dbg(text) { }; - var emscripten_webgl_power_preferences = ['default', 'low-power', 'high-performance']; + var webglPowerPreferences = ["default","low-power","high-performance"]; /** @suppress {duplicate } */ var _emscripten_webgl_do_create_context = (target, attributes) => { assert(attributes); - var a = attributes >> 2; - var powerPreference = HEAP32[a + (24>>2)]; + var attr32 = ((attributes)>>2); + var powerPreference = HEAP32[attr32 + (8>>2)]; var contextAttributes = { - 'alpha': !!HEAP32[a + (0>>2)], - 'depth': !!HEAP32[a + (4>>2)], - 'stencil': !!HEAP32[a + (8>>2)], - 'antialias': !!HEAP32[a + (12>>2)], - 'premultipliedAlpha': !!HEAP32[a + (16>>2)], - 'preserveDrawingBuffer': !!HEAP32[a + (20>>2)], - 'powerPreference': emscripten_webgl_power_preferences[powerPreference], - 'failIfMajorPerformanceCaveat': !!HEAP32[a + (28>>2)], + 'alpha': !!HEAP8[attributes + 0], + 'depth': !!HEAP8[attributes + 1], + 'stencil': !!HEAP8[attributes + 2], + 'antialias': !!HEAP8[attributes + 3], + 'premultipliedAlpha': !!HEAP8[attributes + 4], + 'preserveDrawingBuffer': !!HEAP8[attributes + 5], + 'powerPreference': webglPowerPreferences[powerPreference], + 'failIfMajorPerformanceCaveat': !!HEAP8[attributes + 12], // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure. - majorVersion: HEAP32[a + (32>>2)], - minorVersion: HEAP32[a + (36>>2)], - enableExtensionsByDefault: HEAP32[a + (40>>2)], - explicitSwapControl: HEAP32[a + (44>>2)], - proxyContextToMainThread: HEAP32[a + (48>>2)], - renderViaOffscreenBackBuffer: HEAP32[a + (52>>2)] + majorVersion: HEAP32[attr32 + (16>>2)], + minorVersion: HEAP32[attr32 + (20>>2)], + enableExtensionsByDefault: HEAP8[attributes + 24], + explicitSwapControl: HEAP8[attributes + 25], + proxyContextToMainThread: HEAP32[attr32 + (28>>2)], + renderViaOffscreenBackBuffer: HEAP8[attributes + 32] }; + // TODO: Make these into hard errors at some point in the future + if (contextAttributes.majorVersion !== 1 && contextAttributes.majorVersion !== 2) { + err(`Invalid WebGL version requested: ${contextAttributes.majorVersion}`); + } + var canvas = findCanvasEventTarget(target); if (!canvas) { @@ -2629,34 +2603,24 @@ function dbg(text) { }; var _emscripten_webgl_create_context = _emscripten_webgl_do_create_context; - var _emscripten_webgl_init_context_attributes = (attributes) => { - assert(attributes); - var a = attributes >> 2; - for (var i = 0; i < (56>>2); ++i) { - HEAP32[a+i] = 0; - } - - HEAP32[a + (0>>2)] = - HEAP32[a + (4>>2)] = - HEAP32[a + (12>>2)] = - HEAP32[a + (16>>2)] = - HEAP32[a + (32>>2)] = - HEAP32[a + (40>>2)] = 1; - - }; - var _emscripten_webgl_make_context_current = (contextHandle) => { var success = GL.makeContextCurrent(contextHandle); return success ? 0 : -5; }; + var SYSCALLS = { + varargs:undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + }; var _fd_close = (fd) => { abort('fd_close called without SYSCALLS_REQUIRE_FILESYSTEM'); }; - - function _fd_seek(fd,offset_low, offset_high,whence,newOffset) { - var offset = convertI32PairToI53Checked(offset_low, offset_high);; + function _fd_seek(fd, offset, whence, newOffset) { + offset = bigintToI53Checked(offset); return 70; @@ -2669,7 +2633,7 @@ function dbg(text) { var buffer = printCharBuffers[stream]; assert(buffer); if (curr === 0 || curr === 10) { - (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0)); + (stream === 1 ? out : err)(UTF8ArrayToString(buffer)); buffer.length = 0; } else { buffer.push(curr); @@ -2705,6 +2669,14 @@ function dbg(text) { }; var _glBindBuffer = (target, buffer) => { + // Calling glBindBuffer with an unknown buffer will implicitly create a + // new one. Here we bypass `GL.counter` and directly using the ID passed + // in. + if (buffer && !GL.buffers[buffer]) { + var b = GLctx.createBuffer(); + b.name = buffer; + GL.buffers[buffer] = b; + } if (target == 0x8892 /*GL_ARRAY_BUFFER*/) { GLctx.currentArrayBufferBinding = buffer; } else if (target == 0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/) { @@ -2712,9 +2684,11 @@ function dbg(text) { } if (target == 0x88EB /*GL_PIXEL_PACK_BUFFER*/) { - // In WebGL 2 glReadPixels entry point, we need to use a different WebGL 2 API function call when a buffer is bound to - // GL_PIXEL_PACK_BUFFER_BINDING point, so must keep track whether that binding point is non-null to know what is - // the proper API function to call. + // In WebGL 2 glReadPixels entry point, we need to use a different WebGL 2 + // API function call when a buffer is bound to + // GL_PIXEL_PACK_BUFFER_BINDING point, so must keep track whether that + // binding point is non-null to know what is the proper API function to + // call. GLctx.currentPixelPackBufferBinding = buffer; } else if (target == 0x88EC /*GL_PIXEL_UNPACK_BUFFER*/) { // In WebGL 2 gl(Compressed)Tex(Sub)Image[23]D entry points, we need to @@ -2733,39 +2707,42 @@ function dbg(text) { GLctx.currentElementArrayBufferBinding = ibo ? (ibo.name | 0) : 0; }; - function _glBlendFunc(x0, x1) { GLctx.blendFunc(x0, x1) } + var _glBlendFunc = (x0, x1) => GLctx.blendFunc(x0, x1); var _glBufferData = (target, size, data, usage) => { - if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. - // If size is zero, WebGL would interpret uploading the whole input arraybuffer (starting from given offset), which would - // not make sense in WebAssembly, so avoid uploading if size is zero. However we must still call bufferData to establish a - // backing storage of zero bytes. + if (GL.currentContext.version >= 2) { + // If size is zero, WebGL would interpret uploading the whole input + // arraybuffer (starting from given offset), which would not make sense in + // WebAssembly, so avoid uploading if size is zero. However we must still + // call bufferData to establish a backing storage of zero bytes. if (data && size) { GLctx.bufferData(target, HEAPU8, usage, data, size); } else { GLctx.bufferData(target, size, usage); } - } else { - // N.b. here first form specifies a heap subarray, second form an integer size, so the ?: code here is polymorphic. It is advised to avoid - // randomly mixing both uses in calling code, to avoid any potential JS engine JIT issues. - GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); + return; } + // N.b. here first form specifies a heap subarray, second form an integer + // size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS + // engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); }; var _glBufferSubData = (target, offset, size, data) => { - if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. + if (GL.currentContext.version >= 2) { size && GLctx.bufferSubData(target, offset, HEAPU8, data, size); return; } GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); }; - function _glClear(x0) { GLctx.clear(x0) } + var _glClear = (x0) => GLctx.clear(x0); - function _glClearColor(x0, x1, x2, x3) { GLctx.clearColor(x0, x1, x2, x3) } + var _glClearColor = (x0, x1, x2, x3) => GLctx.clearColor(x0, x1, x2, x3); - function _glClearDepth(x0) { GLctx.clearDepth(x0) } + var _glClearDepth = (x0) => GLctx.clearDepth(x0); var _glCompileShader = (shader) => { GLctx.compileShader(GL.shaders[shader]); @@ -2776,7 +2753,8 @@ function dbg(text) { var program = GLctx.createProgram(); // Store additional information needed for each shader program: program.name = id; - // Lazy cache results of glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + // Lazy cache results of + // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0; program.uniformIdCounter = 1; GL.programs[id] = program; @@ -2813,7 +2791,9 @@ function dbg(text) { var _glDeleteProgram = (id) => { if (!id) return; var program = GL.programs[id]; - if (!program) { // glDeleteProgram actually signals an error when deleting a nonexisting object, unlike some other GL delete functions. + if (!program) { + // glDeleteProgram actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. GL.recordError(0x501 /* GL_INVALID_VALUE */); return; } @@ -2825,7 +2805,9 @@ function dbg(text) { var _glDeleteShader = (id) => { if (!id) return; var shader = GL.shaders[id]; - if (!shader) { // glDeleteShader actually signals an error when deleting a nonexisting object, unlike some other GL delete functions. + if (!shader) { + // glDeleteShader actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. GL.recordError(0x501 /* GL_INVALID_VALUE */); return; } @@ -2841,7 +2823,7 @@ function dbg(text) { } }; - function _glDepthFunc(x0) { GLctx.depthFunc(x0) } + var _glDepthFunc = (x0) => GLctx.depthFunc(x0); var _glDepthMask = (flag) => { GLctx.depthMask(!!flag); @@ -2858,19 +2840,42 @@ function dbg(text) { var _glDrawElements = (mode, count, type, indices) => { var buf; + var vertexes = 0; if (!GLctx.currentElementArrayBufferBinding) { var size = GL.calcBufLength(1, type, 0, count); buf = GL.getTempIndexBuffer(size); GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, buf); GLctx.bufferSubData(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, - 0, - HEAPU8.subarray(indices, indices + size)); + 0, + HEAPU8.subarray(indices, indices + size)); + + // Calculating vertex count if shader's attribute data is on client side + if (count > 0) { + for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) { + var cb = GL.currentContext.clientBuffers[i]; + if (cb.clientside && cb.enabled) { + let arrayClass; + switch(type) { + case 0x1401 /* GL_UNSIGNED_BYTE */: arrayClass = Uint8Array; break; + case 0x1403 /* GL_UNSIGNED_SHORT */: arrayClass = Uint16Array; break; + case 0x1405 /* GL_UNSIGNED_INT */: arrayClass = Uint32Array; break; + default: + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + return; + } + + vertexes = new arrayClass(HEAPU8.buffer, indices, count).reduce((max, current) => Math.max(max, current)) + 1; + break; + } + } + } + // the index is now 0 indices = 0; } // bind any client-side buffers - GL.preDrawHandleClientVertexAttribBindings(count); + GL.preDrawHandleClientVertexAttribBindings(vertexes); GLctx.drawElements(mode, count, type, indices); @@ -2881,7 +2886,7 @@ function dbg(text) { } }; - function _glEnable(x0) { GLctx.enable(x0) } + var _glEnable = (x0) => GLctx.enable(x0); var _glEnableVertexAttribArray = (index) => { var cb = GL.currentContext.clientBuffers[index]; @@ -2889,36 +2894,19 @@ function dbg(text) { GLctx.enableVertexAttribArray(index); }; - var __glGenObject = (n, buffers, createFunction, objectTable - ) => { - for (var i = 0; i < n; i++) { - var buffer = GLctx[createFunction](); - var id = buffer && GL.getNewId(objectTable); - if (buffer) { - buffer.name = id; - objectTable[id] = buffer; - } else { - GL.recordError(0x502 /* GL_INVALID_OPERATION */); - } - HEAP32[(((buffers)+(i*4))>>2)] = id; - } - }; - var _glGenBuffers = (n, buffers) => { - __glGenObject(n, buffers, 'createBuffer', GL.buffers + GL.genObject(n, buffers, 'createBuffer', GL.buffers ); }; - - function _glGenVertexArrays(n, arrays) { - __glGenObject(n, arrays, 'createVertexArray', GL.vaos + var _glGenVertexArrays = (n, arrays) => { + GL.genObject(n, arrays, 'createVertexArray', GL.vaos ); - } + }; - var _glGetAttribLocation = (program, name) => { - return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); - }; + var _glGetAttribLocation = (program, name) => + GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); var _glGetProgramInfoLog = (program, maxLength, length, infoLog) => { var log = GLctx.getProgramInfoLog(GL.programs[program]); @@ -2929,8 +2917,9 @@ function dbg(text) { var _glGetProgramiv = (program, pname, p) => { if (!p) { - // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense - // if p == null, issue a GL error to notify user about it. + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. GL.recordError(0x501 /* GL_INVALID_VALUE */); return; } @@ -2948,21 +2937,24 @@ function dbg(text) { HEAP32[((p)>>2)] = log.length + 1; } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { if (!program.maxUniformLength) { - for (var i = 0; i < GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); ++i) { + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (var i = 0; i < numActiveUniforms; ++i) { program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i).name.length+1); } } HEAP32[((p)>>2)] = program.maxUniformLength; } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { if (!program.maxAttributeLength) { - for (var i = 0; i < GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/); ++i) { + var numActiveAttributes = GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/); + for (var i = 0; i < numActiveAttributes; ++i) { program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i).name.length+1); } } HEAP32[((p)>>2)] = program.maxAttributeLength; } else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) { if (!program.maxUniformBlockNameLength) { - for (var i = 0; i < GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); ++i) { + var numActiveUniformBlocks = GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); + for (var i = 0; i < numActiveUniformBlocks; ++i) { program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1); } } @@ -2982,8 +2974,9 @@ function dbg(text) { var _glGetShaderiv = (shader, pname, p) => { if (!p) { - // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense - // if p == null, issue a GL error to notify user about it. + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. GL.recordError(0x501 /* GL_INVALID_VALUE */); return; } @@ -3011,9 +3004,7 @@ function dbg(text) { var jstoi_q = (str) => parseInt(str); /** @noinline */ - var webglGetLeftBracePos = (name) => { - return name.slice(-1) == ']' && name.lastIndexOf('['); - }; + var webglGetLeftBracePos = (name) => name.slice(-1) == ']' && name.lastIndexOf('['); var webglPrepareUniformLocationsBeforeFirstUse = (program) => { var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation @@ -3028,7 +3019,8 @@ function dbg(text) { // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations program.uniformArrayNamesById = {}; - for (i = 0; i < GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); ++i) { + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (i = 0; i < numActiveUniforms; ++i) { var u = GLctx.getActiveUniform(program, i); var nm = u.name; var sz = u.size; @@ -3067,11 +3059,14 @@ function dbg(text) { var arrayIndex = 0; var uniformBaseName = name; - // Invariant: when populating integer IDs for uniform locations, we must maintain the precondition that - // arrays reside in contiguous addresses, i.e. for a 'vec4 colors[10];', colors[4] must be at location colors[0]+4. - // However, user might call glGetUniformLocation(program, "colors") for an array, so we cannot discover based on the user - // input arguments whether the uniform we are dealing with is an array. The only way to discover which uniforms are arrays - // is to enumerate over all the active uniforms in the program. + // Invariant: when populating integer IDs for uniform locations, we must + // maintain the precondition that arrays reside in contiguous addresses, + // i.e. for a 'vec4 colors[10];', colors[4] must be at location + // colors[0]+4. However, user might call glGetUniformLocation(program, + // "colors") for an array, so we cannot discover based on the user input + // arguments whether the uniform we are dealing with is an array. The only + // way to discover which uniforms are arrays is to enumerate over all the + // active uniforms in the program. var leftBrace = webglGetLeftBracePos(name); // If user passed an array accessor "[index]", parse the array index off the accessor. @@ -3081,10 +3076,12 @@ function dbg(text) { } // Have we cached the location of this uniform before? - var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; // A pair [array length, GLint of the uniform location] + // A pair [array length, GLint of the uniform location] + var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; - // If an uniform with this name exists, and if its index is within the array limits (if it's even an array), - // query the WebGLlocation, or return an existing cached location. + // If an uniform with this name exists, and if its index is within the + // array limits (if it's even an array), query the WebGLlocation, or + // return an existing cached location. if (sizeAndId && arrayIndex < sizeAndId[0]) { arrayIndex += sizeAndId[1]; // Add the base location of the uniform to the array index offset. if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) { @@ -3093,8 +3090,9 @@ function dbg(text) { } } else { - // N.b. we are currently unable to distinguish between GL program IDs that never existed vs GL program IDs that have been deleted, - // so report GL_INVALID_VALUE in both cases. + // N.b. we are currently unable to distinguish between GL program IDs that + // never existed vs GL program IDs that have been deleted, so report + // GL_INVALID_VALUE in both cases. GL.recordError(0x501 /* GL_INVALID_VALUE */); } return -1; @@ -3120,12 +3118,12 @@ function dbg(text) { if (p) { var webglLoc = p.uniformLocsById[location]; - // p.uniformLocsById[location] stores either an integer, or a WebGLUniformLocation. - - // If an integer, we have not yet bound the location, so do it now. The integer value specifies the array index - // we should bind to. + // p.uniformLocsById[location] stores either an integer, or a + // WebGLUniformLocation. + // If an integer, we have not yet bound the location, so do it now. The + // integer value specifies the array index we should bind to. if (typeof webglLoc == 'number') { - p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? '[' + webglLoc + ']' : '')); + p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? `[${webglLoc}]` : '')); } // Else an already cached WebGLUniformLocation, return it. return webglLoc; @@ -3138,18 +3136,19 @@ function dbg(text) { var _glUniformMatrix4fv = (location, count, transpose, value) => { - if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. - count && GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16); + if (GL.currentContext.version >= 2) { + count && GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, ((value)>>2), count*16); return; } if (count <= 18) { // avoid allocation when uploading few enough uniforms - var view = miniTempWebGLFloatBuffers[16*count-1]; + var view = miniTempWebGLFloatBuffers[16*count]; // hoist the heap out of the loop for size and for pthreads+growth. var heap = HEAPF32; - value >>= 2; - for (var i = 0; i < 16 * count; i += 16) { + value = ((value)>>2); + count *= 16; + for (var i = 0; i < count; i += 16) { var dst = value + i; view[i] = heap[dst]; view[i + 1] = heap[dst + 1]; @@ -3170,7 +3169,7 @@ function dbg(text) { } } else { - var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2); + var view = HEAPF32.subarray((((value)>>2)), ((value+count*64)>>2)); } GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view); }; @@ -3207,34 +3206,35 @@ function dbg(text) { Fetch.init();; -handleAllocatorInit(); -var GLctx;; + + // Signal GL rendering layer that processing of a new frame is about to + // start. This helps it optimize VBO double-buffering and reduce GPU stalls. + registerPreMainLoop(() => GL.newRenderingFrameStarted()); + ; var miniTempWebGLFloatBuffersStorage = new Float32Array(288); - for (/**@suppress{duplicate}*/var i = 0; i < 288; ++i) { - miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i+1); - } - ; + // Create GL_POOL_TEMP_BUFFERS_SIZE+1 temporary buffers, for uploads of size 0 through GL_POOL_TEMP_BUFFERS_SIZE inclusive + for (/**@suppress{duplicate}*/var i = 0; i <= 288; ++i) { + miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i); + }; function checkIncomingModuleAPI() { ignoredModuleProp('fetchSettings'); } var wasmImports = { /** @export */ - _emscripten_fetch_free: __emscripten_fetch_free, + _abort_js: __abort_js, /** @export */ _localtime_js: __localtime_js, /** @export */ _tzset_js: __tzset_js, /** @export */ - abort: _abort, - /** @export */ emscripten_date_now: _emscripten_date_now, /** @export */ + emscripten_fetch_free: _emscripten_fetch_free, + /** @export */ emscripten_get_element_css_size: _emscripten_get_element_css_size, /** @export */ emscripten_is_main_browser_thread: _emscripten_is_main_browser_thread, /** @export */ - emscripten_memcpy_js: _emscripten_memcpy_js, - /** @export */ emscripten_request_animation_frame_loop: _emscripten_request_animation_frame_loop, /** @export */ emscripten_resize_heap: _emscripten_resize_heap, @@ -3249,8 +3249,6 @@ var wasmImports = { /** @export */ emscripten_webgl_create_context: _emscripten_webgl_create_context, /** @export */ - emscripten_webgl_init_context_attributes: _emscripten_webgl_init_context_attributes, - /** @export */ emscripten_webgl_make_context_current: _emscripten_webgl_make_context_current, /** @export */ fd_close: _fd_close, @@ -3331,23 +3329,21 @@ var wasmImports = { /** @export */ glVertexAttribPointer: _glVertexAttribPointer }; -var wasmExports = createWasm(); -var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors'); -var _malloc = createExportWrapper('malloc'); -var _free = createExportWrapper('free'); -var _main = Module['_main'] = createExportWrapper('main'); -var ___errno_location = createExportWrapper('__errno_location'); -var _fflush = Module['_fflush'] = createExportWrapper('fflush'); -var setTempRet0 = createExportWrapper('setTempRet0'); +var wasmExports; +createWasm(); +var ___wasm_call_ctors = createExportWrapper('__wasm_call_ctors', 0); +var _free = createExportWrapper('free', 1); +var _malloc = createExportWrapper('malloc', 1); +var _main = Module['_main'] = createExportWrapper('main', 2); +var _fflush = createExportWrapper('fflush', 1); +var _strerror = createExportWrapper('strerror', 1); var _emscripten_stack_init = () => (_emscripten_stack_init = wasmExports['emscripten_stack_init'])(); var _emscripten_stack_get_free = () => (_emscripten_stack_get_free = wasmExports['emscripten_stack_get_free'])(); var _emscripten_stack_get_base = () => (_emscripten_stack_get_base = wasmExports['emscripten_stack_get_base'])(); var _emscripten_stack_get_end = () => (_emscripten_stack_get_end = wasmExports['emscripten_stack_get_end'])(); -var stackSave = createExportWrapper('stackSave'); -var stackRestore = createExportWrapper('stackRestore'); -var stackAlloc = createExportWrapper('stackAlloc'); +var __emscripten_stack_restore = (a0) => (__emscripten_stack_restore = wasmExports['_emscripten_stack_restore'])(a0); +var __emscripten_stack_alloc = (a0) => (__emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc'])(a0); var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports['emscripten_stack_get_current'])(); -var dynCall_jiji = Module['dynCall_jiji'] = createExportWrapper('dynCall_jiji'); // include: postamble.js @@ -3359,39 +3355,35 @@ var missingLibrarySymbols = [ 'writeI53ToU64Clamped', 'writeI53ToU64Signaling', 'convertI32PairToI53', + 'convertI32PairToI53Checked', 'convertU32PairToI53', + 'stackAlloc', + 'getTempRet0', + 'setTempRet0', 'zeroMemory', - 'arraySum', - 'addDays', - 'setErrNo', + 'strError', 'inetPton4', 'inetNtop4', 'inetPton6', 'inetNtop6', 'readSockaddr', 'writeSockaddr', - 'getHostByName', - 'initRandomFill', - 'randomFill', - 'getCallstack', 'emscriptenLog', - 'convertPCtoSourceLocation', 'readEmAsmArgs', - 'jstoi_s', 'getExecutableName', 'listenOnce', 'autoResumeAudioContext', - 'dynCallLegacy', 'getDynCaller', 'dynCall', 'runtimeKeepalivePush', 'runtimeKeepalivePop', - 'safeSetTimeout', 'asmjsMangle', 'asyncLoad', - 'alignMemory', 'mmapAlloc', 'getNativeTypeSize', + 'addOnInit', + 'addOnPostCtor', + 'addOnPreMain', 'STACK_SIZE', 'STACK_ALIGN', 'POINTER_SIZE', @@ -3423,6 +3415,7 @@ var missingLibrarySymbols = [ 'UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32', + 'stringToNewUTF8', 'stringToUTF8OnStack', 'writeArrayToMemory', 'registerKeyEventCallback', @@ -3460,37 +3453,41 @@ var missingLibrarySymbols = [ 'registerBatteryEventCallback', 'setCanvasElementSize', 'getCanvasElementSize', - 'demangle', - 'demangleAll', 'jsStackTrace', - 'stackTrace', + 'getCallstack', + 'convertPCtoSourceLocation', 'getEnvStrings', 'checkWasiClock', 'wasiRightsToMuslOFlags', 'wasiOFlagsToMuslOFlags', - 'createDyncallWrapper', + 'initRandomFill', + 'randomFill', + 'safeSetTimeout', 'setImmediateWrapped', + 'safeRequestAnimationFrame', 'clearImmediateWrapped', - 'polyfillSetImmediate', + 'registerPostMainLoop', 'getPromise', 'makePromise', 'idsToPromises', 'makePromiseCallback', 'ExceptionInfo', 'findMatchingCatch', - 'setMainLoop', + 'Browser_asyncPrepareDataCounter', + 'arraySum', + 'addDays', 'getSocketFromFD', 'getSocketAddress', 'FS_createPreloadedFile', 'FS_modeStringToFlags', 'FS_getMode', 'FS_stdin_getChar', - 'FS_createDataFile', 'FS_unlink', + 'FS_createDataFile', 'FS_mkdirTree', '_setNetworkCallback', 'heapObjectForWebGLType', - 'heapAccessShiftForWebGLHeap', + 'toTypedArrayIndex', 'emscriptenWebGLGet', 'computeUnpackAlignedImageSize', 'colorChannelsInGlTextureFormat', @@ -3503,78 +3500,63 @@ var missingLibrarySymbols = [ 'writeGLArray', 'registerWebGlEventCallback', 'runAndAbortIfError', - 'SDL_unicode', - 'SDL_ttfContext', - 'SDL_audio', 'emscriptenWebGLGetIndexed', 'ALLOC_NORMAL', 'ALLOC_STACK', 'allocate', 'writeStringToMemory', 'writeAsciiToMemory', + 'setErrNo', + 'demangle', + 'stackTrace', ]; missingLibrarySymbols.forEach(missingLibrarySymbol) var unexportedSymbols = [ 'run', - 'addOnPreRun', - 'addOnInit', - 'addOnPreMain', - 'addOnExit', - 'addOnPostRun', 'addRunDependency', 'removeRunDependency', - 'FS_createFolder', - 'FS_createPath', - 'FS_createLazyFile', - 'FS_createLink', - 'FS_createDevice', - 'FS_readFile', 'out', 'err', 'callMain', 'abort', - 'keepRuntimeAlive', 'wasmMemory', 'wasmExports', - 'stackAlloc', - 'stackSave', - 'stackRestore', - 'getTempRet0', - 'setTempRet0', 'writeStackCookie', 'checkStackCookie', 'writeI53ToI64', 'readI53FromI64', 'readI53FromU64', - 'convertI32PairToI53Checked', + 'INT53_MAX', + 'INT53_MIN', + 'bigintToI53Checked', + 'stackSave', + 'stackRestore', 'ptrToString', 'exitJS', 'getHeapMax', 'growMemory', 'ENV', - 'MONTH_DAYS_REGULAR', - 'MONTH_DAYS_LEAP', - 'MONTH_DAYS_REGULAR_CUMULATIVE', - 'MONTH_DAYS_LEAP_CUMULATIVE', - 'isLeapYear', - 'ydayFromDate', 'ERRNO_CODES', - 'ERRNO_MESSAGES', 'DNS', 'Protocols', 'Sockets', 'timers', 'warnOnce', - 'UNWIND_CACHE', 'readEmAsmArgsArray', 'jstoi_q', + 'jstoi_s', 'handleException', + 'keepRuntimeAlive', 'callUserCallback', 'maybeExit', - 'handleAllocatorInit', + 'alignMemory', 'HandleAllocator', 'wasmTable', + 'noExitRuntime', + 'addOnPreRun', + 'addOnExit', + 'addOnPostRun', 'freeTableIndexes', 'functionsInTableMap', 'setValue', @@ -3588,7 +3570,6 @@ var unexportedSymbols = [ 'stringToUTF8', 'lengthBytesUTF8', 'UTF16Decoder', - 'stringToNewUTF8', 'JSEvents', 'specialHTMLTargets', 'maybeCStringToJsString', @@ -3600,18 +3581,34 @@ var unexportedSymbols = [ 'registerUiEventCallback', 'currentFullscreenStrategy', 'restoreOldWindowedStyle', + 'UNWIND_CACHE', 'ExitStatus', 'flush_NO_FILESYSTEM', + 'emSetImmediate', + 'emClearImmediate_deps', + 'emClearImmediate', + 'registerPreMainLoop', 'promiseMap', 'uncaughtExceptionCount', 'exceptionLast', 'exceptionCaught', 'Browser', + 'getPreloadedImageData__data', 'wget', + 'MONTH_DAYS_REGULAR', + 'MONTH_DAYS_LEAP', + 'MONTH_DAYS_REGULAR_CUMULATIVE', + 'MONTH_DAYS_LEAP_CUMULATIVE', + 'isLeapYear', + 'ydayFromDate', 'SYSCALLS', 'preloadPlugins', 'FS_stdin_getChar_buffer', + 'FS_createPath', + 'FS_createDevice', + 'FS_readFile', 'FS', + 'FS_createLazyFile', 'MEMFS', 'TTY', 'PIPEFS', @@ -3623,12 +3620,13 @@ var unexportedSymbols = [ 'webgl_enable_OES_vertex_array_object', 'webgl_enable_WEBGL_draw_buffers', 'webgl_enable_WEBGL_multi_draw', + 'webgl_enable_EXT_polygon_offset_clamp', + 'webgl_enable_EXT_clip_control', + 'webgl_enable_WEBGL_polygon_mode', 'GL', - '__glGenObject', 'webglGetUniformLocation', 'webglPrepareUniformLocationsBeforeFirstUse', 'webglGetLeftBracePos', - 'emscripten_webgl_power_preferences', 'AL', 'GLUT', 'EGL', @@ -3640,6 +3638,8 @@ var unexportedSymbols = [ 'webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance', 'allocateUTF8', 'allocateUTF8OnStack', + 'print', + 'printErr', 'Fetch', 'fetchDeleteCachedData', 'fetchLoadCachedData', @@ -3652,15 +3652,9 @@ unexportedSymbols.forEach(unexportedRuntimeSymbol); var calledRun; -dependenciesFulfilled = function runCaller() { - // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false) - if (!calledRun) run(); - if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled -}; - function callMain() { assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on Module["onRuntimeInitialized"])'); - assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called'); + assert(typeof onPreRuns === 'undefined' || onPreRuns.length == 0, 'cannot call main when preRun functions remain to be called'); var entryFunction = _main; @@ -3674,8 +3668,7 @@ function callMain() { // if we're not running an evented main loop, it's time to exit exitJS(ret, /* implicit = */ true); return ret; - } - catch (e) { + } catch (e) { return handleException(e); } } @@ -3692,22 +3685,24 @@ function stackCheckInit() { function run() { if (runDependencies > 0) { + dependenciesFulfilled = run; return; } - stackCheckInit(); + stackCheckInit(); preRun(); // a preRun added a dependency, run will be called later if (runDependencies > 0) { + dependenciesFulfilled = run; return; } function doRun() { // run may have just been called through dependencies being fulfilled just in this very frame, // or while the async setStatus time below was happening - if (calledRun) return; + assert(!calledRun); calledRun = true; Module['calledRun'] = true; @@ -3717,19 +3712,18 @@ function run() { preMain(); - if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized'](); + Module['onRuntimeInitialized']?.(); - if (shouldRunNow) callMain(); + var noInitialRun = Module['noInitialRun'];legacyModuleProp('noInitialRun', 'noInitialRun'); + if (!noInitialRun) callMain(); postRun(); } if (Module['setStatus']) { Module['setStatus']('Running...'); - setTimeout(function() { - setTimeout(function() { - Module['setStatus'](''); - }, 1); + setTimeout(() => { + setTimeout(() => Module['setStatus'](''), 1); doRun(); }, 1); } else @@ -3775,12 +3769,7 @@ if (Module['preInit']) { } } -// shouldRunNow refers to calling main(), not run(). -var shouldRunNow = true; - -if (Module['noInitialRun']) shouldRunNow = false; - run(); - // end include: postamble.js + diff --git a/themes/dist/output.wasm b/themes/dist/output.wasm Binary files differindex 925d783..9754410 100755 --- a/themes/dist/output.wasm +++ b/themes/dist/output.wasm diff --git a/themes/src/MainLoop.h b/themes/src/MainLoop.h index 2573bb8..07520a2 100644 --- a/themes/src/MainLoop.h +++ b/themes/src/MainLoop.h @@ -26,4 +26,4 @@ struct MainLoop { void stop() { isRunning = false; } -};
\ No newline at end of file +}; diff --git a/themes/src/main.cpp b/themes/src/main.cpp index 14227c9..d9cfc01 100644 --- a/themes/src/main.cpp +++ b/themes/src/main.cpp @@ -67,14 +67,19 @@ void load(ThemeType theme) { } void update(f32 dtSeconds, void* userData) { + if (!active_theme) + return; active_theme->update(dtSeconds); active_theme->render(); } void unload() { delete active_theme; + active_theme = nullptr; type = ThemeType::Default; + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if (mainLoop.isRunning) { mainLoop.stop(); } @@ -84,7 +89,7 @@ void unload() { EM_BOOL selectNone(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { printf("Default theme selected\n"); unload(); - return true; + return true; } EM_BOOL selectAutumn(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { |