summaryrefslogtreecommitdiff
path: root/2d
diff options
context:
space:
mode:
authorMatthew Kosarek <mattkae@protonmail.com>2021-11-14 14:38:06 -0500
committerMatthew Kosarek <mattkae@protonmail.com>2021-11-14 14:38:06 -0500
commitfd3c1e74e7ebe9125b98dba311efcbe73e89859e (patch)
tree0adb39252bb0e86a45a456971b5253edd7237014 /2d
parent5c613a10364f30bd6add25f7950433f0c482c3ca (diff)
(mkosarek) Working on undamped and damped
Diffstat (limited to '2d')
-rw-r--r--2d/_collisions/polygon_polygon.html2
-rw-r--r--2d/_collisions/rectangle_rectangle.html2
-rw-r--r--2d/rigidbody/rigidbody_1.html2
-rw-r--r--2d/rigidbody/rigidbody_2.html2
-rw-r--r--2d/rigidbody/rigidbody_3.html2
-rw-r--r--2d/softbody/softbody_1.html103
-rw-r--r--2d/softbody/softbody_1.html.content92
-rwxr-xr-x2d/softbody/softbody_1/build.sh2
-rw-r--r--2d/softbody/softbody_1/damped.cpp255
-rw-r--r--2d/softbody/softbody_1/damped.h8
-rw-r--r--2d/softbody/softbody_1/dist/output.js944
-rwxr-xr-x2d/softbody/softbody_1/dist/output.wasmbin44089 -> 55671 bytes
-rw-r--r--2d/softbody/softbody_1/main.cpp219
-rw-r--r--2d/softbody/softbody_1/undamped.cpp227
-rw-r--r--2d/softbody/softbody_1/undamped.h8
15 files changed, 1116 insertions, 752 deletions
diff --git a/2d/_collisions/polygon_polygon.html b/2d/_collisions/polygon_polygon.html
index 75dbcfd..d384bc7 100644
--- a/2d/_collisions/polygon_polygon.html
+++ b/2d/_collisions/polygon_polygon.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
diff --git a/2d/_collisions/rectangle_rectangle.html b/2d/_collisions/rectangle_rectangle.html
index 75c2e62..11376b7 100644
--- a/2d/_collisions/rectangle_rectangle.html
+++ b/2d/_collisions/rectangle_rectangle.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_1.html b/2d/rigidbody/rigidbody_1.html
index 153e443..239bf52 100644
--- a/2d/rigidbody/rigidbody_1.html
+++ b/2d/rigidbody/rigidbody_1.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_2.html b/2d/rigidbody/rigidbody_2.html
index f24666c..64429b5 100644
--- a/2d/rigidbody/rigidbody_2.html
+++ b/2d/rigidbody/rigidbody_2.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_3.html b/2d/rigidbody/rigidbody_3.html
index ed07bbb..f35a151 100644
--- a/2d/rigidbody/rigidbody_3.html
+++ b/2d/rigidbody/rigidbody_3.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
diff --git a/2d/softbody/softbody_1.html b/2d/softbody/softbody_1.html
index b505f1b..f103545 100644
--- a/2d/softbody/softbody_1.html
+++ b/2d/softbody/softbody_1.html
@@ -27,7 +27,7 @@
<li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
<li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Separating Axis Theorem</a></li>
<li><label>Softbody</label></li>
- <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Softbody</a></li>
+ <li><a title="/2d/softbody/softbody_1.html" href="/2d/softbody/softbody_1.html">Springs</a></li>
</ul>
</li>
<li>
@@ -54,40 +54,111 @@
<script src="./softbody_1/dist/output.js"></script>
<script>
window.onload = function() {
- var lPlayElement = document.getElementById('gl_canvas_play'),
- lStopElement = document.getElementById('gl_canvas_stop');
- lPlayElement.addEventListener('click', function() {
- lPlayElement.style.display = 'none';
- lStopElement.style.display = 'block';
- });
- lStopElement.addEventListener('click', function() {
- lStopElement.style.display = 'none';
- lPlayElement.style.display = 'block';
- });
+ function addButtonListener(pPlay, pStop, pDisableElementList) {
+ var lPlayElement = document.getElementById(pPlay),
+ lStopElement = document.getElementById(pStop);
+ lPlayElement.addEventListener('click', function() {
+ lPlayElement.style.display = 'none';
+ lStopElement.style.display = 'block';
+
+ pDisableElementList.forEach(function(element) {
+ element.disabled = true;
+ });
+ });
+ lStopElement.addEventListener('click', function() {
+ lStopElement.style.display = 'none';
+ lPlayElement.style.display = 'block';
+
+ pDisableElementList.forEach(function(element) {
+ element.disabled = false;
+ });
+ });
+ }
+
+ addButtonListener('gl_canvas_play_undamped', 'gl_canvas_stop_undamped', [
+ document.getElementById('undamped_spring_length'),
+ document.getElementById('undamped_start_position')
+ ]);
+ addButtonListener('gl_canvas_play_damped', 'gl_canvas_stop_damped', [
+
+ ]);
}
</script>
<article>
- <h1>Softbody</h1>
+ <h1>Springs</h1>
+ <section>
+ <p>
+ It is time to investigate what it means to have a deformation in our physics system. By deformation, I mean that the
+ vertices of our shapes are no longer fixed to one point within the model. We will begin with what I believe
+ by investigating the most common of all deformations: a weight attached to a spring in two dimensions.
+ </p>
+ </section>
<section>
<h2></h2>
</section>
<section>
<h2>
- Live Example
+ Undamped Springs
+ </h2>
+ <p>
+ <span class='widget_container'>
+ <label for='undamped_spring_length'>Spring Length (m)</label>
+ <input type='range' id='undamped_spring_length'/>
+ </span>
+
+ <span class='widget_container'>
+ <label for='undamped_start_position'>Start Displacement (m)</label>
+ <input type='range' id='undamped_start_position'/>
+ </span>
+
+ </p>
+ <div class="opengl_canvas_container">
+ <canvas id="gl_canvas_undamped" width="800" height="600"></canvas>
+ <button id="gl_canvas_play_undamped" class="play_button">
+ Play
+ </button>
+ <button id="gl_canvas_stop_undamped" class="stop_button">
+ Stop
+ </button>
+ </div>
+ </section>
+
+ <section>
+ <h2>
+ Damped Springs
</h2>
<p>
+
</p>
<div class="opengl_canvas_container">
- <canvas id="gl_canvas" width="800" height="600"></canvas>
- <button id="gl_canvas_play" class="play_button">
+ <canvas id="gl_canvas_damped" width="800" height="600"></canvas>
+ <button id="gl_canvas_play_damped" class="play_button">
Play
</button>
- <button id="gl_canvas_stop" class="stop_button">
+ <button id="gl_canvas_stop_damped" class="stop_button">
Stop
</button>
</div>
</section>
+
+ <footer id='references'>
+ <h2>References</h2>
+ <ul>
+ <li>
+ <a href='https://www.youtube.com/watch?v=Z52emur7Rko'>Wonderful Undamped Resource</a>
+ </li>
+ <li>
+ <a href='https://www.youtube.com/watch?v=CTd1uVq5-l8'>Wonderful Damped Resource</a>
+ </li>
+ <li>
+ <a href='http://ambrsoft.com/CalcPhysics/Spring/SpringData.htm'>List of Equations for Spring Motion</a>
+ </li>
+ <li>
+ <a href='https://www.ryanjuckett.com/damped-springs/'>Ryan Juckett's Explanation of Damped Springs</a>
+ </li>
+ </ul>
+ </footer>
</article>
</main>
</body>
diff --git a/2d/softbody/softbody_1.html.content b/2d/softbody/softbody_1.html.content
index 92be361..9e48383 100644
--- a/2d/softbody/softbody_1.html.content
+++ b/2d/softbody/softbody_1.html.content
@@ -1,16 +1,34 @@
<script src="./softbody_1/dist/output.js"></script>
<script>
window.onload = function() {
- var lPlayElement = document.getElementById('gl_canvas_play'),
- lStopElement = document.getElementById('gl_canvas_stop');
- lPlayElement.addEventListener('click', function() {
- lPlayElement.style.display = 'none';
- lStopElement.style.display = 'block';
- });
- lStopElement.addEventListener('click', function() {
- lStopElement.style.display = 'none';
- lPlayElement.style.display = 'block';
- });
+ function addButtonListener(pPlay, pStop, pDisableElementList) {
+ var lPlayElement = document.getElementById(pPlay),
+ lStopElement = document.getElementById(pStop);
+ lPlayElement.addEventListener('click', function() {
+ lPlayElement.style.display = 'none';
+ lStopElement.style.display = 'block';
+
+ pDisableElementList.forEach(function(element) {
+ element.disabled = true;
+ });
+ });
+ lStopElement.addEventListener('click', function() {
+ lStopElement.style.display = 'none';
+ lPlayElement.style.display = 'block';
+
+ pDisableElementList.forEach(function(element) {
+ element.disabled = false;
+ });
+ });
+ }
+
+ addButtonListener('gl_canvas_play_undamped', 'gl_canvas_stop_undamped', [
+ document.getElementById('undamped_spring_length'),
+ document.getElementById('undamped_start_position')
+ ]);
+ addButtonListener('gl_canvas_play_damped', 'gl_canvas_stop_damped', [
+
+ ]);
}
</script>
@@ -28,18 +46,64 @@
</section>
<section>
<h2>
- Live Example
+ Undamped Springs
</h2>
<p>
+ <span class='widget_container'>
+ <label for='undamped_spring_length'>Spring Length (m)</label>
+ <input type='range' id='undamped_spring_length'/>
+ </span>
+
+ <span class='widget_container'>
+ <label for='undamped_start_position'>Start Displacement (m)</label>
+ <input type='range' id='undamped_start_position'/>
+ </span>
+
</p>
<div class="opengl_canvas_container">
- <canvas id="gl_canvas" width="800" height="600"></canvas>
- <button id="gl_canvas_play" class="play_button">
+ <canvas id="gl_canvas_undamped" width="800" height="600"></canvas>
+ <button id="gl_canvas_play_undamped" class="play_button">
Play
</button>
- <button id="gl_canvas_stop" class="stop_button">
+ <button id="gl_canvas_stop_undamped" class="stop_button">
Stop
</button>
</div>
</section>
+
+ <section>
+ <h2>
+ Damped Springs
+ </h2>
+ <p>
+
+ </p>
+ <div class="opengl_canvas_container">
+ <canvas id="gl_canvas_damped" width="800" height="600"></canvas>
+ <button id="gl_canvas_play_damped" class="play_button">
+ Play
+ </button>
+ <button id="gl_canvas_stop_damped" class="stop_button">
+ Stop
+ </button>
+ </div>
+ </section>
+
+ <footer id='references'>
+ <h2>References</h2>
+ <ul>
+ <li>
+ <a href='https://www.youtube.com/watch?v=Z52emur7Rko'>Wonderful Undamped Resource</a>
+ </li>
+ <li>
+ <a href='https://www.youtube.com/watch?v=CTd1uVq5-l8'>Wonderful Damped Resource</a>
+ </li>
+ <li>
+ <a href='http://ambrsoft.com/CalcPhysics/Spring/SpringData.htm'>List of Equations for Spring Motion</a>
+ </li>
+ <li>
+ <a href='https://www.ryanjuckett.com/damped-springs/'>Ryan Juckett's Explanation of Damped Springs</a>
+ </li>
+ </ul>
+ </footer>
</article>
diff --git a/2d/softbody/softbody_1/build.sh b/2d/softbody/softbody_1/build.sh
index 892dddd..f1c15de 100755
--- a/2d/softbody/softbody_1/build.sh
+++ b/2d/softbody/softbody_1/build.sh
@@ -13,4 +13,4 @@ if [ ! -d ./dist ]; then
fi
echo "$filepaths"
-emcc -o dist/output.js main.cpp $filepaths -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1 \ No newline at end of file
+emcc -o dist/output.js main.cpp undamped.cpp damped.cpp $filepaths -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1
diff --git a/2d/softbody/softbody_1/damped.cpp b/2d/softbody/softbody_1/damped.cpp
new file mode 100644
index 0000000..010963b
--- /dev/null
+++ b/2d/softbody/softbody_1/damped.cpp
@@ -0,0 +1,255 @@
+#include "undamped.h"
+#include "../../../shared_cpp/Renderer2d.h"
+#include "../../../shared_cpp/types.h"
+#include "../../../shared_cpp/WebglContext.h"
+#include "../../../shared_cpp/mathlib.h"
+#include "../../../shared_cpp/MainLoop.h"
+#include <cstdio>
+#include <cmath>
+#include <emscripten/html5.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <cmath>
+#include <cfloat>
+
+namespace Damped {
+ struct DampedSpringWeight {
+ Mesh2d shape;
+ float32 radius;
+ float32 mass = 1.f;
+
+ void load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ struct DampedSpring {
+ DampedSpringWeight* weight;
+
+ Mesh2d shape;
+
+ Vertex2d* vertices = NULL;
+ int32 numSegments = 0;
+ int32 numVertices = 0;
+
+ // Initialization variables
+ float32 k = 4; // DampedSpring Constant, in N / m (Hooke's Law)
+ float32 c = 1.f; // Viscous damping coefficient (Damping force)
+ float32 R = 2.f;
+ float32 gamma = 6.2;
+
+ // Constants calculated at load time
+ float32 discriminant = 0.f;
+ float32 omega1 = 0.f;
+
+ // Update variables
+ float32 displacement = 0.f;
+ float32 timeElapsed = 0.f;
+
+
+ void load(Renderer2d* renderer, DampedSpringWeight* inWieight, float32 length, float32 loopRadius);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ WebglContext* context;
+ Renderer2d renderer;
+ MainLoop mainLoop;
+ DampedSpringWeight weight;
+ DampedSpring spring;
+
+ EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ void load();
+ void update(float32 deltaTimeSeconds, void* userData);
+ void unload();
+
+ void init(WebglContext* inContext) {
+ context = inContext;
+ emscripten_set_click_callback("#gl_canvas_play_damped", NULL, false, onPlayClicked);
+ emscripten_set_click_callback("#gl_canvas_stop_damped", NULL, false, onStopClicked);
+ }
+
+ void load() {
+ context->init("#gl_canvas_damped");
+
+ renderer.load(context);
+
+ weight.load(&renderer, 32.f, Vector4 { 55.f, 235.f, 35.f, 255.f }, Vector4 { 235.f, 5.f, 235.f, 255.f });
+ spring.load(&renderer, &weight, 250.f, 16.f);
+
+ mainLoop.run(update);
+ }
+
+ void update(float32 deltaTimeSeconds, void* userData) {
+ // -- Update
+ spring.update(deltaTimeSeconds);
+ weight.update(deltaTimeSeconds);
+
+ // -- Render
+ renderer.render();
+ weight.render(&renderer);
+ spring.render(&renderer);
+ }
+
+ void unload() {
+ mainLoop.stop();
+ renderer.unload();
+ weight.unload();
+ spring.unload();
+ context->destroy();
+ }
+
+ void DampedSpringWeight::load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
+ radius = inRadius;
+ const int32 numSegments = 96;
+ const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
+ const int32 numVertices = numSegments * 3;
+
+ float32 t = 0.f;
+ float32 tIncrement = 1.f / (numSegments / 2.f);
+ startColor = startColor.toNormalizedColor();
+ endColor = endColor.toNormalizedColor();
+
+ Vertex2d vertices[numVertices];
+ for (int idx = 0; idx < numSegments; idx++) {
+ int vIdx = idx * 3;
+
+ Vector4 color = lerp(startColor, endColor, t);
+ if (idx >= numSegments / 2) {
+ t -= tIncrement;
+ } else {
+ t += tIncrement;
+ }
+
+ vertices[vIdx].color = color;
+ vertices[vIdx].position = Vector2 { radius * cosf(radiansPerSegment * idx), radius * sinf(radiansPerSegment * idx) };
+ vertices[vIdx + 1].color = color;
+ vertices[vIdx + 1].position = Vector2 { 0.f, 0.f };
+ vertices[vIdx + 2].color = color;
+ vertices[vIdx + 2].position = Vector2 { radius * cosf(radiansPerSegment * (idx + 1)), radius * sinf(radiansPerSegment * (idx + 1)) };
+ }
+
+ shape.load(vertices, numVertices, renderer);
+ }
+
+ void DampedSpringWeight::update(float32 dtSeconds) {
+
+ }
+
+ void DampedSpringWeight::render(Renderer2d* renderer) {
+ shape.render(renderer);
+ }
+
+ void DampedSpringWeight::unload() {
+ shape.unload();
+ }
+
+ const float32 epsilon = 0.0001f;
+
+ void DampedSpring::load(Renderer2d* renderer, DampedSpringWeight* inWeight, float32 length, float32 loopRadius) {
+ weight = inWeight;
+ discriminant = c * c - (4 * weight->mass * k);
+
+ if (discriminant < epsilon && discriminant > -epsilon) { // Real repeated root: Overdamped motion
+
+ }
+ else if (discriminant > 0) { // Two real roots: Critically damped motion
+
+ }
+ else { // Complex pair (less than zero): Underdamped motion
+ omega1 = sqrtf(-discriminant) / (2.f * weight->mass); // Get the real part of the number
+ }
+
+ timeElapsed = 0.f;
+
+ const int32 verticesPerSegment = 6;
+ numSegments = 256;
+ numVertices = numSegments * verticesPerSegment;
+ vertices = new Vertex2d[numVertices];
+
+ float32 lengthIncrement = length / static_cast<float32>(numSegments);
+
+ const float32 frequency = 0.25f;
+ const float32 loopWidth = 20.f;
+ const float32 offset = 0.25f;
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1 = lengthIncrement * pidx;
+ float32 x1 = loopWidth * sinf(frequency * y1 + offset);
+
+ float32 y2 = y1 + lengthIncrement;
+ float32 x2 = loopWidth * sinf(frequency * y2 + offset);
+
+ vertices[vidx++].position = Vector2(x1, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y2);
+ }
+
+ shape.load(vertices, numVertices, renderer, GL_DYNAMIC_DRAW);
+ shape.model = Mat4x4().translateByVec2(Vector2(400, 300));
+
+ weight->shape.model = shape.model.translateByVec2(Vector2(0, -weight->radius));
+ }
+
+ void DampedSpring::update(float32 dtSeconds) {
+ timeElapsed += dtSeconds;
+
+ if (discriminant < epsilon && discriminant > -epsilon) { // Real repeated root: Overdamped motion
+
+ }
+ else if (discriminant > 0) { // Two real roots: Critically damped motion
+
+ }
+ else { // Complex pair (less than zero): Underdamped motion
+ float32 exponent = (-c / (2 * weight->mass)) * timeElapsed;
+ displacement = R * pow(E, exponent) * (cosf(omega1 * timeElapsed - gamma));
+ }
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1Offset = displacement * (1.f - pidx / static_cast<float32>(numSegments));
+ float32 y2Offset = displacement * (1.f - (pidx + 1) / static_cast<float32>(numSegments));
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y2Offset;
+ }
+
+ weight->shape.model = weight->shape.model.translateByVec2(Vector2(0, displacement));
+ }
+
+ void DampedSpring::render(Renderer2d* renderer) {
+ glBindBuffer(GL_ARRAY_BUFFER, shape.vbo);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(Vertex2d), &vertices[0]);
+
+ shape.render(renderer);
+ }
+
+ void DampedSpring::unload() {
+ shape.unload();
+ delete[] vertices;
+ }
+
+
+ EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Play clicked\n");
+
+ load();
+ return true;
+ }
+
+ EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Stop clicked\n");
+ unload();
+ return true;
+ }
+}
diff --git a/2d/softbody/softbody_1/damped.h b/2d/softbody/softbody_1/damped.h
new file mode 100644
index 0000000..f36e8dd
--- /dev/null
+++ b/2d/softbody/softbody_1/damped.h
@@ -0,0 +1,8 @@
+#pragma once
+
+struct WebglContext;
+
+namespace Damped {
+ void init(WebglContext* inContext);
+}
+
diff --git a/2d/softbody/softbody_1/dist/output.js b/2d/softbody/softbody_1/dist/output.js
index 914e5e2..24241bf 100644
--- a/2d/softbody/softbody_1/dist/output.js
+++ b/2d/softbody/softbody_1/dist/output.js
@@ -41,13 +41,16 @@ var quit_ = function(status, 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';
+var ENVIRONMENT_IS_WEB = false;
+var ENVIRONMENT_IS_WORKER = false;
+var ENVIRONMENT_IS_NODE = false;
+var ENVIRONMENT_IS_SHELL = false;
+ENVIRONMENT_IS_WEB = typeof window === 'object';
+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;
+ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
+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, -s ENVIRONMENT=web or -s ENVIRONMENT=node)');
@@ -72,7 +75,6 @@ var nodeFS;
var nodePath;
if (ENVIRONMENT_IS_NODE) {
- if (!(typeof process === 'object' && typeof require === '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 (ENVIRONMENT_IS_WORKER) {
scriptDirectory = require('path').dirname(scriptDirectory) + '/';
} else {
@@ -98,16 +100,6 @@ readBinary = function readBinary(filename) {
return ret;
};
-readAsync = function readAsync(filename, onload, onerror) {
- if (!nodeFS) nodeFS = require('fs');
- if (!nodePath) nodePath = require('path');
- filename = nodePath['normalize'](filename);
- nodeFS['readFile'](filename, function(err, data) {
- if (err) onerror(err);
- else onload(data.buffer);
- });
-};
-
// end include: node_shell_read.js
if (process['argv'].length > 1) {
thisProgram = process['argv'][1].replace(/\\/g, '/');
@@ -128,11 +120,7 @@ readAsync = function readAsync(filename, onload, onerror) {
process['on']('unhandledRejection', abort);
- quit_ = function(status, toThrow) {
- if (keepRuntimeAlive()) {
- process['exitCode'] = status;
- throw toThrow;
- }
+ quit_ = function(status) {
process['exit'](status);
};
@@ -141,8 +129,6 @@ readAsync = function readAsync(filename, onload, onerror) {
} 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_ = function shell_read(f) {
return read(f);
@@ -159,10 +145,6 @@ if (ENVIRONMENT_IS_SHELL) {
return data;
};
- readAsync = function readAsync(f, onload, onerror) {
- setTimeout(function() { onload(readBinary(f)); }, 0);
- };
-
if (typeof scriptArgs != 'undefined') {
arguments_ = scriptArgs;
} else if (typeof arguments != 'undefined') {
@@ -203,8 +185,6 @@ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
scriptDirectory = '';
}
- 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?)');
-
// Differentiate the Web Worker from the Node Worker case, as reading must
// be done differently.
{
@@ -354,15 +334,17 @@ var IDBFS = 'IDBFS is no longer included by default; build with -lidbfs.js';
var PROXYFS = 'PROXYFS is no longer included by default; build with -lproxyfs.js';
var WORKERFS = 'WORKERFS is no longer included by default; build with -lworkerfs.js';
var NODEFS = 'NODEFS is no longer included by default; build with -lnodefs.js';
-function alignMemory() { abort('`alignMemory` is now a library function and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line'); }
-
-assert(!ENVIRONMENT_IS_SHELL, "shell environment detected but not enabled at build time. Add 'shell' to `-s ENVIRONMENT` to enable.");
var STACK_ALIGN = 16;
+function alignMemory(size, factor) {
+ if (!factor) factor = STACK_ALIGN; // stack alignment (16-byte) by default
+ return Math.ceil(size / factor) * factor;
+}
+
function getNativeTypeSize(type) {
switch (type) {
case 'i1': case 'i8': return 1;
@@ -560,6 +542,10 @@ function addFunction(func, sig) {
// end include: runtime_debug.js
+function makeBigInt(low, high, unsigned) {
+ return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0));
+}
+
var tempRet0 = 0;
var setTempRet0 = function(value) {
@@ -570,6 +556,10 @@ var getTempRet0 = function() {
return tempRet0;
};
+function getCompilerSetting(name) {
+ throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for getCompilerSetting or emscripten_get_compiler_setting to work';
+}
+
// === Preamble library stuff ===
@@ -729,12 +719,9 @@ function ccall(ident, returnType, argTypes, args, opts) {
}
}
var ret = func.apply(null, cArgs);
- function onDone(ret) {
- if (stack !== 0) stackRestore(stack);
- return convertReturnValue(ret);
- }
- ret = onDone(ret);
+ ret = convertReturnValue(ret);
+ if (stack !== 0) stackRestore(stack);
return ret;
}
@@ -1273,6 +1260,10 @@ function checkStackCookie() {
if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -s SUPPORT_BIG_ENDIAN=1 to bypass)';
})();
+function abortFnPtrError(ptr, sig) {
+ abort("Invalid function pointer " + ptr + " called with signature '" + sig + "'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this). Build with ASSERTIONS=2 for more info.");
+}
+
// end include: runtime_assertions.js
var __ATPRERUN__ = []; // functions called before the runtime is initialized
var __ATINIT__ = []; // functions called during startup
@@ -1282,11 +1273,6 @@ var __ATPOSTRUN__ = []; // functions called after the main() is called
var runtimeInitialized = false;
var runtimeExited = false;
-var runtimeKeepaliveCounter = 0;
-
-function keepRuntimeAlive() {
- return noExitRuntime || runtimeKeepaliveCounter > 0;
-}
function preRun() {
@@ -1509,18 +1495,25 @@ Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
// include: URIUtils.js
+function hasPrefix(str, prefix) {
+ return String.prototype.startsWith ?
+ str.startsWith(prefix) :
+ str.indexOf(prefix) === 0;
+}
+
// 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);
+ return hasPrefix(filename, dataURIPrefix);
}
+var fileURIPrefix = "file://";
+
// Indicates whether filename is delivered via file protocol (as opposed to http/https)
function isFileURI(filename) {
- return filename.startsWith('file://');
+ return hasPrefix(filename, fileURIPrefix);
}
// end include: URIUtils.js
@@ -1540,11 +1533,10 @@ function createExportWrapper(name, fixedasm) {
};
}
-var wasmBinaryFile;
- wasmBinaryFile = 'output.wasm';
- if (!isDataURI(wasmBinaryFile)) {
- wasmBinaryFile = locateFile(wasmBinaryFile);
- }
+var wasmBinaryFile = 'output.wasm';
+if (!isDataURI(wasmBinaryFile)) {
+ wasmBinaryFile = locateFile(wasmBinaryFile);
+}
function getBinary(file) {
try {
@@ -1590,7 +1582,7 @@ function getBinaryPromise() {
}
}
}
-
+
// Otherwise, getBinary should be able to get it synchronously
return Promise.resolve().then(function() { return getBinary(wasmBinaryFile); });
}
@@ -1630,26 +1622,24 @@ function createWasm() {
// we can't run yet (except in a pthread, where we have a custom sync instantiator)
addRunDependency('wasm-instantiate');
- // Prefer streaming instantiation if available.
// Async compilation can be confusing when an error on the page overwrites Module
// (for example, if the order of elements is wrong, and the one defining Module is
// later), so we save Module and check it later.
var trueModule = Module;
- function receiveInstantiationResult(result) {
- // 'result' is a ResultObject object which has both the module and instance.
+ function receiveInstantiatedSource(output) {
+ // 'output' is a WebAssemblyInstantiatedSource object which has both the module and instance.
// receiveInstance() will swap in the exports (to Module.asm) so they can be called
assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?');
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 USE_PTHREADS-enabled path.
- receiveInstance(result['instance']);
+ receiveInstance(output['instance']);
}
function instantiateArrayBuffer(receiver) {
return getBinaryPromise().then(function(binary) {
- return WebAssembly.instantiate(binary, info);
- }).then(function (instance) {
- return instance;
+ var result = WebAssembly.instantiate(binary, info);
+ return result;
}).then(receiver, function(reason) {
err('failed to asynchronously prepare wasm: ' + reason);
@@ -1661,6 +1651,7 @@ function createWasm() {
});
}
+ // Prefer streaming instantiation if available.
function instantiateAsync() {
if (!wasmBinary &&
typeof WebAssembly.instantiateStreaming === 'function' &&
@@ -1670,19 +1661,16 @@ function createWasm() {
typeof fetch === 'function') {
return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) {
var result = WebAssembly.instantiateStreaming(response, info);
-
- return result.then(
- receiveInstantiationResult,
- function(reason) {
+ return result.then(receiveInstantiatedSource, 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(receiveInstantiationResult);
+ return instantiateArrayBuffer(receiveInstantiatedSource);
});
});
} else {
- return instantiateArrayBuffer(receiveInstantiationResult);
+ return instantiateArrayBuffer(receiveInstantiatedSource);
}
}
@@ -1770,6 +1758,11 @@ var ASM_CONSTS = {
return error.stack.toString();
}
+ var runtimeKeepaliveCounter=0;
+ function keepRuntimeAlive() {
+ return noExitRuntime || runtimeKeepaliveCounter > 0;
+ }
+
function stackTrace() {
var js = jsStackTrace();
if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
@@ -1800,14 +1793,13 @@ var ASM_CONSTS = {
updateGlobalBufferAndViews(wasmMemory.buffer);
return 1 /*success*/;
} catch(e) {
- err('emscripten_realloc_buffer: Attempted to grow heap from ' + buffer.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e);
+ console.error('emscripten_realloc_buffer: Attempted to grow heap from ' + buffer.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e);
}
// implicit 0 return to save code size (caller will cast "undefined" into 0
// anyhow)
}
function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
- requestedSize = requestedSize >>> 0;
// With pthreads, races can happen (another thread might increase the size in between), so return a failure, and let the caller retry.
assert(requestedSize > oldSize);
@@ -1821,7 +1813,7 @@ var ASM_CONSTS = {
// 4. If we were unable to allocate as much memory, it may be due to over-eager decision to excessively reserve due to (3) above.
// Hence if an allocation fails, cut down on the amount of excess growth, in an attempt to succeed to perform a smaller allocation.
- // A limit is set for how much we can grow. We should not exceed that
+ // A limit was set for how much we can grow. We should not exceed that
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
// In CAN_ADDRESS_2GB mode, stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate full 4GB Wasm memories, the size will wrap
// back to 0 bytes in Wasm side for any code that deals with heap sizes, which would require special casing all heap size related code to treat
@@ -1851,7 +1843,7 @@ var ASM_CONSTS = {
return false;
}
- var JSEvents = {inEventHandler:0,removeAllEventListeners:function() {
+ var JSEvents={inEventHandler:0,removeAllEventListeners:function() {
for (var i = JSEvents.eventHandlers.length-1; i >= 0; --i) {
JSEvents._removeHandler(i);
}
@@ -1964,7 +1956,7 @@ var ASM_CONSTS = {
return cString > 2 ? UTF8ToString(cString) : cString;
}
- var specialHTMLTargets = [0, typeof document !== 'undefined' ? document : 0, typeof window !== 'undefined' ? window : 0];
+ var specialHTMLTargets=[0, typeof document !== 'undefined' ? document : 0, typeof window !== 'undefined' ? window : 0];
function findEventTarget(target) {
target = maybeCStringToJsString(target);
var domElement = specialHTMLTargets[target] || (typeof document !== 'undefined' ? document.querySelector(target) : undefined);
@@ -1984,32 +1976,31 @@ var ASM_CONSTS = {
}
function fillMouseEventData(eventStruct, e, target) {
assert(eventStruct % 4 == 0);
- HEAPF64[((eventStruct)>>3)] = e.timeStamp;
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"]
+ HEAP32[idx + 0] = e.screenX;
+ HEAP32[idx + 1] = e.screenY;
+ HEAP32[idx + 2] = e.clientX;
+ HEAP32[idx + 3] = e.clientY;
+ HEAP32[idx + 4] = e.ctrlKey;
+ HEAP32[idx + 5] = e.shiftKey;
+ HEAP32[idx + 6] = e.altKey;
+ HEAP32[idx + 7] = e.metaKey;
+ HEAP16[idx*2 + 16] = e.button;
+ HEAP16[idx*2 + 17] = e.buttons;
+
+ HEAP32[idx + 9] = e["movementX"]
;
- HEAP32[idx + 12] = e["movementY"]
+ HEAP32[idx + 10] = e["movementY"]
;
var rect = getBoundingClientRect(target);
- HEAP32[idx + 13] = e.clientX - rect.left;
- HEAP32[idx + 14] = e.clientY - rect.top;
+ HEAP32[idx + 11] = e.clientX - rect.left;
+ HEAP32[idx + 12] = e.clientY - rect.top;
}
function registerMouseEventCallback(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) {
- if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc( 72 );
+ if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc( 64 );
target = findEventTarget(target);
var mouseEventHandlerFunc = function(ev) {
@@ -2082,7 +2073,7 @@ var ASM_CONSTS = {
// Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted.
return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw'));
}
- var GL = {counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode) {
+ var GL={counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],uniforms:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},timerQueriesEXT:[],queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],programInfos:{},stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode) {
if (!GL.lastError) {
GL.lastError = errorCode;
}
@@ -2306,35 +2297,64 @@ var ASM_CONSTS = {
__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
- // On WebGL 2, EXT_disjoint_timer_query is replaced with an alternative
- // that's based on core APIs, and exposes only the queryCounterEXT()
- // entrypoint.
- if (context.version >= 2) {
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query_webgl2");
- }
-
- // However, Firefox exposes the WebGL 1 version on WebGL 2 as well and
- // thus we look for the WebGL 1 version again if the WebGL 2 version
- // isn't present. https://bugzilla.mozilla.org/show_bug.cgi?id=1328882
- if (context.version < 2 || !GLctx.disjointTimerQueryExt)
- {
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
- }
-
+ 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(function(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')) {
+ if (ext.indexOf('lose_context') < 0 && ext.indexOf('debug') < 0) {
// Call .getExtension() to enable that extension permanently.
GLctx.getExtension(ext);
}
});
+ },populateUniformTable:function(program) {
+ var p = GL.programs[program];
+ var ptable = GL.programInfos[program] = {
+ uniforms: {},
+ maxUniformLength: 0, // This is eagerly computed below, since we already enumerate all uniforms anyway.
+ maxAttributeLength: -1, // This is lazily computed and cached, computed when/if first asked, "-1" meaning not computed yet.
+ maxUniformBlockNameLength: -1 // Lazily computed as well
+ };
+
+ var utable = ptable.uniforms;
+ // A program's uniform table maps the string name of an uniform to an integer location of that uniform.
+ // The global GL.uniforms map maps integer locations to WebGLUniformLocations.
+ var numUniforms = GLctx.getProgramParameter(p, 0x8B86/*GL_ACTIVE_UNIFORMS*/);
+ for (var i = 0; i < numUniforms; ++i) {
+ var u = GLctx.getActiveUniform(p, i);
+
+ var name = u.name;
+ ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1);
+
+ // If we are dealing with an array, e.g. vec4 foo[3], strip off the array index part to canonicalize that "foo", "foo[]",
+ // and "foo[0]" will mean the same. Loop below will populate foo[1] and foo[2].
+ if (name.slice(-1) == ']') {
+ name = name.slice(0, name.lastIndexOf('['));
+ }
+
+ // Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then
+ // only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i.
+ // Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices.
+ var loc = GLctx.getUniformLocation(p, name);
+ if (loc) {
+ var id = GL.getNewId(GL.uniforms);
+ utable[name] = [u.size, id];
+ GL.uniforms[id] = loc;
+
+ for (var j = 1; j < u.size; ++j) {
+ var n = name + '['+j+']';
+ loc = GLctx.getUniformLocation(p, n);
+ id = GL.getNewId(GL.uniforms);
+
+ GL.uniforms[id] = loc;
+ }
+ }
+ }
}};
- var __emscripten_webgl_power_preferences = ['default', 'low-power', 'high-performance'];
+ var __emscripten_webgl_power_preferences=['default', 'low-power', 'high-performance'];
function _emscripten_webgl_do_create_context(target, attributes) {
assert(attributes);
var a = attributes >> 2;
@@ -2375,6 +2395,25 @@ var ASM_CONSTS = {
return _emscripten_webgl_do_create_context(a0,a1);
}
+ function _emscripten_webgl_do_get_current_context() {
+ return GL.currentContext ? GL.currentContext.handle : 0;
+ }
+ function _emscripten_webgl_get_current_context(
+ ) {
+ return _emscripten_webgl_do_get_current_context();
+ }
+ Module["_emscripten_webgl_get_current_context"] = _emscripten_webgl_get_current_context;
+
+ function _emscripten_webgl_make_context_current(contextHandle) {
+ var success = GL.makeContextCurrent(contextHandle);
+ return success ? 0 : -5;
+ }
+ Module["_emscripten_webgl_make_context_current"] = _emscripten_webgl_make_context_current;
+ function _emscripten_webgl_destroy_context(contextHandle) {
+ if (GL.currentContext == contextHandle) GL.currentContext = 0;
+ GL.deleteContext(contextHandle);
+ }
+
function _emscripten_webgl_init_context_attributes(attributes) {
assert(attributes);
var a = attributes >> 2;
@@ -2391,10 +2430,6 @@ var ASM_CONSTS = {
}
- function _emscripten_webgl_make_context_current(contextHandle) {
- var success = GL.makeContextCurrent(contextHandle);
- return success ? 0 : -5;
- }
function flush_NO_FILESYSTEM() {
// flush anything remaining in the buffers during shutdown
@@ -2404,7 +2439,7 @@ var ASM_CONSTS = {
if (buffers[2].length) SYSCALLS.printChar(2, 10);
}
- var SYSCALLS = {mappings:{},buffers:[null,[],[]],printChar:function(stream, curr) {
+ var SYSCALLS={mappings:{},buffers:[null,[],[]],printChar:function(stream, curr) {
var buffer = SYSCALLS.buffers[stream];
assert(buffer);
if (curr === 0 || curr === 10) {
@@ -2442,7 +2477,8 @@ var ASM_CONSTS = {
}
function _glAttachShader(program, shader) {
- GLctx.attachShader(GL.programs[program], GL.shaders[shader]);
+ GLctx.attachShader(GL.programs[program],
+ GL.shaders[shader]);
}
function _glBindBuffer(target, buffer) {
@@ -2510,11 +2546,7 @@ var ASM_CONSTS = {
function _glCreateProgram() {
var id = GL.getNewId(GL.programs);
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)
- program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0;
- program.uniformIdCounter = 1;
GL.programs[id] = program;
return id;
}
@@ -2522,7 +2554,6 @@ var ASM_CONSTS = {
function _glCreateShader(shaderType) {
var id = GL.getNewId(GL.shaders);
GL.shaders[id] = GLctx.createShader(shaderType);
-
return id;
}
@@ -2556,6 +2587,7 @@ var ASM_CONSTS = {
GLctx.deleteProgram(program);
program.name = 0;
GL.programs[id] = null;
+ GL.programInfos[id] = null;
}
function _glDeleteShader(id) {
@@ -2648,35 +2680,42 @@ var ASM_CONSTS = {
return;
}
- program = GL.programs[program];
+ var ptable = GL.programInfos[program];
+ if (!ptable) {
+ GL.recordError(0x502 /* GL_INVALID_OPERATION */);
+ return;
+ }
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- var log = GLctx.getProgramInfoLog(program);
+ var log = GLctx.getProgramInfoLog(GL.programs[program]);
if (log === null) log = '(unknown error)';
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) {
- program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i).name.length+1);
- }
- }
- HEAP32[((p)>>2)] = program.maxUniformLength;
+ HEAP32[((p)>>2)] = ptable.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) {
- program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i).name.length+1);
+ if (ptable.maxAttributeLength == -1) {
+ program = GL.programs[program];
+ var numAttribs = GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/);
+ ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned.
+ for (var i = 0; i < numAttribs; ++i) {
+ var activeAttrib = GLctx.getActiveAttrib(program, i);
+ ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1);
}
}
- HEAP32[((p)>>2)] = program.maxAttributeLength;
+ HEAP32[((p)>>2)] = ptable.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) {
- program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1);
+ if (ptable.maxUniformBlockNameLength == -1) {
+ program = GL.programs[program];
+ var numBlocks = GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/);
+ ptable.maxUniformBlockNameLength = 0;
+ for (var i = 0; i < numBlocks; ++i) {
+ var activeBlockName = GLctx.getActiveUniformBlockName(program, i);
+ ptable.maxUniformBlockNameLength = Math.max(ptable.maxUniformBlockNameLength, activeBlockName.length+1);
}
}
- HEAP32[((p)>>2)] = program.maxUniformBlockNameLength;
+ HEAP32[((p)>>2)] = ptable.maxUniformBlockNameLength;
} else {
- HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname);
+ HEAP32[((p)>>2)] = GLctx.getProgramParameter(GL.programs[program], pname);
}
}
@@ -2718,100 +2757,28 @@ var ASM_CONSTS = {
function jstoi_q(str) {
return parseInt(str);
}
-
- /** @noinline */
- function webglGetLeftBracePos(name) {
- return name.slice(-1) == ']' && name.lastIndexOf('[');
- }
- function webglPrepareUniformLocationsBeforeFirstUse(program) {
- var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation
- uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint]
- i, j;
-
- // On the first time invocation of glGetUniformLocation on this shader program:
- // initialize cache data structures and discover which uniforms are arrays.
- if (!uniformLocsById) {
- // maps GLint integer locations to WebGLUniformLocations
- program.uniformLocsById = uniformLocsById = {};
- // 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 u = GLctx.getActiveUniform(program, i);
- var nm = u.name;
- var sz = u.size;
- var lb = webglGetLeftBracePos(nm);
- var arrayName = lb > 0 ? nm.slice(0, lb) : nm;
-
- // Assign a new location.
- var id = program.uniformIdCounter;
- program.uniformIdCounter += sz;
- // Eagerly get the location of the uniformArray[0] base element.
- // The remaining indices >0 will be left for lazy evaluation to
- // improve performance. Those may never be needed to fetch, if the
- // application fills arrays always in full starting from the first
- // element of the array.
- uniformSizeAndIdsByName[arrayName] = [sz, id];
-
- // Store placeholder integers in place that highlight that these
- // >0 index locations are array indices pending population.
- for(j = 0; j < sz; ++j) {
- uniformLocsById[id] = j;
- program.uniformArrayNamesById[id++] = arrayName;
- }
- }
- }
- }
function _glGetUniformLocation(program, name) {
-
name = UTF8ToString(name);
- if (program = GL.programs[program]) {
- webglPrepareUniformLocationsBeforeFirstUse(program);
- var uniformLocsById = program.uniformLocsById; // Maps GLuint -> WebGLUniformLocation
- 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.
- var leftBrace = webglGetLeftBracePos(name);
-
- // If user passed an array accessor "[index]", parse the array index off the accessor.
- if (leftBrace > 0) {
- arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds.
- uniformBaseName = name.slice(0, leftBrace);
- }
-
- // Have we cached the location of this uniform before?
- var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; // A pair [array length, GLint of the uniform 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))) {
- return arrayIndex;
- }
- }
+ var arrayIndex = 0;
+ // If user passed an array accessor "[index]", parse the array index off the accessor.
+ if (name[name.length - 1] == ']') {
+ var leftBrace = name.lastIndexOf('[');
+ arrayIndex = name[leftBrace+1] != ']' ? jstoi_q(name.slice(leftBrace + 1)) : 0; // "index]", parseInt will ignore the ']' at the end; but treat "foo[]" as "foo[0]"
+ name = name.slice(0, leftBrace);
}
- 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.
- GL.recordError(0x501 /* GL_INVALID_VALUE */);
+
+ var uniformInfo = GL.programInfos[program] && GL.programInfos[program].uniforms[name]; // returns pair [ dimension_of_uniform_array, uniform_location ]
+ if (uniformInfo && arrayIndex >= 0 && arrayIndex < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1.
+ return uniformInfo[1] + arrayIndex;
+ } else {
+ return -1;
}
- return -1;
}
function _glLinkProgram(program) {
- program = GL.programs[program];
- GLctx.linkProgram(program);
- // Invalidate earlier computed uniform->ID mappings, those have now become stale
- program.uniformLocsById = 0; // Mark as null-like so that glGetUniformLocation() knows to populate this again.
- program.uniformSizeAndIdsByName = {};
-
+ GLctx.linkProgram(GL.programs[program]);
+ GL.populateUniformTable(program);
}
function _glShaderSource(shader, count, string, length) {
@@ -2820,30 +2787,11 @@ var ASM_CONSTS = {
GLctx.shaderSource(GL.shaders[shader], source);
}
- function webglGetUniformLocation(location) {
- var p = GLctx.currentProgram;
-
- 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.
- if (typeof webglLoc === 'number') {
- p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? '[' + webglLoc + ']' : ''));
- }
- // Else an already cached WebGLUniformLocation, return it.
- return webglLoc;
- } else {
- GL.recordError(0x502/*GL_INVALID_OPERATION*/);
- }
- }
-
- var miniTempWebGLFloatBuffers = [];
+ var miniTempWebGLFloatBuffers=[];
function _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.
- GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16);
+ GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, HEAPF32, value>>2, count*16);
return;
}
@@ -2876,15 +2824,11 @@ var ASM_CONSTS = {
{
var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2);
}
- GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view);
+ GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, view);
}
function _glUseProgram(program) {
- program = GL.programs[program];
- GLctx.useProgram(program);
- // Record the currently active program so that we can access the uniform
- // mapping table of that program.
- GLctx.currentProgram = program;
+ GLctx.useProgram(GL.programs[program]);
}
function _glVertexAttribPointer(index, size, type, normalized, stride, ptr) {
@@ -2905,8 +2849,8 @@ var ASM_CONSTS = {
GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
}
- function _setTempRet0(val) {
- setTempRet0(val);
+ function _setTempRet0($i) {
+ setTempRet0(($i) | 0);
}
var GLctx;;
var miniTempWebGLFloatBuffersStorage = new Float32Array(288);
@@ -2951,6 +2895,7 @@ var asmLibraryArg = {
"emscripten_set_canvas_element_size": _emscripten_set_canvas_element_size,
"emscripten_set_click_callback_on_thread": _emscripten_set_click_callback_on_thread,
"emscripten_webgl_create_context": _emscripten_webgl_create_context,
+ "emscripten_webgl_destroy_context": _emscripten_webgl_destroy_context,
"emscripten_webgl_init_context_attributes": _emscripten_webgl_init_context_attributes,
"emscripten_webgl_make_context_current": _emscripten_webgl_make_context_current,
"fd_write": _fd_write,
@@ -3041,237 +2986,230 @@ var dynCall_jiji = Module["dynCall_jiji"] = createExportWrapper("dynCall_jiji");
// === Auto-generated postamble setup entry stuff ===
-if (!Object.getOwnPropertyDescriptor(Module, "intArrayFromString")) Module["intArrayFromString"] = function() { abort("'intArrayFromString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "intArrayToString")) Module["intArrayToString"] = function() { abort("'intArrayToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "ccall")) Module["ccall"] = function() { abort("'ccall' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "cwrap")) Module["cwrap"] = function() { abort("'cwrap' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setValue")) Module["setValue"] = function() { abort("'setValue' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getValue")) Module["getValue"] = function() { abort("'getValue' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "allocate")) Module["allocate"] = function() { abort("'allocate' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "UTF8ArrayToString")) Module["UTF8ArrayToString"] = function() { abort("'UTF8ArrayToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "UTF8ToString")) Module["UTF8ToString"] = function() { abort("'UTF8ToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8Array")) Module["stringToUTF8Array"] = function() { abort("'stringToUTF8Array' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8")) Module["stringToUTF8"] = function() { abort("'stringToUTF8' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF8")) Module["lengthBytesUTF8"] = function() { abort("'lengthBytesUTF8' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addOnPreRun")) Module["addOnPreRun"] = function() { abort("'addOnPreRun' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addOnInit")) Module["addOnInit"] = function() { abort("'addOnInit' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addOnPreMain")) Module["addOnPreMain"] = function() { abort("'addOnPreMain' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addOnExit")) Module["addOnExit"] = function() { abort("'addOnExit' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addOnPostRun")) Module["addOnPostRun"] = function() { abort("'addOnPostRun' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeStringToMemory")) Module["writeStringToMemory"] = function() { abort("'writeStringToMemory' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeArrayToMemory")) Module["writeArrayToMemory"] = function() { abort("'writeArrayToMemory' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeAsciiToMemory")) Module["writeAsciiToMemory"] = function() { abort("'writeAsciiToMemory' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addRunDependency")) Module["addRunDependency"] = function() { abort("'addRunDependency' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "removeRunDependency")) Module["removeRunDependency"] = function() { abort("'removeRunDependency' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createFolder")) Module["FS_createFolder"] = function() { abort("'FS_createFolder' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createPath")) Module["FS_createPath"] = function() { abort("'FS_createPath' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createDataFile")) Module["FS_createDataFile"] = function() { abort("'FS_createDataFile' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createPreloadedFile")) Module["FS_createPreloadedFile"] = function() { abort("'FS_createPreloadedFile' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createLazyFile")) Module["FS_createLazyFile"] = function() { abort("'FS_createLazyFile' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createLink")) Module["FS_createLink"] = function() { abort("'FS_createLink' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_createDevice")) Module["FS_createDevice"] = function() { abort("'FS_createDevice' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS_unlink")) Module["FS_unlink"] = function() { abort("'FS_unlink' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
-if (!Object.getOwnPropertyDescriptor(Module, "getLEB")) Module["getLEB"] = function() { abort("'getLEB' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getFunctionTables")) Module["getFunctionTables"] = function() { abort("'getFunctionTables' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "alignFunctionTables")) Module["alignFunctionTables"] = function() { abort("'alignFunctionTables' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerFunctions")) Module["registerFunctions"] = function() { abort("'registerFunctions' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "addFunction")) Module["addFunction"] = function() { abort("'addFunction' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "removeFunction")) Module["removeFunction"] = function() { abort("'removeFunction' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "prettyPrint")) Module["prettyPrint"] = function() { abort("'prettyPrint' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getCompilerSetting")) Module["getCompilerSetting"] = function() { abort("'getCompilerSetting' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "print")) Module["print"] = function() { abort("'print' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "printErr")) Module["printErr"] = function() { abort("'printErr' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getTempRet0")) Module["getTempRet0"] = function() { abort("'getTempRet0' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setTempRet0")) Module["setTempRet0"] = function() { abort("'setTempRet0' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "callMain")) Module["callMain"] = function() { abort("'callMain' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "abort")) Module["abort"] = function() { abort("'abort' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "keepRuntimeAlive")) Module["keepRuntimeAlive"] = function() { abort("'keepRuntimeAlive' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "zeroMemory")) Module["zeroMemory"] = function() { abort("'zeroMemory' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToNewUTF8")) Module["stringToNewUTF8"] = function() { abort("'stringToNewUTF8' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setFileTime")) Module["setFileTime"] = function() { abort("'setFileTime' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscripten_realloc_buffer")) Module["emscripten_realloc_buffer"] = function() { abort("'emscripten_realloc_buffer' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "ENV")) Module["ENV"] = function() { abort("'ENV' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_CODES")) Module["ERRNO_CODES"] = function() { abort("'ERRNO_CODES' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_MESSAGES")) Module["ERRNO_MESSAGES"] = function() { abort("'ERRNO_MESSAGES' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setErrNo")) Module["setErrNo"] = function() { abort("'setErrNo' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetPton4")) Module["inetPton4"] = function() { abort("'inetPton4' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetNtop4")) Module["inetNtop4"] = function() { abort("'inetNtop4' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetPton6")) Module["inetPton6"] = function() { abort("'inetPton6' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetNtop6")) Module["inetNtop6"] = function() { abort("'inetNtop6' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readSockaddr")) Module["readSockaddr"] = function() { abort("'readSockaddr' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeSockaddr")) Module["writeSockaddr"] = function() { abort("'writeSockaddr' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() { abort("'DNS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getHostByName")) Module["getHostByName"] = function() { abort("'getHostByName' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GAI_ERRNO_MESSAGES")) Module["GAI_ERRNO_MESSAGES"] = function() { abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "Protocols")) Module["Protocols"] = function() { abort("'Protocols' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "Sockets")) Module["Sockets"] = function() { abort("'Sockets' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getRandomDevice")) Module["getRandomDevice"] = function() { abort("'getRandomDevice' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "traverseStack")) Module["traverseStack"] = function() { abort("'traverseStack' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "UNWIND_CACHE")) Module["UNWIND_CACHE"] = function() { abort("'UNWIND_CACHE' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "withBuiltinMalloc")) Module["withBuiltinMalloc"] = function() { abort("'withBuiltinMalloc' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgsArray")) Module["readAsmConstArgsArray"] = function() { abort("'readAsmConstArgsArray' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgs")) Module["readAsmConstArgs"] = function() { abort("'readAsmConstArgs' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "mainThreadEM_ASM")) Module["mainThreadEM_ASM"] = function() { abort("'mainThreadEM_ASM' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "jstoi_q")) Module["jstoi_q"] = function() { abort("'jstoi_q' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "jstoi_s")) Module["jstoi_s"] = function() { abort("'jstoi_s' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getExecutableName")) Module["getExecutableName"] = function() { abort("'getExecutableName' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "listenOnce")) Module["listenOnce"] = function() { abort("'listenOnce' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "autoResumeAudioContext")) Module["autoResumeAudioContext"] = function() { abort("'autoResumeAudioContext' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "dynCallLegacy")) Module["dynCallLegacy"] = function() { abort("'dynCallLegacy' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getDynCaller")) Module["getDynCaller"] = function() { abort("'getDynCaller' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "callRuntimeCallbacks")) Module["callRuntimeCallbacks"] = function() { abort("'callRuntimeCallbacks' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "handleException")) Module["handleException"] = function() { abort("'handleException' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePush")) Module["runtimeKeepalivePush"] = function() { abort("'runtimeKeepalivePush' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePop")) Module["runtimeKeepalivePop"] = function() { abort("'runtimeKeepalivePop' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "callUserCallback")) Module["callUserCallback"] = function() { abort("'callUserCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "maybeExit")) Module["maybeExit"] = function() { abort("'maybeExit' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "safeSetTimeout")) Module["safeSetTimeout"] = function() { abort("'safeSetTimeout' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "asmjsMangle")) Module["asmjsMangle"] = function() { abort("'asmjsMangle' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "asyncLoad")) Module["asyncLoad"] = function() { abort("'asyncLoad' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "alignMemory")) Module["alignMemory"] = function() { abort("'alignMemory' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "mmapAlloc")) Module["mmapAlloc"] = function() { abort("'mmapAlloc' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "formatString")) Module["formatString"] = function() { abort("'formatString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "PATH")) Module["PATH"] = function() { abort("'PATH' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "PATH_FS")) Module["PATH_FS"] = function() { abort("'PATH_FS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SYSCALLS")) Module["SYSCALLS"] = function() { abort("'SYSCALLS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "syscallMmap2")) Module["syscallMmap2"] = function() { abort("'syscallMmap2' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "syscallMunmap")) Module["syscallMunmap"] = function() { abort("'syscallMunmap' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getSocketFromFD")) Module["getSocketFromFD"] = function() { abort("'getSocketFromFD' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getSocketAddress")) Module["getSocketAddress"] = function() { abort("'getSocketAddress' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "JSEvents")) Module["JSEvents"] = function() { abort("'JSEvents' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerKeyEventCallback")) Module["registerKeyEventCallback"] = function() { abort("'registerKeyEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "specialHTMLTargets")) Module["specialHTMLTargets"] = function() { abort("'specialHTMLTargets' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "maybeCStringToJsString")) Module["maybeCStringToJsString"] = function() { abort("'maybeCStringToJsString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "findEventTarget")) Module["findEventTarget"] = function() { abort("'findEventTarget' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "findCanvasEventTarget")) Module["findCanvasEventTarget"] = function() { abort("'findCanvasEventTarget' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getBoundingClientRect")) Module["getBoundingClientRect"] = function() { abort("'getBoundingClientRect' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillMouseEventData")) Module["fillMouseEventData"] = function() { abort("'fillMouseEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerMouseEventCallback")) Module["registerMouseEventCallback"] = function() { abort("'registerMouseEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerWheelEventCallback")) Module["registerWheelEventCallback"] = function() { abort("'registerWheelEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerUiEventCallback")) Module["registerUiEventCallback"] = function() { abort("'registerUiEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerFocusEventCallback")) Module["registerFocusEventCallback"] = function() { abort("'registerFocusEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillDeviceOrientationEventData")) Module["fillDeviceOrientationEventData"] = function() { abort("'fillDeviceOrientationEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerDeviceOrientationEventCallback")) Module["registerDeviceOrientationEventCallback"] = function() { abort("'registerDeviceOrientationEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillDeviceMotionEventData")) Module["fillDeviceMotionEventData"] = function() { abort("'fillDeviceMotionEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerDeviceMotionEventCallback")) Module["registerDeviceMotionEventCallback"] = function() { abort("'registerDeviceMotionEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "screenOrientation")) Module["screenOrientation"] = function() { abort("'screenOrientation' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillOrientationChangeEventData")) Module["fillOrientationChangeEventData"] = function() { abort("'fillOrientationChangeEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerOrientationChangeEventCallback")) Module["registerOrientationChangeEventCallback"] = function() { abort("'registerOrientationChangeEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillFullscreenChangeEventData")) Module["fillFullscreenChangeEventData"] = function() { abort("'fillFullscreenChangeEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerFullscreenChangeEventCallback")) Module["registerFullscreenChangeEventCallback"] = function() { abort("'registerFullscreenChangeEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerRestoreOldStyle")) Module["registerRestoreOldStyle"] = function() { abort("'registerRestoreOldStyle' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "hideEverythingExceptGivenElement")) Module["hideEverythingExceptGivenElement"] = function() { abort("'hideEverythingExceptGivenElement' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "restoreHiddenElements")) Module["restoreHiddenElements"] = function() { abort("'restoreHiddenElements' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setLetterbox")) Module["setLetterbox"] = function() { abort("'setLetterbox' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "currentFullscreenStrategy")) Module["currentFullscreenStrategy"] = function() { abort("'currentFullscreenStrategy' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "restoreOldWindowedStyle")) Module["restoreOldWindowedStyle"] = function() { abort("'restoreOldWindowedStyle' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "softFullscreenResizeWebGLRenderTarget")) Module["softFullscreenResizeWebGLRenderTarget"] = function() { abort("'softFullscreenResizeWebGLRenderTarget' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "doRequestFullscreen")) Module["doRequestFullscreen"] = function() { abort("'doRequestFullscreen' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillPointerlockChangeEventData")) Module["fillPointerlockChangeEventData"] = function() { abort("'fillPointerlockChangeEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerPointerlockChangeEventCallback")) Module["registerPointerlockChangeEventCallback"] = function() { abort("'registerPointerlockChangeEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerPointerlockErrorEventCallback")) Module["registerPointerlockErrorEventCallback"] = function() { abort("'registerPointerlockErrorEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "requestPointerLock")) Module["requestPointerLock"] = function() { abort("'requestPointerLock' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillVisibilityChangeEventData")) Module["fillVisibilityChangeEventData"] = function() { abort("'fillVisibilityChangeEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerVisibilityChangeEventCallback")) Module["registerVisibilityChangeEventCallback"] = function() { abort("'registerVisibilityChangeEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerTouchEventCallback")) Module["registerTouchEventCallback"] = function() { abort("'registerTouchEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillGamepadEventData")) Module["fillGamepadEventData"] = function() { abort("'fillGamepadEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerGamepadEventCallback")) Module["registerGamepadEventCallback"] = function() { abort("'registerGamepadEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerBeforeUnloadEventCallback")) Module["registerBeforeUnloadEventCallback"] = function() { abort("'registerBeforeUnloadEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "fillBatteryEventData")) Module["fillBatteryEventData"] = function() { abort("'fillBatteryEventData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "battery")) Module["battery"] = function() { abort("'battery' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "registerBatteryEventCallback")) Module["registerBatteryEventCallback"] = function() { abort("'registerBatteryEventCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setCanvasElementSize")) Module["setCanvasElementSize"] = function() { abort("'setCanvasElementSize' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getCanvasElementSize")) Module["getCanvasElementSize"] = function() { abort("'getCanvasElementSize' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "polyfillSetImmediate")) Module["polyfillSetImmediate"] = function() { abort("'polyfillSetImmediate' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "demangle")) Module["demangle"] = function() { abort("'demangle' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "demangleAll")) Module["demangleAll"] = function() { abort("'demangleAll' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "jsStackTrace")) Module["jsStackTrace"] = function() { abort("'jsStackTrace' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getEnvStrings")) Module["getEnvStrings"] = function() { abort("'getEnvStrings' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "checkWasiClock")) Module["checkWasiClock"] = function() { abort("'checkWasiClock' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "flush_NO_FILESYSTEM")) Module["flush_NO_FILESYSTEM"] = function() { abort("'flush_NO_FILESYSTEM' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64")) Module["writeI53ToI64"] = function() { abort("'writeI53ToI64' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Clamped")) Module["writeI53ToI64Clamped"] = function() { abort("'writeI53ToI64Clamped' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Signaling")) Module["writeI53ToI64Signaling"] = function() { abort("'writeI53ToI64Signaling' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Clamped")) Module["writeI53ToU64Clamped"] = function() { abort("'writeI53ToU64Clamped' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Signaling")) Module["writeI53ToU64Signaling"] = function() { abort("'writeI53ToU64Signaling' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readI53FromI64")) Module["readI53FromI64"] = function() { abort("'readI53FromI64' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readI53FromU64")) Module["readI53FromU64"] = function() { abort("'readI53FromU64' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "convertI32PairToI53")) Module["convertI32PairToI53"] = function() { abort("'convertI32PairToI53' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "convertU32PairToI53")) Module["convertU32PairToI53"] = function() { abort("'convertU32PairToI53' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "uncaughtExceptionCount")) Module["uncaughtExceptionCount"] = function() { abort("'uncaughtExceptionCount' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "exceptionLast")) Module["exceptionLast"] = function() { abort("'exceptionLast' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "exceptionCaught")) Module["exceptionCaught"] = function() { abort("'exceptionCaught' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "ExceptionInfo")) Module["ExceptionInfo"] = function() { abort("'ExceptionInfo' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "CatchInfo")) Module["CatchInfo"] = function() { abort("'CatchInfo' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "exception_addRef")) Module["exception_addRef"] = function() { abort("'exception_addRef' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "exception_decRef")) Module["exception_decRef"] = function() { abort("'exception_decRef' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "Browser")) Module["Browser"] = function() { abort("'Browser' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "funcWrappers")) Module["funcWrappers"] = function() { abort("'funcWrappers' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "setMainLoop")) Module["setMainLoop"] = function() { abort("'setMainLoop' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "wget")) Module["wget"] = function() { abort("'wget' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "FS")) Module["FS"] = function() { abort("'FS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "MEMFS")) Module["MEMFS"] = function() { abort("'MEMFS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "TTY")) Module["TTY"] = function() { abort("'TTY' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "PIPEFS")) Module["PIPEFS"] = function() { abort("'PIPEFS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SOCKFS")) Module["SOCKFS"] = function() { abort("'SOCKFS' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "_setNetworkCallback")) Module["_setNetworkCallback"] = function() { abort("'_setNetworkCallback' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "tempFixedLengthArray")) Module["tempFixedLengthArray"] = function() { abort("'tempFixedLengthArray' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "miniTempWebGLFloatBuffers")) Module["miniTempWebGLFloatBuffers"] = function() { abort("'miniTempWebGLFloatBuffers' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "heapObjectForWebGLType")) Module["heapObjectForWebGLType"] = function() { abort("'heapObjectForWebGLType' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "heapAccessShiftForWebGLHeap")) Module["heapAccessShiftForWebGLHeap"] = function() { abort("'heapAccessShiftForWebGLHeap' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GL")) Module["GL"] = function() { abort("'GL' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGet")) Module["emscriptenWebGLGet"] = function() { abort("'emscriptenWebGLGet' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "computeUnpackAlignedImageSize")) Module["computeUnpackAlignedImageSize"] = function() { abort("'computeUnpackAlignedImageSize' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetTexPixelData")) Module["emscriptenWebGLGetTexPixelData"] = function() { abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetUniform")) Module["emscriptenWebGLGetUniform"] = function() { abort("'emscriptenWebGLGetUniform' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "webglGetUniformLocation")) Module["webglGetUniformLocation"] = function() { abort("'webglGetUniformLocation' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "webglPrepareUniformLocationsBeforeFirstUse")) Module["webglPrepareUniformLocationsBeforeFirstUse"] = function() { abort("'webglPrepareUniformLocationsBeforeFirstUse' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "webglGetLeftBracePos")) Module["webglGetLeftBracePos"] = function() { abort("'webglGetLeftBracePos' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetVertexAttrib")) Module["emscriptenWebGLGetVertexAttrib"] = function() { abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetBufferBinding")) Module["emscriptenWebGLGetBufferBinding"] = function() { abort("'emscriptenWebGLGetBufferBinding' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLValidateMapBufferTarget")) Module["emscriptenWebGLValidateMapBufferTarget"] = function() { abort("'emscriptenWebGLValidateMapBufferTarget' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeGLArray")) Module["writeGLArray"] = function() { abort("'writeGLArray' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "AL")) Module["AL"] = function() { abort("'AL' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SDL_unicode")) Module["SDL_unicode"] = function() { abort("'SDL_unicode' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SDL_ttfContext")) Module["SDL_ttfContext"] = function() { abort("'SDL_ttfContext' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SDL_audio")) Module["SDL_audio"] = function() { abort("'SDL_audio' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SDL")) Module["SDL"] = function() { abort("'SDL' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "SDL_gfx")) Module["SDL_gfx"] = function() { abort("'SDL_gfx' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GLUT")) Module["GLUT"] = function() { abort("'GLUT' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "EGL")) Module["EGL"] = function() { abort("'EGL' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GLFW_Window")) Module["GLFW_Window"] = function() { abort("'GLFW_Window' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GLFW")) Module["GLFW"] = function() { abort("'GLFW' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "GLEW")) Module["GLEW"] = function() { abort("'GLEW' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "IDBStore")) Module["IDBStore"] = function() { abort("'IDBStore' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runAndAbortIfError")) Module["runAndAbortIfError"] = function() { abort("'runAndAbortIfError' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetIndexed")) Module["emscriptenWebGLGetIndexed"] = function() { abort("'emscriptenWebGLGetIndexed' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "warnOnce")) Module["warnOnce"] = function() { abort("'warnOnce' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stackSave")) Module["stackSave"] = function() { abort("'stackSave' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stackRestore")) Module["stackRestore"] = function() { abort("'stackRestore' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stackAlloc")) Module["stackAlloc"] = function() { abort("'stackAlloc' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "AsciiToString")) Module["AsciiToString"] = function() { abort("'AsciiToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToAscii")) Module["stringToAscii"] = function() { abort("'stringToAscii' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "UTF16ToString")) Module["UTF16ToString"] = function() { abort("'UTF16ToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF16")) Module["stringToUTF16"] = function() { abort("'stringToUTF16' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF16")) Module["lengthBytesUTF16"] = function() { abort("'lengthBytesUTF16' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "UTF32ToString")) Module["UTF32ToString"] = function() { abort("'UTF32ToString' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF32")) Module["stringToUTF32"] = function() { abort("'stringToUTF32' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF32")) Module["lengthBytesUTF32"] = function() { abort("'lengthBytesUTF32' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8")) Module["allocateUTF8"] = function() { abort("'allocateUTF8' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8OnStack")) Module["allocateUTF8OnStack"] = function() { abort("'allocateUTF8OnStack' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "intArrayFromString")) Module["intArrayFromString"] = function() { abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "intArrayToString")) Module["intArrayToString"] = function() { abort("'intArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ccall")) Module["ccall"] = function() { abort("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "cwrap")) Module["cwrap"] = function() { abort("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setValue")) Module["setValue"] = function() { abort("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getValue")) Module["getValue"] = function() { abort("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "allocate")) Module["allocate"] = function() { abort("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "UTF8ArrayToString")) Module["UTF8ArrayToString"] = function() { abort("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "UTF8ToString")) Module["UTF8ToString"] = function() { abort("'UTF8ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8Array")) Module["stringToUTF8Array"] = function() { abort("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF8")) Module["stringToUTF8"] = function() { abort("'stringToUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF8")) Module["lengthBytesUTF8"] = function() { abort("'lengthBytesUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addOnPreRun")) Module["addOnPreRun"] = function() { abort("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addOnInit")) Module["addOnInit"] = function() { abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addOnPreMain")) Module["addOnPreMain"] = function() { abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addOnExit")) Module["addOnExit"] = function() { abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addOnPostRun")) Module["addOnPostRun"] = function() { abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeStringToMemory")) Module["writeStringToMemory"] = function() { abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeArrayToMemory")) Module["writeArrayToMemory"] = function() { abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeAsciiToMemory")) Module["writeAsciiToMemory"] = function() { abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addRunDependency")) Module["addRunDependency"] = function() { abort("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "removeRunDependency")) Module["removeRunDependency"] = function() { abort("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createFolder")) Module["FS_createFolder"] = function() { abort("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createPath")) Module["FS_createPath"] = function() { abort("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createDataFile")) Module["FS_createDataFile"] = function() { abort("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createPreloadedFile")) Module["FS_createPreloadedFile"] = function() { abort("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createLazyFile")) Module["FS_createLazyFile"] = function() { abort("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createLink")) Module["FS_createLink"] = function() { abort("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_createDevice")) Module["FS_createDevice"] = function() { abort("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS_unlink")) Module["FS_unlink"] = function() { abort("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
+if (!Object.getOwnPropertyDescriptor(Module, "getLEB")) Module["getLEB"] = function() { abort("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getFunctionTables")) Module["getFunctionTables"] = function() { abort("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "alignFunctionTables")) Module["alignFunctionTables"] = function() { abort("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerFunctions")) Module["registerFunctions"] = function() { abort("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "addFunction")) Module["addFunction"] = function() { abort("'addFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "removeFunction")) Module["removeFunction"] = function() { abort("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "prettyPrint")) Module["prettyPrint"] = function() { abort("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "makeBigInt")) Module["makeBigInt"] = function() { abort("'makeBigInt' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getCompilerSetting")) Module["getCompilerSetting"] = function() { abort("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "print")) Module["print"] = function() { abort("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "printErr")) Module["printErr"] = function() { abort("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getTempRet0")) Module["getTempRet0"] = function() { abort("'getTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setTempRet0")) Module["setTempRet0"] = function() { abort("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "callMain")) Module["callMain"] = function() { abort("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "abort")) Module["abort"] = function() { abort("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToNewUTF8")) Module["stringToNewUTF8"] = function() { abort("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setFileTime")) Module["setFileTime"] = function() { abort("'setFileTime' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscripten_realloc_buffer")) Module["emscripten_realloc_buffer"] = function() { abort("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ENV")) Module["ENV"] = function() { abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_CODES")) Module["ERRNO_CODES"] = function() { abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_MESSAGES")) Module["ERRNO_MESSAGES"] = function() { abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setErrNo")) Module["setErrNo"] = function() { abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "inetPton4")) Module["inetPton4"] = function() { abort("'inetPton4' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "inetNtop4")) Module["inetNtop4"] = function() { abort("'inetNtop4' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "inetPton6")) Module["inetPton6"] = function() { abort("'inetPton6' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "inetNtop6")) Module["inetNtop6"] = function() { abort("'inetNtop6' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "readSockaddr")) Module["readSockaddr"] = function() { abort("'readSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeSockaddr")) Module["writeSockaddr"] = function() { abort("'writeSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() { abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getHostByName")) Module["getHostByName"] = function() { abort("'getHostByName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GAI_ERRNO_MESSAGES")) Module["GAI_ERRNO_MESSAGES"] = function() { abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "Protocols")) Module["Protocols"] = function() { abort("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "Sockets")) Module["Sockets"] = function() { abort("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getRandomDevice")) Module["getRandomDevice"] = function() { abort("'getRandomDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "traverseStack")) Module["traverseStack"] = function() { abort("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "UNWIND_CACHE")) Module["UNWIND_CACHE"] = function() { abort("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "withBuiltinMalloc")) Module["withBuiltinMalloc"] = function() { abort("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgsArray")) Module["readAsmConstArgsArray"] = function() { abort("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "readAsmConstArgs")) Module["readAsmConstArgs"] = function() { abort("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "mainThreadEM_ASM")) Module["mainThreadEM_ASM"] = function() { abort("'mainThreadEM_ASM' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "jstoi_q")) Module["jstoi_q"] = function() { abort("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "jstoi_s")) Module["jstoi_s"] = function() { abort("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getExecutableName")) Module["getExecutableName"] = function() { abort("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "listenOnce")) Module["listenOnce"] = function() { abort("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "autoResumeAudioContext")) Module["autoResumeAudioContext"] = function() { abort("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "dynCallLegacy")) Module["dynCallLegacy"] = function() { abort("'dynCallLegacy' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getDynCaller")) Module["getDynCaller"] = function() { abort("'getDynCaller' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "callRuntimeCallbacks")) Module["callRuntimeCallbacks"] = function() { abort("'callRuntimeCallbacks' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepaliveCounter")) Module["runtimeKeepaliveCounter"] = function() { abort("'runtimeKeepaliveCounter' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "keepRuntimeAlive")) Module["keepRuntimeAlive"] = function() { abort("'keepRuntimeAlive' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePush")) Module["runtimeKeepalivePush"] = function() { abort("'runtimeKeepalivePush' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePop")) Module["runtimeKeepalivePop"] = function() { abort("'runtimeKeepalivePop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "callUserCallback")) Module["callUserCallback"] = function() { abort("'callUserCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "maybeExit")) Module["maybeExit"] = function() { abort("'maybeExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "formatString")) Module["formatString"] = function() { abort("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "PATH")) Module["PATH"] = function() { abort("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "PATH_FS")) Module["PATH_FS"] = function() { abort("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SYSCALLS")) Module["SYSCALLS"] = function() { abort("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "syscallMmap2")) Module["syscallMmap2"] = function() { abort("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "syscallMunmap")) Module["syscallMunmap"] = function() { abort("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getSocketFromFD")) Module["getSocketFromFD"] = function() { abort("'getSocketFromFD' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getSocketAddress")) Module["getSocketAddress"] = function() { abort("'getSocketAddress' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "JSEvents")) Module["JSEvents"] = function() { abort("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerKeyEventCallback")) Module["registerKeyEventCallback"] = function() { abort("'registerKeyEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "specialHTMLTargets")) Module["specialHTMLTargets"] = function() { abort("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "maybeCStringToJsString")) Module["maybeCStringToJsString"] = function() { abort("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "findEventTarget")) Module["findEventTarget"] = function() { abort("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "findCanvasEventTarget")) Module["findCanvasEventTarget"] = function() { abort("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getBoundingClientRect")) Module["getBoundingClientRect"] = function() { abort("'getBoundingClientRect' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillMouseEventData")) Module["fillMouseEventData"] = function() { abort("'fillMouseEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerMouseEventCallback")) Module["registerMouseEventCallback"] = function() { abort("'registerMouseEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerWheelEventCallback")) Module["registerWheelEventCallback"] = function() { abort("'registerWheelEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerUiEventCallback")) Module["registerUiEventCallback"] = function() { abort("'registerUiEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerFocusEventCallback")) Module["registerFocusEventCallback"] = function() { abort("'registerFocusEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillDeviceOrientationEventData")) Module["fillDeviceOrientationEventData"] = function() { abort("'fillDeviceOrientationEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerDeviceOrientationEventCallback")) Module["registerDeviceOrientationEventCallback"] = function() { abort("'registerDeviceOrientationEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillDeviceMotionEventData")) Module["fillDeviceMotionEventData"] = function() { abort("'fillDeviceMotionEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerDeviceMotionEventCallback")) Module["registerDeviceMotionEventCallback"] = function() { abort("'registerDeviceMotionEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "screenOrientation")) Module["screenOrientation"] = function() { abort("'screenOrientation' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillOrientationChangeEventData")) Module["fillOrientationChangeEventData"] = function() { abort("'fillOrientationChangeEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerOrientationChangeEventCallback")) Module["registerOrientationChangeEventCallback"] = function() { abort("'registerOrientationChangeEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillFullscreenChangeEventData")) Module["fillFullscreenChangeEventData"] = function() { abort("'fillFullscreenChangeEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerFullscreenChangeEventCallback")) Module["registerFullscreenChangeEventCallback"] = function() { abort("'registerFullscreenChangeEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerRestoreOldStyle")) Module["registerRestoreOldStyle"] = function() { abort("'registerRestoreOldStyle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "hideEverythingExceptGivenElement")) Module["hideEverythingExceptGivenElement"] = function() { abort("'hideEverythingExceptGivenElement' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "restoreHiddenElements")) Module["restoreHiddenElements"] = function() { abort("'restoreHiddenElements' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setLetterbox")) Module["setLetterbox"] = function() { abort("'setLetterbox' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "currentFullscreenStrategy")) Module["currentFullscreenStrategy"] = function() { abort("'currentFullscreenStrategy' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "restoreOldWindowedStyle")) Module["restoreOldWindowedStyle"] = function() { abort("'restoreOldWindowedStyle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "softFullscreenResizeWebGLRenderTarget")) Module["softFullscreenResizeWebGLRenderTarget"] = function() { abort("'softFullscreenResizeWebGLRenderTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "doRequestFullscreen")) Module["doRequestFullscreen"] = function() { abort("'doRequestFullscreen' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillPointerlockChangeEventData")) Module["fillPointerlockChangeEventData"] = function() { abort("'fillPointerlockChangeEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerPointerlockChangeEventCallback")) Module["registerPointerlockChangeEventCallback"] = function() { abort("'registerPointerlockChangeEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerPointerlockErrorEventCallback")) Module["registerPointerlockErrorEventCallback"] = function() { abort("'registerPointerlockErrorEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "requestPointerLock")) Module["requestPointerLock"] = function() { abort("'requestPointerLock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillVisibilityChangeEventData")) Module["fillVisibilityChangeEventData"] = function() { abort("'fillVisibilityChangeEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerVisibilityChangeEventCallback")) Module["registerVisibilityChangeEventCallback"] = function() { abort("'registerVisibilityChangeEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerTouchEventCallback")) Module["registerTouchEventCallback"] = function() { abort("'registerTouchEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillGamepadEventData")) Module["fillGamepadEventData"] = function() { abort("'fillGamepadEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerGamepadEventCallback")) Module["registerGamepadEventCallback"] = function() { abort("'registerGamepadEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerBeforeUnloadEventCallback")) Module["registerBeforeUnloadEventCallback"] = function() { abort("'registerBeforeUnloadEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "fillBatteryEventData")) Module["fillBatteryEventData"] = function() { abort("'fillBatteryEventData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "battery")) Module["battery"] = function() { abort("'battery' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "registerBatteryEventCallback")) Module["registerBatteryEventCallback"] = function() { abort("'registerBatteryEventCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setCanvasElementSize")) Module["setCanvasElementSize"] = function() { abort("'setCanvasElementSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getCanvasElementSize")) Module["getCanvasElementSize"] = function() { abort("'getCanvasElementSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "polyfillSetImmediate")) Module["polyfillSetImmediate"] = function() { abort("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "demangle")) Module["demangle"] = function() { abort("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "demangleAll")) Module["demangleAll"] = function() { abort("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "jsStackTrace")) Module["jsStackTrace"] = function() { abort("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stackTrace")) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getEnvStrings")) Module["getEnvStrings"] = function() { abort("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "checkWasiClock")) Module["checkWasiClock"] = function() { abort("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "flush_NO_FILESYSTEM")) Module["flush_NO_FILESYSTEM"] = function() { abort("'flush_NO_FILESYSTEM' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64")) Module["writeI53ToI64"] = function() { abort("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Clamped")) Module["writeI53ToI64Clamped"] = function() { abort("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToI64Signaling")) Module["writeI53ToI64Signaling"] = function() { abort("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Clamped")) Module["writeI53ToU64Clamped"] = function() { abort("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeI53ToU64Signaling")) Module["writeI53ToU64Signaling"] = function() { abort("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "readI53FromI64")) Module["readI53FromI64"] = function() { abort("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "readI53FromU64")) Module["readI53FromU64"] = function() { abort("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "convertI32PairToI53")) Module["convertI32PairToI53"] = function() { abort("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "convertU32PairToI53")) Module["convertU32PairToI53"] = function() { abort("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "uncaughtExceptionCount")) Module["uncaughtExceptionCount"] = function() { abort("'uncaughtExceptionCount' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "exceptionLast")) Module["exceptionLast"] = function() { abort("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "exceptionCaught")) Module["exceptionCaught"] = function() { abort("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ExceptionInfoAttrs")) Module["ExceptionInfoAttrs"] = function() { abort("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "ExceptionInfo")) Module["ExceptionInfo"] = function() { abort("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "CatchInfo")) Module["CatchInfo"] = function() { abort("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "exception_addRef")) Module["exception_addRef"] = function() { abort("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "exception_decRef")) Module["exception_decRef"] = function() { abort("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "Browser")) Module["Browser"] = function() { abort("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "funcWrappers")) Module["funcWrappers"] = function() { abort("'funcWrappers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "getFuncWrapper")) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "setMainLoop")) Module["setMainLoop"] = function() { abort("'setMainLoop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "FS")) Module["FS"] = function() { abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "mmapAlloc")) Module["mmapAlloc"] = function() { abort("'mmapAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "MEMFS")) Module["MEMFS"] = function() { abort("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "TTY")) Module["TTY"] = function() { abort("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "PIPEFS")) Module["PIPEFS"] = function() { abort("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SOCKFS")) Module["SOCKFS"] = function() { abort("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "_setNetworkCallback")) Module["_setNetworkCallback"] = function() { abort("'_setNetworkCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "tempFixedLengthArray")) Module["tempFixedLengthArray"] = function() { abort("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "miniTempWebGLFloatBuffers")) Module["miniTempWebGLFloatBuffers"] = function() { abort("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "heapObjectForWebGLType")) Module["heapObjectForWebGLType"] = function() { abort("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "heapAccessShiftForWebGLHeap")) Module["heapAccessShiftForWebGLHeap"] = function() { abort("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GL")) Module["GL"] = function() { abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGet")) Module["emscriptenWebGLGet"] = function() { abort("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "computeUnpackAlignedImageSize")) Module["computeUnpackAlignedImageSize"] = function() { abort("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetTexPixelData")) Module["emscriptenWebGLGetTexPixelData"] = function() { abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetUniform")) Module["emscriptenWebGLGetUniform"] = function() { abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetVertexAttrib")) Module["emscriptenWebGLGetVertexAttrib"] = function() { abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetBufferBinding")) Module["emscriptenWebGLGetBufferBinding"] = function() { abort("'emscriptenWebGLGetBufferBinding' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLValidateMapBufferTarget")) Module["emscriptenWebGLValidateMapBufferTarget"] = function() { abort("'emscriptenWebGLValidateMapBufferTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "writeGLArray")) Module["writeGLArray"] = function() { abort("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "AL")) Module["AL"] = function() { abort("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SDL_unicode")) Module["SDL_unicode"] = function() { abort("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SDL_ttfContext")) Module["SDL_ttfContext"] = function() { abort("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SDL_audio")) Module["SDL_audio"] = function() { abort("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SDL")) Module["SDL"] = function() { abort("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "SDL_gfx")) Module["SDL_gfx"] = function() { abort("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GLUT")) Module["GLUT"] = function() { abort("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "EGL")) Module["EGL"] = function() { abort("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GLFW_Window")) Module["GLFW_Window"] = function() { abort("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GLFW")) Module["GLFW"] = function() { abort("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "GLEW")) Module["GLEW"] = function() { abort("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "IDBStore")) Module["IDBStore"] = function() { abort("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runAndAbortIfError")) Module["runAndAbortIfError"] = function() { abort("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetIndexed")) Module["emscriptenWebGLGetIndexed"] = function() { abort("'emscriptenWebGLGetIndexed' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "warnOnce")) Module["warnOnce"] = function() { abort("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stackSave")) Module["stackSave"] = function() { abort("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stackRestore")) Module["stackRestore"] = function() { abort("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stackAlloc")) Module["stackAlloc"] = function() { abort("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "AsciiToString")) Module["AsciiToString"] = function() { abort("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToAscii")) Module["stringToAscii"] = function() { abort("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "UTF16ToString")) Module["UTF16ToString"] = function() { abort("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF16")) Module["stringToUTF16"] = function() { abort("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF16")) Module["lengthBytesUTF16"] = function() { abort("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "UTF32ToString")) Module["UTF32ToString"] = function() { abort("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "stringToUTF32")) Module["stringToUTF32"] = function() { abort("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "lengthBytesUTF32")) Module["lengthBytesUTF32"] = function() { abort("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8")) Module["allocateUTF8"] = function() { abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "allocateUTF8OnStack")) Module["allocateUTF8OnStack"] = function() { abort("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
Module["writeStackCookie"] = writeStackCookie;
Module["checkStackCookie"] = checkStackCookie;
-if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NORMAL")) Object.defineProperty(Module, "ALLOC_NORMAL", { configurable: true, get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
-if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_STACK")) Object.defineProperty(Module, "ALLOC_STACK", { configurable: true, get: function() { abort("'ALLOC_STACK' was not exported. add it to EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
+if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_NORMAL")) Object.defineProperty(Module, "ALLOC_NORMAL", { configurable: true, get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
+if (!Object.getOwnPropertyDescriptor(Module, "ALLOC_STACK")) Object.defineProperty(Module, "ALLOC_STACK", { configurable: true, get: function() { abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
var calledRun;
@@ -3315,25 +3253,25 @@ function callMain(args) {
// In PROXY_TO_PTHREAD builds, we should never exit the runtime below, as
// execution is asynchronously handed off to a pthread.
- // if we're not running an evented main loop, it's time to exit
- exit(ret, /* implicit = */ true);
- }
- catch (e) {
- // Certain exception types we do not treat as errors since they are used for
- // internal control flow.
- // 1. ExitStatus, which is thrown by exit()
- // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
- // that wish to return to JS event loop.
- if (e instanceof ExitStatus || e == 'unwind') {
+ // if we're not running an evented main loop, it's time to exit
+ exit(ret, /* implicit = */ true);
+ }
+ catch(e) {
+ if (e instanceof ExitStatus) {
+ // exit() throws this once it's done to make sure execution
+ // has been stopped completely
return;
+ } else if (e == 'unwind') {
+ // running an evented main loop, don't immediately exit
+ return;
+ } else {
+ var toLog = e;
+ if (e && typeof e === 'object' && e.stack) {
+ toLog = [e, e.stack];
+ }
+ err('exception thrown: ' + toLog);
+ quit_(1, e);
}
- // Anything else is an unexpected exception and we treat it as hard error.
- var toLog = e;
- if (e && typeof e === 'object' && e.stack) {
- toLog = [e, e.stack];
- }
- err('exception thrown: ' + toLog);
- quit_(1, e);
} finally {
calledMain = true;
@@ -3438,6 +3376,14 @@ function exit(status, implicit) {
checkUnflushedContent();
+ // if this is just main exit-ing implicitly, and the status is 0, then we
+ // don't need to do anything here and can just leave. if the status is
+ // non-zero, though, then we need to report it.
+ // (we may have warned about this earlier, if a situation justifies doing so)
+ if (implicit && keepRuntimeAlive() && status === 0) {
+ return;
+ }
+
if (keepRuntimeAlive()) {
// if exit() was called, we may warn the user if the runtime isn't actually being shut down
if (!implicit) {
@@ -3445,19 +3391,15 @@ function exit(status, implicit) {
err(msg);
}
} else {
+
exitRuntime();
- }
- procExit(status);
-}
+ if (Module['onExit']) Module['onExit'](status);
-function procExit(code) {
- EXITSTATUS = code;
- if (!keepRuntimeAlive()) {
- if (Module['onExit']) Module['onExit'](code);
ABORT = true;
}
- quit_(code, new ExitStatus(code));
+
+ quit_(status, new ExitStatus(status));
}
if (Module['preInit']) {
diff --git a/2d/softbody/softbody_1/dist/output.wasm b/2d/softbody/softbody_1/dist/output.wasm
index a0646b3..9c47c47 100755
--- a/2d/softbody/softbody_1/dist/output.wasm
+++ b/2d/softbody/softbody_1/dist/output.wasm
Binary files differ
diff --git a/2d/softbody/softbody_1/main.cpp b/2d/softbody/softbody_1/main.cpp
index 0b04426..33a2c77 100644
--- a/2d/softbody/softbody_1/main.cpp
+++ b/2d/softbody/softbody_1/main.cpp
@@ -1,228 +1,17 @@
-#include "../../../shared_cpp/Renderer2d.h"
-#include "../../../shared_cpp/types.h"
+#include "undamped.h"
+#include "damped.h"
#include "../../../shared_cpp/WebglContext.h"
-#include "../../../shared_cpp/mathlib.h"
-#include "../../../shared_cpp/MainLoop.h"
-#include <cstdio>
-#include <cmath>
-#include <emscripten/html5.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <cmath>
-#include <cfloat>
-
-struct MassSpringVertex {
-
-};
-
-struct MassSpringBody {
-
-};
-
-struct SpringWeight {
- Mesh2d shape;
- float32 radius;
- float32 mass = 2.f;
-
- void load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor);
- void update(float32 dtSeconds);
- void render(Renderer2d* renderer);
- void unload();
-};
-
-struct Spring {
- SpringWeight* weight;
-
- Mesh2d shape;
-
- Vertex2d* vertices = NULL;
- int32 numSegments = 0;
- int32 numVertices = 0;
- float32 k = 5; // Spring Constant, in N / m
- float32 angularVelocity = 0.f; // To be calculated
- float32 displacement = 0.f;
- float32 timeElapsed = 0.f;
-
- void load(Renderer2d* renderer, SpringWeight* inWieight, float32 length, float32 loopRadius);
- void update(float32 dtSeconds);
- void render(Renderer2d* renderer);
- void unload();
-};
-
-EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
-EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
-
-void load();
-void update(float32 time, void* userData);
-void unload();
WebglContext context;
-Renderer2d renderer;
-MainLoop mainLoop;
-SpringWeight weight;
-Spring spring;
int main() {
- context.init("#gl_canvas");
- emscripten_set_click_callback("#gl_canvas_play", NULL, false, onPlayClicked);
- emscripten_set_click_callback("#gl_canvas_stop", NULL, false, onStopClicked);
+ Damped::init(&context);
+ Undamped::init(&context);
return 0;
}
-void load() {
- renderer.load(&context);
-
- weight.load(&renderer, 32.f, Vector4 { 55.f, 235.f, 35.f, 255.f }, Vector4 { 235.f, 5.f, 235.f, 255.f });
- spring.load(&renderer, &weight, 100.f, 16.f);
-
- mainLoop.run(update);
-}
-
-void update(float32 deltaTimeSeconds, void* userData) {
- // -- Update
- spring.update(deltaTimeSeconds);
- weight.update(deltaTimeSeconds);
-
- // -- Render
- renderer.render();
- weight.render(&renderer);
- spring.render(&renderer);
-}
-
-void unload() {
- mainLoop.stop();
- renderer.unload();
- weight.unload();
- spring.unload();
-}
//
// Interactions with DOM handled below
//
-EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
- printf("Play clicked\n");
-
- load();
- return true;
-}
-
-EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
- printf("Stop clicked\n");
- unload();
- return true;
-}
-
-
-void SpringWeight::load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
- radius = inRadius;
- const int32 numSegments = 96;
- const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
- const int32 numVertices = numSegments * 3;
-
- float32 t = 0.f;
- float32 tIncrement = 1.f / (numSegments / 2.f);
- startColor = startColor.toNormalizedColor();
- endColor = endColor.toNormalizedColor();
- Vertex2d vertices[numVertices];
- for (int idx = 0; idx < numSegments; idx++) {
- int vIdx = idx * 3;
-
- Vector4 color = lerp(startColor, endColor, t);
- if (idx >= numSegments / 2) {
- t -= tIncrement;
- } else {
- t += tIncrement;
- }
-
- vertices[vIdx].color = color;
- vertices[vIdx].position = Vector2 { radius * cosf(radiansPerSegment * idx), radius * sinf(radiansPerSegment * idx) };
- vertices[vIdx + 1].color = color;
- vertices[vIdx + 1].position = Vector2 { 0.f, 0.f };
- vertices[vIdx + 2].color = color;
- vertices[vIdx + 2].position = Vector2 { radius * cosf(radiansPerSegment * (idx + 1)), radius * sinf(radiansPerSegment * (idx + 1)) };
- }
-
- shape.load(vertices, numVertices, renderer);
-}
-
-void SpringWeight::update(float32 dtSeconds) {
-
-}
-
-void SpringWeight::render(Renderer2d* renderer) {
- shape.render(renderer);
-}
-
-void SpringWeight::unload() {
- shape.unload();
-}
-
-void Spring::load(Renderer2d* renderer, SpringWeight* inWeight, float32 length, float32 loopRadius) {
- weight = inWeight;
- angularVelocity = sqrtf(k / weight->mass);
- timeElapsed = 0.f;
-
- const int32 verticesPerSegment = 6;
- numSegments = 256;
- numVertices = numSegments * verticesPerSegment;
- vertices = new Vertex2d[numVertices];
-
- float32 lengthIncrement = length / static_cast<float32>(numSegments);
-
- const float32 frequency = 0.25f;
- const float32 loopWidth = 20.f;
- const float32 offset = 0.25f;
-
- int32 vidx = 0;
- for (int pidx = 0; pidx < numSegments; pidx++) {
- float32 y1 = lengthIncrement * pidx;
- float32 x1 = loopWidth * sinf(frequency * y1 + offset);
-
- float32 y2 = y1 + lengthIncrement;
- float32 x2 = loopWidth * sinf(frequency * y2 + offset);
-
- vertices[vidx++].position = Vector2(x1, y1);
- vertices[vidx++].position = Vector2(x1, y2);
- vertices[vidx++].position = Vector2(x2, y1);
- vertices[vidx++].position = Vector2(x2, y1);
- vertices[vidx++].position = Vector2(x1, y2);
- vertices[vidx++].position = Vector2(x2, y2);
- }
-
- shape.load(vertices, numVertices, renderer, GL_DYNAMIC_DRAW);
- shape.model = Mat4x4().translateByVec2(Vector2(400, 300));
-
- weight->shape.model = shape.model.translateByVec2(Vector2(0, -weight->radius));
-}
-
-void Spring::update(float32 dtSeconds) {
- timeElapsed += dtSeconds;
- displacement = 2 * cosf(angularVelocity * timeElapsed);
-
- int32 vidx = 0;
- for (int pidx = 0; pidx < numSegments; pidx++) {
- float32 y1Offset = displacement * (1.f - pidx / static_cast<float32>(numSegments));
- float32 y2Offset = displacement * (1.f - (pidx + 1) / static_cast<float32>(numSegments));
- vertices[vidx++].position.y += y1Offset;
- vertices[vidx++].position.y += y2Offset;
- vertices[vidx++].position.y += y1Offset;
- vertices[vidx++].position.y += y1Offset;
- vertices[vidx++].position.y += y2Offset;
- vertices[vidx++].position.y += y2Offset;
- }
-
- weight->shape.model = weight->shape.model.translateByVec2(Vector2(0, displacement));
-}
-
-void Spring::render(Renderer2d* renderer) {
- glBindBuffer(GL_ARRAY_BUFFER, shape.vbo);
- glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(Vertex2d), &vertices[0]);
-
- shape.render(renderer);
-}
-
-void Spring::unload() {
- shape.unload();
- delete[] vertices;
-}
diff --git a/2d/softbody/softbody_1/undamped.cpp b/2d/softbody/softbody_1/undamped.cpp
new file mode 100644
index 0000000..ec53f50
--- /dev/null
+++ b/2d/softbody/softbody_1/undamped.cpp
@@ -0,0 +1,227 @@
+#include "undamped.h"
+#include "../../../shared_cpp/Renderer2d.h"
+#include "../../../shared_cpp/types.h"
+#include "../../../shared_cpp/WebglContext.h"
+#include "../../../shared_cpp/mathlib.h"
+#include "../../../shared_cpp/MainLoop.h"
+#include <cstdio>
+#include <cmath>
+#include <emscripten/html5.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <cmath>
+#include <cfloat>
+
+namespace Undamped {
+
+ struct SpringWeight {
+ Mesh2d shape;
+ float32 radius;
+ float32 mass = 2.f;
+
+ void load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ struct Spring {
+ SpringWeight* weight;
+
+ Mesh2d shape;
+
+ Vertex2d* vertices = NULL;
+ int32 numSegments = 0;
+ int32 numVertices = 0;
+ float32 k = 4; // Spring Constant, in N / m
+ float32 initialDisplacement = 3.f;
+ float32 initialVelocity = 0.f;
+ float32 angularVelocity = 0.f; // To be calculated
+ float32 displacement = 0.f;
+ float32 timeElapsed = 0.f;
+
+ void load(Renderer2d* renderer, SpringWeight* inWieight, float32 length, float32 loopRadius);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ WebglContext* context;
+ Renderer2d renderer;
+ MainLoop mainLoop;
+ SpringWeight weight;
+ Spring spring;
+
+ EM_BOOL onUndampedPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ EM_BOOL onUndampedStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ void load();
+ void update(float32 deltaTimeSeconds, void* userData);
+ void unload();
+
+ void init(WebglContext* inContext) {
+ context = inContext;
+ emscripten_set_click_callback("#gl_canvas_play_undamped", NULL, false, onUndampedPlayClicked);
+ emscripten_set_click_callback("#gl_canvas_stop_undamped", NULL, false, onUndampedStopClicked);
+ }
+
+ void load() {
+ context->init("#gl_canvas_undamped");
+
+ renderer.load(context);
+
+ weight.load(&renderer, 32.f, Vector4 { 55.f, 235.f, 35.f, 255.f }, Vector4 { 235.f, 5.f, 235.f, 255.f });
+ spring.load(&renderer, &weight, 250.f, 64.f);
+
+ mainLoop.run(update);
+ }
+
+ void update(float32 deltaTimeSeconds, void* userData) {
+ // -- Update
+ spring.update(deltaTimeSeconds);
+ weight.update(deltaTimeSeconds);
+
+ // -- Render
+ renderer.render();
+ weight.render(&renderer);
+ spring.render(&renderer);
+ }
+
+ void unload() {
+ mainLoop.stop();
+ renderer.unload();
+ weight.unload();
+ spring.unload();
+
+ context->destroy();
+ }
+
+
+ void SpringWeight::load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
+ radius = inRadius;
+ const int32 numSegments = 96;
+ const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
+ const int32 numVertices = numSegments * 3;
+
+ float32 t = 0.f;
+ float32 tIncrement = 1.f / (numSegments / 2.f);
+ startColor = startColor.toNormalizedColor();
+ endColor = endColor.toNormalizedColor();
+
+ Vertex2d vertices[numVertices];
+ for (int idx = 0; idx < numSegments; idx++) {
+ int vIdx = idx * 3;
+
+ Vector4 color = lerp(startColor, endColor, t);
+ if (idx >= numSegments / 2) {
+ t -= tIncrement;
+ } else {
+ t += tIncrement;
+ }
+
+ vertices[vIdx].color = color;
+ vertices[vIdx].position = Vector2 { radius * cosf(radiansPerSegment * idx), radius * sinf(radiansPerSegment * idx) };
+ vertices[vIdx + 1].color = color;
+ vertices[vIdx + 1].position = Vector2 { 0.f, 0.f };
+ vertices[vIdx + 2].color = color;
+ vertices[vIdx + 2].position = Vector2 { radius * cosf(radiansPerSegment * (idx + 1)), radius * sinf(radiansPerSegment * (idx + 1)) };
+ }
+
+ shape.load(vertices, numVertices, renderer);
+ }
+
+ void SpringWeight::update(float32 dtSeconds) {
+
+ }
+
+ void SpringWeight::render(Renderer2d* renderer) {
+ shape.render(renderer);
+ }
+
+ void SpringWeight::unload() {
+ shape.unload();
+ }
+
+ void Spring::load(Renderer2d* renderer, SpringWeight* inWeight, float32 length, float32 loopRadius) {
+ weight = inWeight;
+ angularVelocity = sqrtf(k / weight->mass);
+ timeElapsed = 0.f;
+
+ const int32 verticesPerSegment = 6;
+ numSegments = 256;
+ numVertices = numSegments * verticesPerSegment;
+ vertices = new Vertex2d[numVertices];
+
+ float32 lengthIncrement = length / static_cast<float32>(numSegments);
+
+ const float32 frequency = 0.25f;
+ const float32 loopWidth = 20.f;
+ const float32 offset = 0.25f;
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1 = lengthIncrement * pidx;
+ float32 x1 = loopWidth * sinf(frequency * y1 + offset);
+
+ float32 y2 = y1 + lengthIncrement;
+ float32 x2 = loopWidth * sinf(frequency * y2 + offset);
+
+ vertices[vidx++].position = Vector2(x1, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y2);
+ }
+
+ shape.load(vertices, numVertices, renderer, GL_DYNAMIC_DRAW);
+ shape.model = Mat4x4().translateByVec2(Vector2(400, 300));
+
+ weight->shape.model = shape.model.translateByVec2(Vector2(0, -weight->radius));
+ }
+
+ void Spring::update(float32 dtSeconds) {
+ timeElapsed += dtSeconds;
+ displacement = initialDisplacement * cosf(angularVelocity * timeElapsed - initialVelocity);
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1Offset = displacement * (1.f - pidx / static_cast<float32>(numSegments));
+ float32 y2Offset = displacement * (1.f - (pidx + 1) / static_cast<float32>(numSegments));
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y2Offset;
+ }
+
+ weight->shape.model = weight->shape.model.translateByVec2(Vector2(0, displacement));
+ }
+
+ void Spring::render(Renderer2d* renderer) {
+ glBindBuffer(GL_ARRAY_BUFFER, shape.vbo);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(Vertex2d), &vertices[0]);
+
+ shape.render(renderer);
+ }
+
+ void Spring::unload() {
+ shape.unload();
+ delete[] vertices;
+ }
+
+
+ EM_BOOL onUndampedPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Play clicked\n");
+
+ load();
+ return true;
+ }
+
+ EM_BOOL onUndampedStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Stop clicked\n");
+ unload();
+ return true;
+ }
+
+}
diff --git a/2d/softbody/softbody_1/undamped.h b/2d/softbody/softbody_1/undamped.h
new file mode 100644
index 0000000..a87e446
--- /dev/null
+++ b/2d/softbody/softbody_1/undamped.h
@@ -0,0 +1,8 @@
+#pragma once
+
+struct WebglContext;
+
+namespace Undamped {
+ void init(WebglContext* inContext);
+}
+