summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2d/_collisions/pill_line/main.cpp20
-rw-r--r--2d/_collisions/pill_pill/main.cpp12
-rw-r--r--2d/_collisions/polygon_polygon.html2
-rw-r--r--2d/_collisions/polygon_polygon/main.cpp12
-rw-r--r--2d/_collisions/rectangle_line/main.cpp20
-rw-r--r--2d/_collisions/rectangle_rectangle.html2
-rw-r--r--2d/_collisions/rectangle_rectangle/main.cpp12
-rw-r--r--2d/rigidbody/rigidbody_1.html2
-rw-r--r--2d/rigidbody/rigidbody_1/main.cpp20
-rw-r--r--2d/rigidbody/rigidbody_2.html2
-rw-r--r--2d/rigidbody/rigidbody_2/main.cpp20
-rw-r--r--2d/rigidbody/rigidbody_3.html2
-rw-r--r--2d/rigidbody/rigidbody_3/main.cpp12
-rw-r--r--2d/softbody/softbody_1.html94
-rw-r--r--2d/softbody/softbody_1.html.content45
-rwxr-xr-x2d/softbody/softbody_1/build.sh16
-rw-r--r--2d/softbody/softbody_1/dist/output.js3480
-rwxr-xr-x2d/softbody/softbody_1/dist/output.wasmbin0 -> 44089 bytes
-rw-r--r--2d/softbody/softbody_1/main.cpp228
-rw-r--r--3d/rigidbody.html10
-rw-r--r--3d/rigidbody.html.content8
-rw-r--r--_wasm/intro/intro.cpp10
-rw-r--r--index.html2
-rw-r--r--roadmap.html2
-rw-r--r--shared_cpp/Renderer2d.cpp (renamed from shared_cpp/OrthographicRenderer.cpp)22
-rw-r--r--shared_cpp/Renderer2d.h (renamed from shared_cpp/OrthographicRenderer.h)12
-rw-r--r--shared_cpp/WebglHelper.h4
-rw-r--r--shared_cpp/mathlib.cpp11
-rw-r--r--shared_cpp/mathlib.h4
-rw-r--r--tools/transpiler/pages.txt2
30 files changed, 3996 insertions, 92 deletions
diff --git a/2d/_collisions/pill_line/main.cpp b/2d/_collisions/pill_line/main.cpp
index b9315a8..65687ba 100644
--- a/2d/_collisions/pill_line/main.cpp
+++ b/2d/_collisions/pill_line/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -54,7 +54,7 @@ struct Rigidbody {
};
struct Pill {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
float32 a = 0;
float32 b = 0;
@@ -68,7 +68,7 @@ struct Pill {
return retval;
}
- void load(OrthographicRenderer* renderer, float32 numSegments, float32 width, float32 height) {
+ void load(Renderer2d* renderer, float32 numSegments, float32 width, float32 height) {
// Note that a so-called "pill" is simply an ellipse.
// Equation of an ellipse is:
//
@@ -80,7 +80,7 @@ struct Pill {
//
float32 angleIncrements = (2.f * PI) / numSegments;
uint32 numVertices = static_cast<uint32>(numSegments * 3.f);
- OrthographicVertex* vertices = new OrthographicVertex[numVertices];
+ Vertex2d* vertices = new Vertex2d[numVertices];
a = width / 2.f;
b = height / 2.f;
@@ -119,7 +119,7 @@ struct Pill {
shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -129,15 +129,15 @@ struct Pill {
};
struct LineSegment {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 start;
Vector2 end;
float32 length;
Vector2 normal;
- OrthographicVertex vertices[2];
+ Vertex2d vertices[2];
- void load(OrthographicRenderer* renderer, Vector4 color, Vector2 inStart, Vector2 inEnd) {
+ void load(Renderer2d* renderer, Vector4 color, Vector2 inStart, Vector2 inEnd) {
start = inStart;
end = inEnd;
length = (start - end).length();
@@ -156,7 +156,7 @@ struct LineSegment {
body.momentOfInertia = body.mass * (length / 2.f);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer, GL_LINES);
}
@@ -195,7 +195,7 @@ void resolveCollision(Rigidbody* first, Rigidbody* second, IntersectionResult* i
// Global Variables
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
Pill pill;
MainLoop mainLoop;
LineSegment segmentList[4];
diff --git a/2d/_collisions/pill_pill/main.cpp b/2d/_collisions/pill_pill/main.cpp
index 1aef594..7802a5d 100644
--- a/2d/_collisions/pill_pill/main.cpp
+++ b/2d/_collisions/pill_pill/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -59,7 +59,7 @@ struct PillInData {
};
struct Pill {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
float32 a = 0;
float32 b = 0;
@@ -73,10 +73,10 @@ struct Pill {
return retval;
}
- void load(OrthographicRenderer* renderer, PillInData data) {
+ void load(Renderer2d* renderer, PillInData data) {
float32 angleIncrements = (2.f * PI) / data.numSegments;
uint32 numVertices = static_cast<uint32>(data.numSegments * 3.f);
- OrthographicVertex* vertices = new OrthographicVertex[numVertices];
+ Vertex2d* vertices = new Vertex2d[numVertices];
a = data.width / 2.f;
b = data.height / 2.f;
@@ -112,7 +112,7 @@ struct Pill {
shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -141,7 +141,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
Pill pillList[2];
diff --git a/2d/_collisions/polygon_polygon.html b/2d/_collisions/polygon_polygon.html
index da5edea..75dbcfd 100644
--- a/2d/_collisions/polygon_polygon.html
+++ b/2d/_collisions/polygon_polygon.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/2d/_collisions/polygon_polygon/main.cpp b/2d/_collisions/polygon_polygon/main.cpp
index 9cb3eb2..3d8561f 100644
--- a/2d/_collisions/polygon_polygon/main.cpp
+++ b/2d/_collisions/polygon_polygon/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -112,7 +112,7 @@ struct Edge {
};
struct ConvexPolygon {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Rigidbody previousBody;
Vector4 color;
@@ -123,7 +123,7 @@ struct ConvexPolygon {
Vector2* transformedVertices;
Edge* edges;
- void load(OrthographicRenderer* renderer) {
+ void load(Renderer2d* renderer) {
transformedVertices = new Vector2[numVertices]; // This will be used for SAT calculations later
originalVertices = new Vector2[numVertices];
@@ -134,7 +134,7 @@ struct ConvexPolygon {
// is the 2k lines of JavaScript that are required to display it.
int32 verticesNeeded = numVertices * 3;
float32 angleIncrements = (2.f * PI) / static_cast<float32>(numVertices);
- OrthographicVertex* shaderVertices = new OrthographicVertex[verticesNeeded];
+ Vertex2d* shaderVertices = new Vertex2d[verticesNeeded];
for (int32 vidx = 0; vidx < numVertices; vidx++) {
int32 indexPosition = vidx * 3;
@@ -186,7 +186,7 @@ struct ConvexPolygon {
body = previousBody;
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -213,7 +213,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
ConvexPolygon polygons[4];
diff --git a/2d/_collisions/rectangle_line/main.cpp b/2d/_collisions/rectangle_line/main.cpp
index 25e124c..49ce7d7 100644
--- a/2d/_collisions/rectangle_line/main.cpp
+++ b/2d/_collisions/rectangle_line/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -60,13 +60,13 @@ struct IntersectionResult {
};
struct Rectangle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector4 color;
float32 width = 0.f;
float32 height = 0.f;
- void load(OrthographicRenderer* renderer, Vector4 inColor, float32 inWidth, float32 inHeight) {
+ void load(Renderer2d* renderer, Vector4 inColor, float32 inWidth, float32 inHeight) {
color = inColor.toNormalizedColor();
width = inWidth;;
height = inHeight;
@@ -74,7 +74,7 @@ struct Rectangle {
float32 halfWidth = width / 2.f;
float32 halfHeight = height / 2.f;
- OrthographicVertex vertices[6];
+ Vertex2d vertices[6];
vertices[0].position = Vector2 { -halfWidth, -halfHeight };
vertices[1].position = Vector2 { -halfWidth, halfHeight };
vertices[2].position = Vector2 { halfWidth, halfHeight };
@@ -96,7 +96,7 @@ struct Rectangle {
shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -106,15 +106,15 @@ struct Rectangle {
};
struct LineSegment {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 start;
Vector2 end;
float32 length;
Vector2 normal;
- OrthographicVertex vertices[2];
+ Vertex2d vertices[2];
- void load(OrthographicRenderer* renderer, Vector4 color, Vector2 inStart, Vector2 inEnd) {
+ void load(Renderer2d* renderer, Vector4 color, Vector2 inStart, Vector2 inEnd) {
start = inStart;
end = inEnd;
length = (start - end).length();
@@ -133,7 +133,7 @@ struct LineSegment {
body.momentOfInertia = body.mass * (length / 2.f);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer, GL_LINES);
}
@@ -161,7 +161,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
LineSegment segmentList[4];
Rectangle rectangle;
diff --git a/2d/_collisions/rectangle_rectangle.html b/2d/_collisions/rectangle_rectangle.html
index d5c407a..75c2e62 100644
--- a/2d/_collisions/rectangle_rectangle.html
+++ b/2d/_collisions/rectangle_rectangle.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/2d/_collisions/rectangle_rectangle/main.cpp b/2d/_collisions/rectangle_rectangle/main.cpp
index 6913749..3cd4f46 100644
--- a/2d/_collisions/rectangle_rectangle/main.cpp
+++ b/2d/_collisions/rectangle_rectangle/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -67,14 +67,14 @@ struct Edge {
};
struct Rectangle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Rigidbody previousBody;
Vector4 color;
float32 width = 0.f;
float32 height = 0.f;
- void load(OrthographicRenderer* renderer, Vector4 inColor, float32 inWidth, float32 inHeight) {
+ void load(Renderer2d* renderer, Vector4 inColor, float32 inWidth, float32 inHeight) {
color = inColor.toNormalizedColor();
width = inWidth;;
height = inHeight;
@@ -82,7 +82,7 @@ struct Rectangle {
float32 halfWidth = width / 2.f;
float32 halfHeight = height / 2.f;
- OrthographicVertex vertices[6];
+ Vertex2d vertices[6];
vertices[0].position = Vector2 { -halfWidth, -halfHeight };
vertices[1].position = Vector2 { -halfWidth, halfHeight };
vertices[2].position = Vector2 { halfWidth, halfHeight };
@@ -106,7 +106,7 @@ struct Rectangle {
shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -169,7 +169,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
Rectangle rectangleList[4];
diff --git a/2d/rigidbody/rigidbody_1.html b/2d/rigidbody/rigidbody_1.html
index 62e4bf6..153e443 100644
--- a/2d/rigidbody/rigidbody_1.html
+++ b/2d/rigidbody/rigidbody_1.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_1/main.cpp b/2d/rigidbody/rigidbody_1/main.cpp
index a327fee..c8a3cb4 100644
--- a/2d/rigidbody/rigidbody_1/main.cpp
+++ b/2d/rigidbody/rigidbody_1/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -85,18 +85,18 @@ struct Rigidbody {
};
struct Rectangle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 originalPoints[4];
Vector2 transformedPoints[4];
- void load(OrthographicRenderer* renderer, Vector4 color, float32 width, float32 height) {
+ void load(Renderer2d* renderer, Vector4 color, float32 width, float32 height) {
color = color.toNormalizedColor();
float32 halfWidth = width / 2.f;
float32 halfHeight = height / 2.f;
- OrthographicVertex vertices[6];
+ Vertex2d vertices[6];
vertices[0].position = Vector2 { -halfWidth, -halfHeight };
vertices[1].position = Vector2 { -halfWidth, halfHeight };
vertices[2].position = Vector2 { halfWidth, halfHeight };
@@ -128,7 +128,7 @@ struct Rectangle {
}
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -138,20 +138,20 @@ struct Rectangle {
};
struct Circle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 force;
float32 radius = 5.f;
- void load(OrthographicRenderer* renderer, Vector4 color) {
+ void load(Renderer2d* renderer, Vector4 color) {
const int32 numSegments = 36;
const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
const int32 numVertices = numSegments * 3;
color = color.toNormalizedColor();
- OrthographicVertex vertices[numSegments * 3];
+ Vertex2d vertices[numSegments * 3];
for (int idx = 0; idx < numSegments; idx++) {
int vIdx = idx * 3;
@@ -171,7 +171,7 @@ struct Circle {
shape.model = Mat4x4().translateByVec2(body.position);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -189,7 +189,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
Rectangle rectangle;
Circle pointer;
diff --git a/2d/rigidbody/rigidbody_2.html b/2d/rigidbody/rigidbody_2.html
index 2378a7e..f24666c 100644
--- a/2d/rigidbody/rigidbody_2.html
+++ b/2d/rigidbody/rigidbody_2.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_2/main.cpp b/2d/rigidbody/rigidbody_2/main.cpp
index 44a3c53..cae18a5 100644
--- a/2d/rigidbody/rigidbody_2/main.cpp
+++ b/2d/rigidbody/rigidbody_2/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -100,18 +100,18 @@ struct Rigidbody {
};
struct Rectangle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 originalPoints[4];
Vector2 transformedPoints[4];
- void load(OrthographicRenderer* renderer, Vector4 color, float32 width, float32 height) {
+ void load(Renderer2d* renderer, Vector4 color, float32 width, float32 height) {
color = color.toNormalizedColor();
float32 halfWidth = width / 2.f;
float32 halfHeight = height / 2.f;
- OrthographicVertex vertices[6];
+ Vertex2d vertices[6];
vertices[0].position = Vector2 { -halfWidth, -halfHeight };
vertices[1].position = Vector2 { -halfWidth, halfHeight };
vertices[2].position = Vector2 { halfWidth, halfHeight };
@@ -145,7 +145,7 @@ struct Rectangle {
}
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -155,20 +155,20 @@ struct Rectangle {
};
struct Circle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Vector2 force;
float32 radius = 5.f;
- void load(OrthographicRenderer* renderer, Vector4 color) {
+ void load(Renderer2d* renderer, Vector4 color) {
const int32 numSegments = 36;
const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
const int32 numVertices = numSegments * 3;
color = color.toNormalizedColor();
- OrthographicVertex vertices[numSegments * 3];
+ Vertex2d vertices[numSegments * 3];
for (int idx = 0; idx < numSegments; idx++) {
int vIdx = idx * 3;
@@ -188,7 +188,7 @@ struct Circle {
shape.model = Mat4x4().translateByVec2(body.position);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -206,7 +206,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
Rectangle rectangle;
Circle pointer;
diff --git a/2d/rigidbody/rigidbody_3.html b/2d/rigidbody/rigidbody_3.html
index 052c6b1..ed07bbb 100644
--- a/2d/rigidbody/rigidbody_3.html
+++ b/2d/rigidbody/rigidbody_3.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/2d/rigidbody/rigidbody_3/main.cpp b/2d/rigidbody/rigidbody_3/main.cpp
index 2a0af24..7d3edd0 100644
--- a/2d/rigidbody/rigidbody_3/main.cpp
+++ b/2d/rigidbody/rigidbody_3/main.cpp
@@ -1,4 +1,4 @@
-#include "../../../shared_cpp/OrthographicRenderer.h"
+#include "../../../shared_cpp/Renderer2d.h"
#include "../../../shared_cpp/types.h"
#include "../../../shared_cpp/WebglContext.h"
#include "../../../shared_cpp/mathlib.h"
@@ -100,13 +100,13 @@ struct Rigidbody {
};
struct Circle {
- OrthographicShape shape;
+ Mesh2d shape;
Rigidbody body;
Rigidbody previousBody;
Vector2 force;
float32 radius;
- void load(OrthographicRenderer* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
+ void load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
radius = inRadius;
const int32 numSegments = 36;
const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
@@ -115,7 +115,7 @@ struct Circle {
startColor = startColor.toNormalizedColor();
endColor = endColor.toNormalizedColor();
- OrthographicVertex vertices[numSegments * 3];
+ Vertex2d vertices[numSegments * 3];
for (int idx = 0; idx < numSegments; idx++) {
int vIdx = idx * 3;
@@ -146,7 +146,7 @@ struct Circle {
body.update(dtSeconds);
}
- void render(OrthographicRenderer* renderer) {
+ void render(Renderer2d* renderer) {
shape.render(renderer);
}
@@ -175,7 +175,7 @@ void update(float32 time, void* userData);
void unload();
WebglContext context;
-OrthographicRenderer renderer;
+Renderer2d renderer;
MainLoop mainLoop;
Circle c1;
Circle c2;
diff --git a/2d/softbody/softbody_1.html b/2d/softbody/softbody_1.html
new file mode 100644
index 0000000..b505f1b
--- /dev/null
+++ b/2d/softbody/softbody_1.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="/index.css">
+ <title>Physics for Games</title>
+ <link rel="shortcut icon" href="/favicon/favicon.ico" type="image/x-icon">
+ <meta name="description" content="A place to learn all about real-time physics simulations through descriptions, code snippets, and example programs all written in C++ and OpenGL.">
+ <meta name="og:description" content="A place to learn all about real-time physics simulations through descriptions, code snippets, and example programs all written in C++ and OpenGL.">
+ </head>
+ <body>
+ <header>
+ <h1><a title="physicsforgames.com" href="/">Physics for Games</a></h1>
+ </header>
+ <main>
+ <nav>
+ <ul class="outer-tree">
+ <li><a href="/">Introduction</a></li>
+ <li>
+ <span>&#127936;<span>2D</span></span>
+ <ul class="inner-tree">
+ <li><label>Rigidbody</label></li>
+ <li><a title="/2d/rigidbody/rigidbody_1.html" href="/2d/rigidbody/rigidbody_1.html">Linear Forces</a></li>
+ <li><a title="/2d/rigidbody/rigidbody_2.html" href="/2d/rigidbody/rigidbody_2.html">Rotational Forces</a></li>
+ <li><a title="/2d/rigidbody/rigidbody_3.html" href="/2d/rigidbody/rigidbody_3.html">Collisions</a></li>
+ <li><label>Collisions</label></li>
+ <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>
+ </ul>
+ </li>
+ <li>
+ <span>&#127776;<span>3D</span></span>
+ <ul class="inner-tree">
+ <li><label>Rigidbody</label></li>
+ <li><a title="/3d/rigidbody.html" href="/3d/rigidbody.html">Rigidbody in 3D</a></li>
+ </ul>
+ </li>
+ <li>
+ <span>&#128295;<span>WebAssembly</span></span>
+ <ul class="inner-tree">
+ <li><a title="/intro/intro.html" href="/intro/intro.html">Introduction</a></li>
+ </ul>
+ </li>
+ <li>
+ <span>&#128712;<span>About</span></span>
+ <ul class="inner-tree">
+ <li><a title="/roadmap.html" href="/roadmap.html">Roadmap</a></li>
+ </ul>
+ </li>
+ </ul>
+ </nav>
+<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';
+ });
+ }
+
+</script>
+<article>
+ <h1>Softbody</h1>
+ <section>
+ <h2></h2>
+ </section>
+ <section>
+ <h2>
+ Live Example
+ </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">
+ Play
+ </button>
+ <button id="gl_canvas_stop" class="stop_button">
+ Stop
+ </button>
+ </div>
+ </section>
+</article>
+ </main>
+ </body>
+</html>
diff --git a/2d/softbody/softbody_1.html.content b/2d/softbody/softbody_1.html.content
new file mode 100644
index 0000000..92be361
--- /dev/null
+++ b/2d/softbody/softbody_1.html.content
@@ -0,0 +1,45 @@
+<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';
+ });
+ }
+
+</script>
+<article>
+ <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
+ </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">
+ Play
+ </button>
+ <button id="gl_canvas_stop" class="stop_button">
+ Stop
+ </button>
+ </div>
+ </section>
+</article>
diff --git a/2d/softbody/softbody_1/build.sh b/2d/softbody/softbody_1/build.sh
new file mode 100755
index 0000000..892dddd
--- /dev/null
+++ b/2d/softbody/softbody_1/build.sh
@@ -0,0 +1,16 @@
+filepaths=""
+
+for file in ../../../shared_cpp/*; do
+ if [ -f "$file" ]; then
+ if [[ "$file" == *.cpp ]]; then
+ filepaths+=" $file"
+ fi
+ fi
+done
+
+if [ ! -d ./dist ]; then
+ mkdir ./dist
+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
diff --git a/2d/softbody/softbody_1/dist/output.js b/2d/softbody/softbody_1/dist/output.js
new file mode 100644
index 0000000..914e5e2
--- /dev/null
+++ b/2d/softbody/softbody_1/dist/output.js
@@ -0,0 +1,3480 @@
+
+
+// The Module object: Our interface to the outside world. We import
+// and export values on it. There are various ways Module can be used:
+// 1. Not defined. We create it here
+// 2. A function parameter, function(Module) { ..generated code.. }
+// 3. pre-run appended it, var Module = {}; ..generated code..
+// 4. External script tag defines var Module.
+// We need to check if Module already exists (e.g. case 3 above).
+// Substitution will be replaced with actual code on later stage of the build,
+// this way Closure Compiler will not mangle it (e.g. case 4. above).
+// Note that if you want to run closure, and also to use Module
+// after the generated code, you will need to define var Module = {};
+// before the code. Then that object will be used in the code, and you
+// can continue to use Module afterwards as well.
+var Module = typeof Module !== 'undefined' ? Module : {};
+
+// --pre-jses are emitted after the Module integration code, so that they can
+// refer to Module (if they choose; they can also define Module)
+// {{PRE_JSES}}
+
+// Sometimes an existing Module object exists with properties
+// meant to overwrite the default module functionality. Here
+// we collect those properties and reapply _after_ we configure
+// the current environment's defaults to avoid having to be so
+// defensive during initialization.
+var moduleOverrides = {};
+var key;
+for (key in Module) {
+ if (Module.hasOwnProperty(key)) {
+ moduleOverrides[key] = Module[key];
+ }
+}
+
+var arguments_ = [];
+var thisProgram = './this.program';
+var quit_ = function(status, toThrow) {
+ throw toThrow;
+};
+
+// Determine the runtime environment we are in. You can customize this by
+// setting the ENVIRONMENT setting at compile time (see settings.js).
+
+// Attempt to auto-detect the environment
+var ENVIRONMENT_IS_WEB = typeof window === 'object';
+var ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
+// N.b. Electron.js environment is simultaneously a NODE-environment, but
+// also a web environment.
+var ENVIRONMENT_IS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
+var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
+
+if (Module['ENVIRONMENT']) {
+ throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)');
+}
+
+// `/` should be present at the end if `scriptDirectory` is not empty
+var scriptDirectory = '';
+function locateFile(path) {
+ if (Module['locateFile']) {
+ return Module['locateFile'](path, scriptDirectory);
+ }
+ return scriptDirectory + path;
+}
+
+// Hooks that are implemented differently in different runtime environments.
+var read_,
+ readAsync,
+ readBinary,
+ setWindowTitle;
+
+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 {
+ scriptDirectory = __dirname + '/';
+ }
+
+// include: node_shell_read.js
+
+
+read_ = function shell_read(filename, binary) {
+ if (!nodeFS) nodeFS = require('fs');
+ if (!nodePath) nodePath = require('path');
+ filename = nodePath['normalize'](filename);
+ return nodeFS['readFileSync'](filename, binary ? null : 'utf8');
+};
+
+readBinary = function readBinary(filename) {
+ var ret = read_(filename, true);
+ if (!ret.buffer) {
+ ret = new Uint8Array(ret);
+ }
+ assert(ret.buffer);
+ 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, '/');
+ }
+
+ arguments_ = process['argv'].slice(2);
+
+ if (typeof module !== 'undefined') {
+ module['exports'] = Module;
+ }
+
+ process['on']('uncaughtException', function(ex) {
+ // suppress ExitStatus exceptions from showing an error
+ if (!(ex instanceof ExitStatus)) {
+ throw ex;
+ }
+ });
+
+ process['on']('unhandledRejection', abort);
+
+ quit_ = function(status, toThrow) {
+ if (keepRuntimeAlive()) {
+ process['exitCode'] = status;
+ throw toThrow;
+ }
+ process['exit'](status);
+ };
+
+ Module['inspect'] = function () { return '[Emscripten Module object]'; };
+
+} else
+if (ENVIRONMENT_IS_SHELL) {
+
+ if ((typeof process === 'object' && typeof require === 'function') || typeof window === 'object' || typeof importScripts === 'function') throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)');
+
+ if (typeof read != 'undefined') {
+ read_ = function shell_read(f) {
+ return read(f);
+ };
+ }
+
+ readBinary = function readBinary(f) {
+ var data;
+ if (typeof readbuffer === 'function') {
+ return new Uint8Array(readbuffer(f));
+ }
+ data = read(f, 'binary');
+ assert(typeof data === 'object');
+ 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') {
+ arguments_ = arguments;
+ }
+
+ if (typeof quit === 'function') {
+ quit_ = function(status) {
+ quit(status);
+ };
+ }
+
+ if (typeof print !== 'undefined') {
+ // Prefer to use print/printErr where they exist, as they usually work better.
+ if (typeof console === 'undefined') console = /** @type{!Console} */({});
+ console.log = /** @type{!function(this:Console, ...*): undefined} */ (print);
+ console.warn = console.error = /** @type{!function(this:Console, ...*): undefined} */ (typeof printErr !== 'undefined' ? printErr : print);
+ }
+
+} else
+
+// Note that this includes Node.js workers when relevant (pthreads is enabled).
+// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
+// ENVIRONMENT_IS_NODE.
+if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled
+ scriptDirectory = self.location.href;
+ } else if (typeof document !== 'undefined' && document.currentScript) { // web
+ scriptDirectory = document.currentScript.src;
+ }
+ // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
+ // otherwise, slice off the final part of the url to find the script directory.
+ // if scriptDirectory does not contain a slash, lastIndexOf will return -1,
+ // and scriptDirectory will correctly be replaced with an empty string.
+ if (scriptDirectory.indexOf('blob:') !== 0) {
+ scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/')+1);
+ } else {
+ 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.
+ {
+
+// include: web_or_worker_shell_read.js
+
+
+ read_ = function(url) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ xhr.send(null);
+ return xhr.responseText;
+ };
+
+ if (ENVIRONMENT_IS_WORKER) {
+ readBinary = function(url) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ xhr.responseType = 'arraybuffer';
+ xhr.send(null);
+ return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response));
+ };
+ }
+
+ readAsync = function(url, onload, onerror) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
+ xhr.responseType = 'arraybuffer';
+ xhr.onload = function() {
+ if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
+ onload(xhr.response);
+ return;
+ }
+ onerror();
+ };
+ xhr.onerror = onerror;
+ xhr.send(null);
+ };
+
+// end include: web_or_worker_shell_read.js
+ }
+
+ setWindowTitle = function(title) { document.title = title };
+} else
+{
+ throw new Error('environment detection error');
+}
+
+// Set up the out() and err() hooks, which are how we can print to stdout or
+// stderr, respectively.
+var out = Module['print'] || console.log.bind(console);
+var err = Module['printErr'] || console.warn.bind(console);
+
+// Merge back in the overrides
+for (key in moduleOverrides) {
+ if (moduleOverrides.hasOwnProperty(key)) {
+ Module[key] = moduleOverrides[key];
+ }
+}
+// Free the object hierarchy contained in the overrides, this lets the GC
+// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array.
+moduleOverrides = null;
+
+// Emit code to handle expected values on the Module object. This applies Module.x
+// to the proper local x. This has two benefits: first, we only emit it if it is
+// expected to arrive, and second, by using a local everywhere else that can be
+// minified.
+
+if (Module['arguments']) arguments_ = Module['arguments'];
+if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) {
+ Object.defineProperty(Module, 'arguments', {
+ configurable: true,
+ get: function() {
+ abort('Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (Module['thisProgram']) thisProgram = Module['thisProgram'];
+if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) {
+ Object.defineProperty(Module, 'thisProgram', {
+ configurable: true,
+ get: function() {
+ abort('Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (Module['quit']) quit_ = Module['quit'];
+if (!Object.getOwnPropertyDescriptor(Module, 'quit')) {
+ Object.defineProperty(Module, 'quit', {
+ configurable: true,
+ get: function() {
+ abort('Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
+// Assertions on removed incoming Module JS APIs.
+assert(typeof Module['memoryInitializerPrefixURL'] === 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead');
+assert(typeof Module['pthreadMainPrefixURL'] === 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead');
+assert(typeof Module['cdInitializerPrefixURL'] === 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead');
+assert(typeof Module['filePackagePrefixURL'] === 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead');
+assert(typeof Module['read'] === 'undefined', 'Module.read option was removed (modify read_ in JS)');
+assert(typeof Module['readAsync'] === 'undefined', 'Module.readAsync option was removed (modify readAsync in JS)');
+assert(typeof Module['readBinary'] === 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)');
+assert(typeof Module['setWindowTitle'] === 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)');
+assert(typeof Module['TOTAL_MEMORY'] === 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY');
+
+if (!Object.getOwnPropertyDescriptor(Module, 'read')) {
+ Object.defineProperty(Module, 'read', {
+ configurable: true,
+ get: function() {
+ abort('Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) {
+ Object.defineProperty(Module, 'readAsync', {
+ configurable: true,
+ get: function() {
+ abort('Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) {
+ Object.defineProperty(Module, 'readBinary', {
+ configurable: true,
+ get: function() {
+ abort('Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) {
+ Object.defineProperty(Module, 'setWindowTitle', {
+ configurable: true,
+ get: function() {
+ abort('Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+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 getNativeTypeSize(type) {
+ switch (type) {
+ case 'i1': case 'i8': return 1;
+ case 'i16': return 2;
+ case 'i32': return 4;
+ case 'i64': return 8;
+ case 'float': return 4;
+ case 'double': return 8;
+ default: {
+ if (type[type.length-1] === '*') {
+ return 4; // A pointer
+ } else if (type[0] === 'i') {
+ var bits = Number(type.substr(1));
+ assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);
+ return bits / 8;
+ } else {
+ return 0;
+ }
+ }
+ }
+}
+
+function warnOnce(text) {
+ if (!warnOnce.shown) warnOnce.shown = {};
+ if (!warnOnce.shown[text]) {
+ warnOnce.shown[text] = 1;
+ err(text);
+ }
+}
+
+// include: runtime_functions.js
+
+
+// Wraps a JS function as a wasm function with a given signature.
+function convertJsFunctionToWasm(func, sig) {
+
+ // If the type reflection proposal is available, use the new
+ // "WebAssembly.Function" constructor.
+ // Otherwise, construct a minimal wasm module importing the JS function and
+ // re-exporting it.
+ if (typeof WebAssembly.Function === "function") {
+ var typeNames = {
+ 'i': 'i32',
+ 'j': 'i64',
+ 'f': 'f32',
+ 'd': 'f64'
+ };
+ var type = {
+ parameters: [],
+ results: sig[0] == 'v' ? [] : [typeNames[sig[0]]]
+ };
+ for (var i = 1; i < sig.length; ++i) {
+ type.parameters.push(typeNames[sig[i]]);
+ }
+ return new WebAssembly.Function(type, func);
+ }
+
+ // The module is static, with the exception of the type section, which is
+ // generated based on the signature passed in.
+ var typeSection = [
+ 0x01, // id: section,
+ 0x00, // length: 0 (placeholder)
+ 0x01, // count: 1
+ 0x60, // form: func
+ ];
+ var sigRet = sig.slice(0, 1);
+ var sigParam = sig.slice(1);
+ var typeCodes = {
+ 'i': 0x7f, // i32
+ 'j': 0x7e, // i64
+ 'f': 0x7d, // f32
+ 'd': 0x7c, // f64
+ };
+
+ // Parameters, length + signatures
+ typeSection.push(sigParam.length);
+ for (var i = 0; i < sigParam.length; ++i) {
+ typeSection.push(typeCodes[sigParam[i]]);
+ }
+
+ // Return values, length + signatures
+ // With no multi-return in MVP, either 0 (void) or 1 (anything else)
+ if (sigRet == 'v') {
+ typeSection.push(0x00);
+ } else {
+ typeSection = typeSection.concat([0x01, typeCodes[sigRet]]);
+ }
+
+ // Write the overall length of the type section back into the section header
+ // (excepting the 2 bytes for the section id and length)
+ typeSection[1] = typeSection.length - 2;
+
+ // Rest of the module is static
+ var bytes = new Uint8Array([
+ 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm")
+ 0x01, 0x00, 0x00, 0x00, // version: 1
+ ].concat(typeSection, [
+ 0x02, 0x07, // import section
+ // (import "e" "f" (func 0 (type 0)))
+ 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00,
+ 0x07, 0x05, // export section
+ // (export "f" (func 0 (type 0)))
+ 0x01, 0x01, 0x66, 0x00, 0x00,
+ ]));
+
+ // We can compile this wasm module synchronously because it is very small.
+ // This accepts an import (at "e.f"), that it reroutes to an export (at "f")
+ var module = new WebAssembly.Module(bytes);
+ var instance = new WebAssembly.Instance(module, {
+ 'e': {
+ 'f': func
+ }
+ });
+ var wrappedFunc = instance.exports['f'];
+ return wrappedFunc;
+}
+
+var freeTableIndexes = [];
+
+// Weak map of functions in the table to their indexes, created on first use.
+var functionsInTableMap;
+
+function getEmptyTableSlot() {
+ // Reuse a free index if there is one, otherwise grow.
+ if (freeTableIndexes.length) {
+ return freeTableIndexes.pop();
+ }
+ // Grow the table
+ try {
+ wasmTable.grow(1);
+ } catch (err) {
+ if (!(err instanceof RangeError)) {
+ throw err;
+ }
+ throw 'Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.';
+ }
+ return wasmTable.length - 1;
+}
+
+// Add a wasm function to the table.
+function addFunctionWasm(func, sig) {
+ // Check if the function is already in the table, to ensure each function
+ // gets a unique index. First, create the map if this is the first use.
+ if (!functionsInTableMap) {
+ functionsInTableMap = new WeakMap();
+ for (var i = 0; i < wasmTable.length; i++) {
+ var item = wasmTable.get(i);
+ // Ignore null values.
+ if (item) {
+ functionsInTableMap.set(item, i);
+ }
+ }
+ }
+ if (functionsInTableMap.has(func)) {
+ return functionsInTableMap.get(func);
+ }
+
+ // It's not in the table, add it now.
+
+ var ret = getEmptyTableSlot();
+
+ // Set the new value.
+ try {
+ // Attempting to call this with JS function will cause of table.set() to fail
+ wasmTable.set(ret, func);
+ } catch (err) {
+ if (!(err instanceof TypeError)) {
+ throw err;
+ }
+ assert(typeof sig !== 'undefined', 'Missing signature argument to addFunction: ' + func);
+ var wrapped = convertJsFunctionToWasm(func, sig);
+ wasmTable.set(ret, wrapped);
+ }
+
+ functionsInTableMap.set(func, ret);
+
+ return ret;
+}
+
+function removeFunction(index) {
+ functionsInTableMap.delete(wasmTable.get(index));
+ freeTableIndexes.push(index);
+}
+
+// 'sig' parameter is required for the llvm backend but only when func is not
+// already a WebAssembly function.
+function addFunction(func, sig) {
+ assert(typeof func !== 'undefined');
+
+ return addFunctionWasm(func, sig);
+}
+
+// end include: runtime_functions.js
+// include: runtime_debug.js
+
+
+// end include: runtime_debug.js
+var tempRet0 = 0;
+
+var setTempRet0 = function(value) {
+ tempRet0 = value;
+};
+
+var getTempRet0 = function() {
+ return tempRet0;
+};
+
+
+
+// === Preamble library stuff ===
+
+// Documentation for the public APIs defined in this file must be updated in:
+// site/source/docs/api_reference/preamble.js.rst
+// A prebuilt local version of the documentation is available at:
+// site/build/text/docs/api_reference/preamble.js.txt
+// You can also build docs locally as HTML or other formats in site/
+// An online HTML version (which may be of a different version of Emscripten)
+// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
+
+var wasmBinary;
+if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];
+if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) {
+ Object.defineProperty(Module, 'wasmBinary', {
+ configurable: true,
+ get: function() {
+ abort('Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+var noExitRuntime = Module['noExitRuntime'] || true;
+if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) {
+ Object.defineProperty(Module, 'noExitRuntime', {
+ configurable: true,
+ get: function() {
+ abort('Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+if (typeof WebAssembly !== 'object') {
+ abort('no native wasm support detected');
+}
+
+// include: runtime_safe_heap.js
+
+
+// In MINIMAL_RUNTIME, setValue() and getValue() are only available when building with safe heap enabled, for heap safety checking.
+// In traditional runtime, setValue() and getValue() are always available (although their use is highly discouraged due to perf penalties)
+
+/** @param {number} ptr
+ @param {number} value
+ @param {string} type
+ @param {number|boolean=} noSafe */
+function setValue(ptr, value, type, noSafe) {
+ type = type || 'i8';
+ if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+ switch (type) {
+ case 'i1': HEAP8[((ptr)>>0)] = value; break;
+ case 'i8': HEAP8[((ptr)>>0)] = value; break;
+ case 'i16': HEAP16[((ptr)>>1)] = value; break;
+ case 'i32': HEAP32[((ptr)>>2)] = value; break;
+ case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math.abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math.min((+(Math.floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math.ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((ptr)>>2)] = tempI64[0],HEAP32[(((ptr)+(4))>>2)] = tempI64[1]); break;
+ case 'float': HEAPF32[((ptr)>>2)] = value; break;
+ case 'double': HEAPF64[((ptr)>>3)] = value; break;
+ default: abort('invalid type for setValue: ' + type);
+ }
+}
+
+/** @param {number} ptr
+ @param {string} type
+ @param {number|boolean=} noSafe */
+function getValue(ptr, type, noSafe) {
+ type = type || 'i8';
+ if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
+ switch (type) {
+ case 'i1': return HEAP8[((ptr)>>0)];
+ case 'i8': return HEAP8[((ptr)>>0)];
+ case 'i16': return HEAP16[((ptr)>>1)];
+ case 'i32': return HEAP32[((ptr)>>2)];
+ case 'i64': return HEAP32[((ptr)>>2)];
+ case 'float': return HEAPF32[((ptr)>>2)];
+ case 'double': return HEAPF64[((ptr)>>3)];
+ default: abort('invalid type for getValue: ' + type);
+ }
+ return null;
+}
+
+// end include: runtime_safe_heap.js
+// Wasm globals
+
+var wasmMemory;
+
+//========================================
+// Runtime essentials
+//========================================
+
+// whether we are quitting the application. no code should run after this.
+// set in exit() and abort()
+var ABORT = false;
+
+// set by exit() and abort(). Passed to 'onExit' handler.
+// NOTE: This is also used as the process return code code in shell environments
+// but only when noExitRuntime is false.
+var EXITSTATUS;
+
+/** @type {function(*, string=)} */
+function assert(condition, text) {
+ if (!condition) {
+ abort('Assertion failed: ' + text);
+ }
+}
+
+// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
+function getCFunc(ident) {
+ var func = Module['_' + ident]; // closure exported function
+ assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported');
+ return func;
+}
+
+// C calling interface.
+/** @param {string|null=} returnType
+ @param {Array=} argTypes
+ @param {Arguments|Array=} args
+ @param {Object=} opts */
+function ccall(ident, returnType, argTypes, args, opts) {
+ // For fast lookup of conversion functions
+ var toC = {
+ 'string': function(str) {
+ var ret = 0;
+ if (str !== null && str !== undefined && str !== 0) { // null string
+ // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0'
+ var len = (str.length << 2) + 1;
+ ret = stackAlloc(len);
+ stringToUTF8(str, ret, len);
+ }
+ return ret;
+ },
+ 'array': function(arr) {
+ var ret = stackAlloc(arr.length);
+ writeArrayToMemory(arr, ret);
+ return ret;
+ }
+ };
+
+ function convertReturnValue(ret) {
+ if (returnType === 'string') return UTF8ToString(ret);
+ if (returnType === 'boolean') return Boolean(ret);
+ return ret;
+ }
+
+ var func = getCFunc(ident);
+ var cArgs = [];
+ var stack = 0;
+ assert(returnType !== 'array', 'Return type should not be "array".');
+ if (args) {
+ for (var i = 0; i < args.length; i++) {
+ var converter = toC[argTypes[i]];
+ if (converter) {
+ if (stack === 0) stack = stackSave();
+ cArgs[i] = converter(args[i]);
+ } else {
+ cArgs[i] = args[i];
+ }
+ }
+ }
+ var ret = func.apply(null, cArgs);
+ function onDone(ret) {
+ if (stack !== 0) stackRestore(stack);
+ return convertReturnValue(ret);
+ }
+
+ ret = onDone(ret);
+ return ret;
+}
+
+/** @param {string=} returnType
+ @param {Array=} argTypes
+ @param {Object=} opts */
+function cwrap(ident, returnType, argTypes, opts) {
+ return function() {
+ return ccall(ident, returnType, argTypes, arguments, opts);
+ }
+}
+
+// We used to include malloc/free by default in the past. Show a helpful error in
+// builds with assertions.
+
+var ALLOC_NORMAL = 0; // Tries to use _malloc()
+var ALLOC_STACK = 1; // Lives for the duration of the current function call
+
+// allocate(): This is for internal use. You can use it yourself as well, but the interface
+// is a little tricky (see docs right below). The reason is that it is optimized
+// for multiple syntaxes to save space in generated code. So you should
+// normally not use allocate(), and instead allocate memory using _malloc(),
+// initialize it with setValue(), and so forth.
+// @slab: An array of data.
+// @allocator: How to allocate memory, see ALLOC_*
+/** @type {function((Uint8Array|Array<number>), number)} */
+function allocate(slab, allocator) {
+ var ret;
+ assert(typeof allocator === 'number', 'allocate no longer takes a type argument')
+ assert(typeof slab !== 'number', 'allocate no longer takes a number as arg0')
+
+ if (allocator == ALLOC_STACK) {
+ ret = stackAlloc(slab.length);
+ } else {
+ ret = _malloc(slab.length);
+ }
+
+ if (slab.subarray || slab.slice) {
+ HEAPU8.set(/** @type {!Uint8Array} */(slab), ret);
+ } else {
+ HEAPU8.set(new Uint8Array(slab), ret);
+ }
+ return ret;
+}
+
+// include: runtime_strings.js
+
+
+// runtime_strings.js: Strings related runtime functions that are part of both MINIMAL_RUNTIME and regular runtime.
+
+// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
+// a copy of that string as a Javascript String object.
+
+var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;
+
+/**
+ * @param {number} idx
+ * @param {number=} maxBytesToRead
+ * @return {string}
+ */
+function UTF8ArrayToString(heap, idx, maxBytesToRead) {
+ var endIdx = idx + maxBytesToRead;
+ var endPtr = idx;
+ // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
+ // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
+ // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity)
+ while (heap[endPtr] && !(endPtr >= endIdx)) ++endPtr;
+
+ if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) {
+ return UTF8Decoder.decode(heap.subarray(idx, endPtr));
+ } else {
+ var str = '';
+ // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that
+ while (idx < endPtr) {
+ // For UTF8 byte structure, see:
+ // http://en.wikipedia.org/wiki/UTF-8#Description
+ // https://www.ietf.org/rfc/rfc2279.txt
+ // https://tools.ietf.org/html/rfc3629
+ var u0 = heap[idx++];
+ if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
+ var u1 = heap[idx++] & 63;
+ if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
+ var u2 = heap[idx++] & 63;
+ if ((u0 & 0xF0) == 0xE0) {
+ u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
+ } else {
+ if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!');
+ u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63);
+ }
+
+ if (u0 < 0x10000) {
+ str += String.fromCharCode(u0);
+ } else {
+ var ch = u0 - 0x10000;
+ str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+ }
+ }
+ }
+ return str;
+}
+
+// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns a
+// copy of that string as a Javascript String object.
+// maxBytesToRead: an optional length that specifies the maximum number of bytes to read. You can omit
+// this parameter to scan the string until the first \0 byte. If maxBytesToRead is
+// passed, and the string at [ptr, ptr+maxBytesToReadr[ contains a null byte in the
+// middle, then the string will cut short at that byte index (i.e. maxBytesToRead will
+// not produce a string of exact length [ptr, ptr+maxBytesToRead[)
+// N.B. mixing frequent uses of UTF8ToString() with and without maxBytesToRead may
+// throw JS JIT optimizations off, so it is worth to consider consistently using one
+// style or the other.
+/**
+ * @param {number} ptr
+ * @param {number=} maxBytesToRead
+ * @return {string}
+ */
+function UTF8ToString(ptr, maxBytesToRead) {
+ return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';
+}
+
+// Copies the given Javascript String object 'str' to the given byte array at address 'outIdx',
+// encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP.
+// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
+// Parameters:
+// str: the Javascript string to copy.
+// heap: the array to copy to. Each index in this array is assumed to be one 8-byte element.
+// outIdx: The starting offset in the array to begin the copying.
+// maxBytesToWrite: The maximum number of bytes this function can write to the array.
+// This count should include the null terminator,
+// i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else.
+// maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator.
+// Returns the number of bytes written, EXCLUDING the null terminator.
+
+function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {
+ if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes.
+ return 0;
+
+ var startIdx = outIdx;
+ var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator.
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
+ var u = str.charCodeAt(i); // possibly a lead surrogate
+ if (u >= 0xD800 && u <= 0xDFFF) {
+ var u1 = str.charCodeAt(++i);
+ u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF);
+ }
+ if (u <= 0x7F) {
+ if (outIdx >= endIdx) break;
+ heap[outIdx++] = u;
+ } else if (u <= 0x7FF) {
+ if (outIdx + 1 >= endIdx) break;
+ heap[outIdx++] = 0xC0 | (u >> 6);
+ heap[outIdx++] = 0x80 | (u & 63);
+ } else if (u <= 0xFFFF) {
+ if (outIdx + 2 >= endIdx) break;
+ heap[outIdx++] = 0xE0 | (u >> 12);
+ heap[outIdx++] = 0x80 | ((u >> 6) & 63);
+ heap[outIdx++] = 0x80 | (u & 63);
+ } else {
+ if (outIdx + 3 >= endIdx) break;
+ if (u >= 0x200000) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x1FFFFF).');
+ heap[outIdx++] = 0xF0 | (u >> 18);
+ heap[outIdx++] = 0x80 | ((u >> 12) & 63);
+ heap[outIdx++] = 0x80 | ((u >> 6) & 63);
+ heap[outIdx++] = 0x80 | (u & 63);
+ }
+ }
+ // Null-terminate the pointer to the buffer.
+ heap[outIdx] = 0;
+ return outIdx - startIdx;
+}
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP.
+// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
+// Returns the number of bytes written, EXCLUDING the null terminator.
+
+function stringToUTF8(str, outPtr, maxBytesToWrite) {
+ assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
+ return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite);
+}
+
+// Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte.
+function lengthBytesUTF8(str) {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var u = str.charCodeAt(i); // possibly a lead surrogate
+ if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
+ if (u <= 0x7F) ++len;
+ else if (u <= 0x7FF) len += 2;
+ else if (u <= 0xFFFF) len += 3;
+ else len += 4;
+ }
+ return len;
+}
+
+// end include: runtime_strings.js
+// include: runtime_strings_extra.js
+
+
+// runtime_strings_extra.js: Strings related runtime functions that are available only in regular runtime.
+
+// Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+
+function AsciiToString(ptr) {
+ var str = '';
+ while (1) {
+ var ch = HEAPU8[((ptr++)>>0)];
+ if (!ch) return str;
+ str += String.fromCharCode(ch);
+ }
+}
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP.
+
+function stringToAscii(str, outPtr) {
+ return writeAsciiToMemory(str, outPtr, false);
+}
+
+// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
+// a copy of that string as a Javascript String object.
+
+var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;
+
+function UTF16ToString(ptr, maxBytesToRead) {
+ assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!');
+ var endPtr = ptr;
+ // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
+ // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
+ var idx = endPtr >> 1;
+ var maxIdx = idx + maxBytesToRead / 2;
+ // If maxBytesToRead is not passed explicitly, it will be undefined, and this
+ // will always evaluate to true. This saves on code size.
+ while (!(idx >= maxIdx) && HEAPU16[idx]) ++idx;
+ endPtr = idx << 1;
+
+ if (endPtr - ptr > 32 && UTF16Decoder) {
+ return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));
+ } else {
+ var str = '';
+
+ // If maxBytesToRead is not passed explicitly, it will be undefined, and the for-loop's condition
+ // will always evaluate to true. The loop is then terminated on the first null char.
+ for (var i = 0; !(i >= maxBytesToRead / 2); ++i) {
+ var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
+ if (codeUnit == 0) break;
+ // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
+ str += String.fromCharCode(codeUnit);
+ }
+
+ return str;
+ }
+}
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP.
+// Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write.
+// Parameters:
+// str: the Javascript string to copy.
+// outPtr: Byte address in Emscripten HEAP where to write the string to.
+// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
+// terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else.
+// maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator.
+// Returns the number of bytes written, EXCLUDING the null terminator.
+
+function stringToUTF16(str, outPtr, maxBytesToWrite) {
+ assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!');
+ assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
+ // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
+ if (maxBytesToWrite === undefined) {
+ maxBytesToWrite = 0x7FFFFFFF;
+ }
+ if (maxBytesToWrite < 2) return 0;
+ maxBytesToWrite -= 2; // Null terminator.
+ var startPtr = outPtr;
+ var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length;
+ for (var i = 0; i < numCharsToWrite; ++i) {
+ // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
+ var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+ HEAP16[((outPtr)>>1)] = codeUnit;
+ outPtr += 2;
+ }
+ // Null-terminate the pointer to the HEAP.
+ HEAP16[((outPtr)>>1)] = 0;
+ return outPtr - startPtr;
+}
+
+// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
+
+function lengthBytesUTF16(str) {
+ return str.length*2;
+}
+
+function UTF32ToString(ptr, maxBytesToRead) {
+ assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!');
+ var i = 0;
+
+ var str = '';
+ // If maxBytesToRead is not passed explicitly, it will be undefined, and this
+ // will always evaluate to true. This saves on code size.
+ while (!(i >= maxBytesToRead / 4)) {
+ var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
+ if (utf32 == 0) break;
+ ++i;
+ // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ if (utf32 >= 0x10000) {
+ var ch = utf32 - 0x10000;
+ str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
+ } else {
+ str += String.fromCharCode(utf32);
+ }
+ }
+ return str;
+}
+
+// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
+// null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP.
+// Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write.
+// Parameters:
+// str: the Javascript string to copy.
+// outPtr: Byte address in Emscripten HEAP where to write the string to.
+// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
+// terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else.
+// maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator.
+// Returns the number of bytes written, EXCLUDING the null terminator.
+
+function stringToUTF32(str, outPtr, maxBytesToWrite) {
+ assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!');
+ assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
+ // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
+ if (maxBytesToWrite === undefined) {
+ maxBytesToWrite = 0x7FFFFFFF;
+ }
+ if (maxBytesToWrite < 4) return 0;
+ var startPtr = outPtr;
+ var endPtr = startPtr + maxBytesToWrite - 4;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
+ if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
+ var trailSurrogate = str.charCodeAt(++i);
+ codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
+ }
+ HEAP32[((outPtr)>>2)] = codeUnit;
+ outPtr += 4;
+ if (outPtr + 4 > endPtr) break;
+ }
+ // Null-terminate the pointer to the HEAP.
+ HEAP32[((outPtr)>>2)] = 0;
+ return outPtr - startPtr;
+}
+
+// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
+
+function lengthBytesUTF32(str) {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
+ // See http://unicode.org/faq/utf_bom.html#utf16-3
+ var codeUnit = str.charCodeAt(i);
+ if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate.
+ len += 4;
+ }
+
+ return len;
+}
+
+// Allocate heap space for a JS string, and write it there.
+// It is the responsibility of the caller to free() that memory.
+function allocateUTF8(str) {
+ var size = lengthBytesUTF8(str) + 1;
+ var ret = _malloc(size);
+ if (ret) stringToUTF8Array(str, HEAP8, ret, size);
+ return ret;
+}
+
+// Allocate stack space for a JS string, and write it there.
+function allocateUTF8OnStack(str) {
+ var size = lengthBytesUTF8(str) + 1;
+ var ret = stackAlloc(size);
+ stringToUTF8Array(str, HEAP8, ret, size);
+ return ret;
+}
+
+// Deprecated: This function should not be called because it is unsafe and does not provide
+// a maximum length limit of how many bytes it is allowed to write. Prefer calling the
+// function stringToUTF8Array() instead, which takes in a maximum length that can be used
+// to be secure from out of bounds writes.
+/** @deprecated
+ @param {boolean=} dontAddNull */
+function writeStringToMemory(string, buffer, dontAddNull) {
+ warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!');
+
+ var /** @type {number} */ lastChar, /** @type {number} */ end;
+ if (dontAddNull) {
+ // stringToUTF8Array always appends null. If we don't want to do that, remember the
+ // character that existed at the location where the null will be placed, and restore
+ // that after the write (below).
+ end = buffer + lengthBytesUTF8(string);
+ lastChar = HEAP8[end];
+ }
+ stringToUTF8(string, buffer, Infinity);
+ if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character.
+}
+
+function writeArrayToMemory(array, buffer) {
+ assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)')
+ HEAP8.set(array, buffer);
+}
+
+/** @param {boolean=} dontAddNull */
+function writeAsciiToMemory(str, buffer, dontAddNull) {
+ for (var i = 0; i < str.length; ++i) {
+ assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff);
+ HEAP8[((buffer++)>>0)] = str.charCodeAt(i);
+ }
+ // Null-terminate the pointer to the HEAP.
+ if (!dontAddNull) HEAP8[((buffer)>>0)] = 0;
+}
+
+// end include: runtime_strings_extra.js
+// Memory management
+
+function alignUp(x, multiple) {
+ if (x % multiple > 0) {
+ x += multiple - (x % multiple);
+ }
+ return x;
+}
+
+var HEAP,
+/** @type {ArrayBuffer} */
+ buffer,
+/** @type {Int8Array} */
+ HEAP8,
+/** @type {Uint8Array} */
+ HEAPU8,
+/** @type {Int16Array} */
+ HEAP16,
+/** @type {Uint16Array} */
+ HEAPU16,
+/** @type {Int32Array} */
+ HEAP32,
+/** @type {Uint32Array} */
+ HEAPU32,
+/** @type {Float32Array} */
+ HEAPF32,
+/** @type {Float64Array} */
+ HEAPF64;
+
+function updateGlobalBufferAndViews(buf) {
+ buffer = buf;
+ Module['HEAP8'] = HEAP8 = new Int8Array(buf);
+ Module['HEAP16'] = HEAP16 = new Int16Array(buf);
+ Module['HEAP32'] = HEAP32 = new Int32Array(buf);
+ Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf);
+ Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf);
+ Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf);
+ Module['HEAPF32'] = HEAPF32 = new Float32Array(buf);
+ Module['HEAPF64'] = HEAPF64 = new Float64Array(buf);
+}
+
+var TOTAL_STACK = 5242880;
+if (Module['TOTAL_STACK']) assert(TOTAL_STACK === Module['TOTAL_STACK'], 'the stack size can no longer be determined at runtime')
+
+var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;
+if (!Object.getOwnPropertyDescriptor(Module, 'INITIAL_MEMORY')) {
+ Object.defineProperty(Module, 'INITIAL_MEMORY', {
+ configurable: true,
+ get: function() {
+ abort('Module.INITIAL_MEMORY has been replaced with plain INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)')
+ }
+ });
+}
+
+assert(INITIAL_MEMORY >= TOTAL_STACK, 'INITIAL_MEMORY should be larger than TOTAL_STACK, was ' + INITIAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')');
+
+// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray !== undefined && Int32Array.prototype.set !== undefined,
+ 'JS engine does not provide full typed array support');
+
+// If memory is defined in wasm, the user can't provide it.
+assert(!Module['wasmMemory'], 'Use of `wasmMemory` detected. Use -s IMPORTED_MEMORY to define wasmMemory externally');
+assert(INITIAL_MEMORY == 16777216, 'Detected runtime INITIAL_MEMORY setting. Use -s IMPORTED_MEMORY to define wasmMemory dynamically');
+
+// include: runtime_init_table.js
+// In regular non-RELOCATABLE mode the table is exported
+// from the wasm module and this will be assigned once
+// the exports are available.
+var wasmTable;
+
+// end include: runtime_init_table.js
+// include: runtime_stack_check.js
+
+
+// Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode.
+function writeStackCookie() {
+ var max = _emscripten_stack_get_end();
+ assert((max & 3) == 0);
+ // The stack grows downwards
+ HEAPU32[(max >> 2)+1] = 0x2135467;
+ HEAPU32[(max >> 2)+2] = 0x89BACDFE;
+ // Also test the global address 0 for integrity.
+ HEAP32[0] = 0x63736d65; /* 'emsc' */
+}
+
+function checkStackCookie() {
+ if (ABORT) return;
+ var max = _emscripten_stack_get_end();
+ var cookie1 = HEAPU32[(max >> 2)+1];
+ var cookie2 = HEAPU32[(max >> 2)+2];
+ if (cookie1 != 0x2135467 || cookie2 != 0x89BACDFE) {
+ abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x' + cookie2.toString(16) + ' ' + cookie1.toString(16));
+ }
+ // Also test the global address 0 for integrity.
+ if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) abort('Runtime error: The application has corrupted its heap memory area (address zero)!');
+}
+
+// end include: runtime_stack_check.js
+// include: runtime_assertions.js
+
+
+// Endianness check
+(function() {
+ var h16 = new Int16Array(1);
+ var h8 = new Int8Array(h16.buffer);
+ h16[0] = 0x6373;
+ if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -s SUPPORT_BIG_ENDIAN=1 to bypass)';
+})();
+
+// end include: runtime_assertions.js
+var __ATPRERUN__ = []; // functions called before the runtime is initialized
+var __ATINIT__ = []; // functions called during startup
+var __ATMAIN__ = []; // functions called when main() is to be run
+var __ATEXIT__ = []; // functions called during shutdown
+var __ATPOSTRUN__ = []; // functions called after the main() is called
+
+var runtimeInitialized = false;
+var runtimeExited = false;
+var runtimeKeepaliveCounter = 0;
+
+function keepRuntimeAlive() {
+ return noExitRuntime || runtimeKeepaliveCounter > 0;
+}
+
+function preRun() {
+
+ if (Module['preRun']) {
+ if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
+ while (Module['preRun'].length) {
+ addOnPreRun(Module['preRun'].shift());
+ }
+ }
+
+ callRuntimeCallbacks(__ATPRERUN__);
+}
+
+function initRuntime() {
+ checkStackCookie();
+ assert(!runtimeInitialized);
+ runtimeInitialized = true;
+
+
+ callRuntimeCallbacks(__ATINIT__);
+}
+
+function preMain() {
+ checkStackCookie();
+
+ callRuntimeCallbacks(__ATMAIN__);
+}
+
+function exitRuntime() {
+ checkStackCookie();
+ runtimeExited = true;
+}
+
+function postRun() {
+ checkStackCookie();
+
+ if (Module['postRun']) {
+ if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
+ while (Module['postRun'].length) {
+ addOnPostRun(Module['postRun'].shift());
+ }
+ }
+
+ callRuntimeCallbacks(__ATPOSTRUN__);
+}
+
+function addOnPreRun(cb) {
+ __ATPRERUN__.unshift(cb);
+}
+
+function addOnInit(cb) {
+ __ATINIT__.unshift(cb);
+}
+
+function addOnPreMain(cb) {
+ __ATMAIN__.unshift(cb);
+}
+
+function addOnExit(cb) {
+}
+
+function addOnPostRun(cb) {
+ __ATPOSTRUN__.unshift(cb);
+}
+
+// include: runtime_math.js
+
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
+
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
+
+assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
+assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
+assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
+assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
+
+// end include: runtime_math.js
+// A counter of dependencies for calling run(). If we need to
+// do asynchronous work before running, increment this and
+// decrement it. Incrementing must happen in a place like
+// Module.preRun (used by emcc to add file preloading).
+// Note that you can add dependencies in preRun, even though
+// it happens right before run - run will be postponed until
+// the dependencies are met.
+var runDependencies = 0;
+var runDependencyWatcher = null;
+var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
+var runDependencyTracking = {};
+
+function getUniqueRunDependency(id) {
+ var orig = id;
+ while (1) {
+ if (!runDependencyTracking[id]) return id;
+ id = orig + Math.random();
+ }
+}
+
+function addRunDependency(id) {
+ runDependencies++;
+
+ if (Module['monitorRunDependencies']) {
+ Module['monitorRunDependencies'](runDependencies);
+ }
+
+ if (id) {
+ assert(!runDependencyTracking[id]);
+ runDependencyTracking[id] = 1;
+ if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
+ // Check for missing dependencies every few seconds
+ runDependencyWatcher = setInterval(function() {
+ if (ABORT) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ return;
+ }
+ var shown = false;
+ for (var dep in runDependencyTracking) {
+ if (!shown) {
+ shown = true;
+ err('still waiting on run dependencies:');
+ }
+ err('dependency: ' + dep);
+ }
+ if (shown) {
+ err('(end of list)');
+ }
+ }, 10000);
+ }
+ } else {
+ err('warning: run dependency added without ID');
+ }
+}
+
+function removeRunDependency(id) {
+ runDependencies--;
+
+ if (Module['monitorRunDependencies']) {
+ Module['monitorRunDependencies'](runDependencies);
+ }
+
+ if (id) {
+ assert(runDependencyTracking[id]);
+ delete runDependencyTracking[id];
+ } else {
+ err('warning: run dependency removed without ID');
+ }
+ if (runDependencies == 0) {
+ if (runDependencyWatcher !== null) {
+ clearInterval(runDependencyWatcher);
+ runDependencyWatcher = null;
+ }
+ if (dependenciesFulfilled) {
+ var callback = dependenciesFulfilled;
+ dependenciesFulfilled = null;
+ callback(); // can add another dependenciesFulfilled
+ }
+ }
+}
+
+Module["preloadedImages"] = {}; // maps url to image data
+Module["preloadedAudios"] = {}; // maps url to audio data
+
+/** @param {string|number=} what */
+function abort(what) {
+ if (Module['onAbort']) {
+ Module['onAbort'](what);
+ }
+
+ what += '';
+ err(what);
+
+ ABORT = true;
+ EXITSTATUS = 1;
+
+ var output = 'abort(' + what + ') at ' + stackTrace();
+ what = output;
+
+ // Use a wasm runtime error, because a JS error might be seen as a foreign
+ // exception, which means we'd run destructors on it. We need the error to
+ // simply make the program stop.
+ var e = new WebAssembly.RuntimeError(what);
+
+ // Throw the error whether or not MODULARIZE is set because abort is used
+ // in code paths apart from instantiation where an exception is expected
+ // to be thrown when abort is called.
+ throw e;
+}
+
+// {{MEM_INITIALIZER}}
+
+// include: memoryprofiler.js
+
+
+// end include: memoryprofiler.js
+// show errors on likely calls to FS when it was not included
+var FS = {
+ error: function() {
+ abort('Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -s FORCE_FILESYSTEM=1');
+ },
+ init: function() { FS.error() },
+ createDataFile: function() { FS.error() },
+ createPreloadedFile: function() { FS.error() },
+ createLazyFile: function() { FS.error() },
+ open: function() { FS.error() },
+ mkdev: function() { FS.error() },
+ registerDevice: function() { FS.error() },
+ analyzePath: function() { FS.error() },
+ loadFilesFromDB: function() { FS.error() },
+
+ ErrnoError: function ErrnoError() { FS.error() },
+};
+Module['FS_createDataFile'] = FS.createDataFile;
+Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
+
+// include: URIUtils.js
+
+
+// Prefix of data URIs emitted by SINGLE_FILE and related options.
+var dataURIPrefix = 'data:application/octet-stream;base64,';
+
+// Indicates whether filename is a base64 data URI.
+function isDataURI(filename) {
+ // Prefix of data URIs emitted by SINGLE_FILE and related options.
+ return filename.startsWith(dataURIPrefix);
+}
+
+// Indicates whether filename is delivered via file protocol (as opposed to http/https)
+function isFileURI(filename) {
+ return filename.startsWith('file://');
+}
+
+// end include: URIUtils.js
+function createExportWrapper(name, fixedasm) {
+ return function() {
+ var displayName = name;
+ var asm = fixedasm;
+ if (!fixedasm) {
+ asm = Module['asm'];
+ }
+ assert(runtimeInitialized, 'native function `' + displayName + '` called before runtime initialization');
+ assert(!runtimeExited, 'native function `' + displayName + '` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
+ if (!asm[name]) {
+ assert(asm[name], 'exported native function `' + displayName + '` not found');
+ }
+ return asm[name].apply(null, arguments);
+ };
+}
+
+var wasmBinaryFile;
+ wasmBinaryFile = 'output.wasm';
+ if (!isDataURI(wasmBinaryFile)) {
+ wasmBinaryFile = locateFile(wasmBinaryFile);
+ }
+
+function getBinary(file) {
+ try {
+ if (file == wasmBinaryFile && wasmBinary) {
+ return new Uint8Array(wasmBinary);
+ }
+ if (readBinary) {
+ return readBinary(file);
+ } else {
+ throw "both async and sync fetching of the wasm failed";
+ }
+ }
+ catch (err) {
+ abort(err);
+ }
+}
+
+function getBinaryPromise() {
+ // If we don't have the binary yet, try to to load it asynchronously.
+ // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url.
+ // See https://github.com/github/fetch/pull/92#issuecomment-140665932
+ // Cordova or Electron apps are typically loaded from a file:// url.
+ // So use fetch if it is available and the url is not a file, otherwise fall back to XHR.
+ if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {
+ if (typeof fetch === 'function'
+ && !isFileURI(wasmBinaryFile)
+ ) {
+ return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) {
+ if (!response['ok']) {
+ throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
+ }
+ return response['arrayBuffer']();
+ }).catch(function () {
+ return getBinary(wasmBinaryFile);
+ });
+ }
+ else {
+ if (readAsync) {
+ // fetch is not available or url is file => try XHR (readAsync uses XHR internally)
+ return new Promise(function(resolve, reject) {
+ readAsync(wasmBinaryFile, function(response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject)
+ });
+ }
+ }
+ }
+
+ // Otherwise, getBinary should be able to get it synchronously
+ return Promise.resolve().then(function() { return getBinary(wasmBinaryFile); });
+}
+
+// Create the wasm instance.
+// Receives the wasm imports, returns the exports.
+function createWasm() {
+ // prepare imports
+ var info = {
+ 'env': asmLibraryArg,
+ 'wasi_snapshot_preview1': asmLibraryArg,
+ };
+ // Load the wasm module and create an instance of using native support in the JS engine.
+ // handle a generated wasm instance, receiving its exports and
+ // performing other necessary setup
+ /** @param {WebAssembly.Module=} module*/
+ function receiveInstance(instance, module) {
+ var exports = instance.exports;
+
+ Module['asm'] = exports;
+
+ wasmMemory = Module['asm']['memory'];
+ assert(wasmMemory, "memory not found in wasm exports");
+ // This assertion doesn't hold when emscripten is run in --post-link
+ // mode.
+ // TODO(sbc): Read INITIAL_MEMORY out of the wasm file in post-link mode.
+ //assert(wasmMemory.buffer.byteLength === 16777216);
+ updateGlobalBufferAndViews(wasmMemory.buffer);
+
+ wasmTable = Module['asm']['__indirect_function_table'];
+ assert(wasmTable, "table not found in wasm exports");
+
+ addOnInit(Module['asm']['__wasm_call_ctors']);
+
+ removeRunDependency('wasm-instantiate');
+ }
+ // 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.
+ // 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']);
+ }
+
+ function instantiateArrayBuffer(receiver) {
+ return getBinaryPromise().then(function(binary) {
+ return WebAssembly.instantiate(binary, info);
+ }).then(function (instance) {
+ return instance;
+ }).then(receiver, function(reason) {
+ err('failed to asynchronously prepare wasm: ' + reason);
+
+ // Warn on some common problems.
+ if (isFileURI(wasmBinaryFile)) {
+ err('warning: Loading from a file URI (' + wasmBinaryFile + ') is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing');
+ }
+ abort(reason);
+ });
+ }
+
+ function instantiateAsync() {
+ if (!wasmBinary &&
+ typeof WebAssembly.instantiateStreaming === 'function' &&
+ !isDataURI(wasmBinaryFile) &&
+ // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
+ !isFileURI(wasmBinaryFile) &&
+ typeof fetch === 'function') {
+ return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) {
+ var result = WebAssembly.instantiateStreaming(response, info);
+
+ return result.then(
+ receiveInstantiationResult,
+ 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);
+ });
+ });
+ } else {
+ return instantiateArrayBuffer(receiveInstantiationResult);
+ }
+ }
+
+ // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
+ // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel
+ // to any other async startup actions they are performing.
+ if (Module['instantiateWasm']) {
+ try {
+ var exports = Module['instantiateWasm'](info, receiveInstance);
+ return exports;
+ } catch(e) {
+ err('Module.instantiateWasm callback failed with error: ' + e);
+ return false;
+ }
+ }
+
+ instantiateAsync();
+ return {}; // no exports yet; we'll fill them in later
+}
+
+// Globals used by JS i64 conversions (see makeSetValue)
+var tempDouble;
+var tempI64;
+
+// === Body ===
+
+var ASM_CONSTS = {
+
+};
+
+
+
+
+
+
+ function callRuntimeCallbacks(callbacks) {
+ while (callbacks.length > 0) {
+ var callback = callbacks.shift();
+ if (typeof callback == 'function') {
+ callback(Module); // Pass the module as the first argument.
+ continue;
+ }
+ var func = callback.func;
+ if (typeof func === 'number') {
+ if (callback.arg === undefined) {
+ wasmTable.get(func)();
+ } else {
+ wasmTable.get(func)(callback.arg);
+ }
+ } else {
+ func(callback.arg === undefined ? null : callback.arg);
+ }
+ }
+ }
+
+ function demangle(func) {
+ warnOnce('warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling');
+ return func;
+ }
+
+ function demangleAll(text) {
+ var regex =
+ /\b_Z[\w\d_]+/g;
+ return text.replace(regex,
+ function(x) {
+ var y = demangle(x);
+ return x === y ? x : (y + ' [' + x + ']');
+ });
+ }
+
+ function jsStackTrace() {
+ var error = new Error();
+ if (!error.stack) {
+ // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown,
+ // so try that as a special-case.
+ try {
+ throw new Error();
+ } catch(e) {
+ error = e;
+ }
+ if (!error.stack) {
+ return '(no stack trace available)';
+ }
+ }
+ return error.stack.toString();
+ }
+
+ function stackTrace() {
+ var js = jsStackTrace();
+ if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
+ return demangleAll(js);
+ }
+
+ function _abort() {
+ abort();
+ }
+
+ function _emscripten_memcpy_big(dest, src, num) {
+ HEAPU8.copyWithin(dest, src, src + num);
+ }
+
+ function _emscripten_request_animation_frame_loop(cb, userData) {
+ function tick(timeStamp) {
+ if (wasmTable.get(cb)(timeStamp, userData)) {
+ requestAnimationFrame(tick);
+ }
+ }
+ return requestAnimationFrame(tick);
+ }
+
+ function emscripten_realloc_buffer(size) {
+ try {
+ // round size grow request up to wasm page size (fixed 64KB per spec)
+ wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16); // .grow() takes a delta compared to the previous size
+ 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);
+ }
+ // 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);
+
+ // Memory resize rules:
+ // 1. Always increase heap size to at least the requested size, rounded up to next page multiple.
+ // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap geometrically: increase the heap size according to
+ // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%),
+ // At most overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
+ // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap linearly: increase the heap size by at least MEMORY_GROWTH_LINEAR_STEP bytes.
+ // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
+ // 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
+ // (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
+ // 0 specially.
+ var maxHeapSize = 2147483648;
+ if (requestedSize > maxHeapSize) {
+ err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!');
+ return false;
+ }
+
+ // Loop through potential heap size increases. If we attempt a too eager reservation that fails, cut down on the
+ // attempted size and reserve a smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
+ for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
+ var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth
+ // but limit overreserving (default to capping at +96MB overgrowth at most)
+ overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
+
+ var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
+
+ var replacement = emscripten_realloc_buffer(newSize);
+ if (replacement) {
+
+ return true;
+ }
+ }
+ err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
+ return false;
+ }
+
+ var JSEvents = {inEventHandler:0,removeAllEventListeners:function() {
+ for (var i = JSEvents.eventHandlers.length-1; i >= 0; --i) {
+ JSEvents._removeHandler(i);
+ }
+ JSEvents.eventHandlers = [];
+ JSEvents.deferredCalls = [];
+ },registerRemoveEventListeners:function() {
+ if (!JSEvents.removeEventListenersRegistered) {
+ __ATEXIT__.push(JSEvents.removeAllEventListeners);
+ JSEvents.removeEventListenersRegistered = true;
+ }
+ },deferredCalls:[],deferCall:function(targetFunction, precedence, argsList) {
+ function arraysHaveEqualContent(arrA, arrB) {
+ if (arrA.length != arrB.length) return false;
+
+ for (var i in arrA) {
+ if (arrA[i] != arrB[i]) return false;
+ }
+ return true;
+ }
+ // Test if the given call was already queued, and if so, don't add it again.
+ for (var i in JSEvents.deferredCalls) {
+ var call = JSEvents.deferredCalls[i];
+ if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) {
+ return;
+ }
+ }
+ JSEvents.deferredCalls.push({
+ targetFunction: targetFunction,
+ precedence: precedence,
+ argsList: argsList
+ });
+
+ JSEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; });
+ },removeDeferredCalls:function(targetFunction) {
+ for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
+ if (JSEvents.deferredCalls[i].targetFunction == targetFunction) {
+ JSEvents.deferredCalls.splice(i, 1);
+ --i;
+ }
+ }
+ },canPerformEventHandlerRequests:function() {
+ return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls;
+ },runDeferredCalls:function() {
+ if (!JSEvents.canPerformEventHandlerRequests()) {
+ return;
+ }
+ for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
+ var call = JSEvents.deferredCalls[i];
+ JSEvents.deferredCalls.splice(i, 1);
+ --i;
+ call.targetFunction.apply(null, call.argsList);
+ }
+ },eventHandlers:[],removeAllHandlersOnTarget:function(target, eventTypeString) {
+ for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
+ if (JSEvents.eventHandlers[i].target == target &&
+ (!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) {
+ JSEvents._removeHandler(i--);
+ }
+ }
+ },_removeHandler:function(i) {
+ var h = JSEvents.eventHandlers[i];
+ h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture);
+ JSEvents.eventHandlers.splice(i, 1);
+ },registerOrRemoveHandler:function(eventHandler) {
+ var jsEventHandler = function jsEventHandler(event) {
+ // Increment nesting count for the event handler.
+ ++JSEvents.inEventHandler;
+ JSEvents.currentEventHandler = eventHandler;
+ // Process any old deferred calls the user has placed.
+ JSEvents.runDeferredCalls();
+ // Process the actual event, calls back to user C code handler.
+ eventHandler.handlerFunc(event);
+ // Process any new deferred calls that were placed right now from this event handler.
+ JSEvents.runDeferredCalls();
+ // Out of event handler - restore nesting count.
+ --JSEvents.inEventHandler;
+ };
+
+ if (eventHandler.callbackfunc) {
+ eventHandler.eventListenerFunc = jsEventHandler;
+ eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture);
+ JSEvents.eventHandlers.push(eventHandler);
+ JSEvents.registerRemoveEventListeners();
+ } else {
+ for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
+ if (JSEvents.eventHandlers[i].target == eventHandler.target
+ && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) {
+ JSEvents._removeHandler(i--);
+ }
+ }
+ }
+ },getNodeNameForTarget:function(target) {
+ if (!target) return '';
+ if (target == window) return '#window';
+ if (target == screen) return '#screen';
+ return (target && target.nodeName) ? target.nodeName : '';
+ },fullscreenEnabled:function() {
+ return document.fullscreenEnabled
+ // Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitFullscreenEnabled.
+ // TODO: If Safari at some point ships with unprefixed version, update the version check above.
+ || document.webkitFullscreenEnabled
+ ;
+ }};
+
+ function maybeCStringToJsString(cString) {
+ // "cString > 2" checks if the input is a number, and isn't of the special
+ // values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2).
+ // In other words, if cString > 2 then it's a pointer to a valid place in
+ // memory, and points to a C string.
+ return cString > 2 ? UTF8ToString(cString) : cString;
+ }
+
+ 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);
+ return domElement;
+ }
+ function findCanvasEventTarget(target) { return findEventTarget(target); }
+ function _emscripten_set_canvas_element_size(target, width, height) {
+ var canvas = findCanvasEventTarget(target);
+ if (!canvas) return -4;
+ canvas.width = width;
+ canvas.height = height;
+ return 0;
+ }
+
+ function getBoundingClientRect(e) {
+ return specialHTMLTargets.indexOf(e) < 0 ? e.getBoundingClientRect() : {'left':0,'top':0};
+ }
+ 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 + 12] = e["movementY"]
+ ;
+
+ var rect = getBoundingClientRect(target);
+ HEAP32[idx + 13] = e.clientX - rect.left;
+ HEAP32[idx + 14] = e.clientY - rect.top;
+
+ }
+ function registerMouseEventCallback(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) {
+ if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc( 72 );
+ target = findEventTarget(target);
+
+ var mouseEventHandlerFunc = function(ev) {
+ var e = ev || event;
+
+ // TODO: Make this access thread safe, or this could update live while app is reading it.
+ fillMouseEventData(JSEvents.mouseEvent, e, target);
+
+ if (wasmTable.get(callbackfunc)(eventTypeId, JSEvents.mouseEvent, userData)) e.preventDefault();
+ };
+
+ var eventHandler = {
+ target: target,
+ allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them!
+ eventTypeString: eventTypeString,
+ callbackfunc: callbackfunc,
+ handlerFunc: mouseEventHandlerFunc,
+ useCapture: useCapture
+ };
+ JSEvents.registerOrRemoveHandler(eventHandler);
+ }
+ function _emscripten_set_click_callback_on_thread(target, userData, useCapture, callbackfunc, targetThread) {
+ registerMouseEventCallback(target, userData, useCapture, callbackfunc, 4, "click", targetThread);
+ return 0;
+ }
+
+ function __webgl_enable_ANGLE_instanced_arrays(ctx) {
+ // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2.
+ var ext = ctx.getExtension('ANGLE_instanced_arrays');
+ if (ext) {
+ ctx['vertexAttribDivisor'] = function(index, divisor) { ext['vertexAttribDivisorANGLE'](index, divisor); };
+ ctx['drawArraysInstanced'] = function(mode, first, count, primcount) { ext['drawArraysInstancedANGLE'](mode, first, count, primcount); };
+ ctx['drawElementsInstanced'] = function(mode, count, type, indices, primcount) { ext['drawElementsInstancedANGLE'](mode, count, type, indices, primcount); };
+ return 1;
+ }
+ }
+
+ function __webgl_enable_OES_vertex_array_object(ctx) {
+ // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2.
+ var ext = ctx.getExtension('OES_vertex_array_object');
+ if (ext) {
+ ctx['createVertexArray'] = function() { return ext['createVertexArrayOES'](); };
+ ctx['deleteVertexArray'] = function(vao) { ext['deleteVertexArrayOES'](vao); };
+ ctx['bindVertexArray'] = function(vao) { ext['bindVertexArrayOES'](vao); };
+ ctx['isVertexArray'] = function(vao) { return ext['isVertexArrayOES'](vao); };
+ return 1;
+ }
+ }
+
+ function __webgl_enable_WEBGL_draw_buffers(ctx) {
+ // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2.
+ var ext = ctx.getExtension('WEBGL_draw_buffers');
+ if (ext) {
+ ctx['drawBuffers'] = function(n, bufs) { ext['drawBuffersWEBGL'](n, bufs); };
+ return 1;
+ }
+ }
+
+ function __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx) {
+ // Closure is expected to be allowed to minify the '.dibvbi' property, so not accessing it quoted.
+ return !!(ctx.dibvbi = ctx.getExtension('WEBGL_draw_instanced_base_vertex_base_instance'));
+ }
+
+ function __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx) {
+ // Closure is expected to be allowed to minify the '.mdibvbi' property, so not accessing it quoted.
+ return !!(ctx.mdibvbi = ctx.getExtension('WEBGL_multi_draw_instanced_base_vertex_base_instance'));
+ }
+
+ function __webgl_enable_WEBGL_multi_draw(ctx) {
+ // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted.
+ return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw'));
+ }
+ 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) {
+ if (!GL.lastError) {
+ GL.lastError = errorCode;
+ }
+ },getNewId:function(table) {
+ var ret = GL.counter++;
+ for (var i = table.length; i < ret; i++) {
+ table[i] = null;
+ }
+ return ret;
+ },MAX_TEMP_BUFFER_SIZE:2097152,numTempVertexBuffersPerSize:64,log2ceilLookup:function(i) {
+ return 32 - Math.clz32(i === 0 ? 0 : i - 1);
+ },generateTempBuffers:function(quads, context) {
+ var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
+ context.tempVertexBufferCounters1 = [];
+ context.tempVertexBufferCounters2 = [];
+ context.tempVertexBufferCounters1.length = context.tempVertexBufferCounters2.length = largestIndex+1;
+ context.tempVertexBuffers1 = [];
+ context.tempVertexBuffers2 = [];
+ context.tempVertexBuffers1.length = context.tempVertexBuffers2.length = largestIndex+1;
+ context.tempIndexBuffers = [];
+ context.tempIndexBuffers.length = largestIndex+1;
+ for (var i = 0; i <= largestIndex; ++i) {
+ context.tempIndexBuffers[i] = null; // Created on-demand
+ context.tempVertexBufferCounters1[i] = context.tempVertexBufferCounters2[i] = 0;
+ var ringbufferLength = GL.numTempVertexBuffersPerSize;
+ context.tempVertexBuffers1[i] = [];
+ context.tempVertexBuffers2[i] = [];
+ var ringbuffer1 = context.tempVertexBuffers1[i];
+ var ringbuffer2 = context.tempVertexBuffers2[i];
+ ringbuffer1.length = ringbuffer2.length = ringbufferLength;
+ for (var j = 0; j < ringbufferLength; ++j) {
+ ringbuffer1[j] = ringbuffer2[j] = null; // Created on-demand
+ }
+ }
+
+ if (quads) {
+ // GL_QUAD indexes can be precalculated
+ context.tempQuadIndexBuffer = GLctx.createBuffer();
+ context.GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, context.tempQuadIndexBuffer);
+ var numIndexes = GL.MAX_TEMP_BUFFER_SIZE >> 1;
+ var quadIndexes = new Uint16Array(numIndexes);
+ var i = 0, v = 0;
+ while (1) {
+ quadIndexes[i++] = v;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+1;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+2;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+2;
+ if (i >= numIndexes) break;
+ quadIndexes[i++] = v+3;
+ if (i >= numIndexes) break;
+ v += 4;
+ }
+ context.GLctx.bufferData(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, quadIndexes, 0x88E4 /*GL_STATIC_DRAW*/);
+ context.GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, null);
+ }
+ },getTempVertexBuffer:function getTempVertexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup(sizeBytes);
+ var ringbuffer = GL.currentContext.tempVertexBuffers1[idx];
+ var nextFreeBufferIndex = GL.currentContext.tempVertexBufferCounters1[idx];
+ GL.currentContext.tempVertexBufferCounters1[idx] = (GL.currentContext.tempVertexBufferCounters1[idx]+1) & (GL.numTempVertexBuffersPerSize-1);
+ var vbo = ringbuffer[nextFreeBufferIndex];
+ if (vbo) {
+ return vbo;
+ }
+ var prevVBO = GLctx.getParameter(0x8894 /*GL_ARRAY_BUFFER_BINDING*/);
+ ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer();
+ GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, ringbuffer[nextFreeBufferIndex]);
+ GLctx.bufferData(0x8892 /*GL_ARRAY_BUFFER*/, 1 << idx, 0x88E8 /*GL_DYNAMIC_DRAW*/);
+ GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, prevVBO);
+ return ringbuffer[nextFreeBufferIndex];
+ },getTempIndexBuffer:function getTempIndexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup(sizeBytes);
+ var ibo = GL.currentContext.tempIndexBuffers[idx];
+ if (ibo) {
+ return ibo;
+ }
+ var prevIBO = GLctx.getParameter(0x8895 /*ELEMENT_ARRAY_BUFFER_BINDING*/);
+ GL.currentContext.tempIndexBuffers[idx] = GLctx.createBuffer();
+ GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, GL.currentContext.tempIndexBuffers[idx]);
+ GLctx.bufferData(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, 1 << idx, 0x88E8 /*GL_DYNAMIC_DRAW*/);
+ GLctx.bindBuffer(0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/, prevIBO);
+ return GL.currentContext.tempIndexBuffers[idx];
+ },newRenderingFrameStarted:function newRenderingFrameStarted() {
+ if (!GL.currentContext) {
+ return;
+ }
+ var vb = GL.currentContext.tempVertexBuffers1;
+ GL.currentContext.tempVertexBuffers1 = GL.currentContext.tempVertexBuffers2;
+ GL.currentContext.tempVertexBuffers2 = vb;
+ vb = GL.currentContext.tempVertexBufferCounters1;
+ GL.currentContext.tempVertexBufferCounters1 = GL.currentContext.tempVertexBufferCounters2;
+ GL.currentContext.tempVertexBufferCounters2 = vb;
+ var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
+ for (var i = 0; i <= largestIndex; ++i) {
+ GL.currentContext.tempVertexBufferCounters1[i] = 0;
+ }
+ },getSource:function(shader, count, string, length) {
+ var source = '';
+ for (var i = 0; i < count; ++i) {
+ var len = length ? HEAP32[(((length)+(i*4))>>2)] : -1;
+ source += UTF8ToString(HEAP32[(((string)+(i*4))>>2)], len < 0 ? undefined : len);
+ }
+ return source;
+ },calcBufLength:function calcBufLength(size, type, stride, count) {
+ if (stride > 0) {
+ return count * stride; // XXXvlad this is not exactly correct I don't think
+ }
+ var typeSize = GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
+ return size * typeSize * count;
+ },usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count) {
+ GL.resetBufferBinding = false;
+
+ // TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib
+ for (var i = 0; i < GL.currentContext.maxVertexAttribs; ++i) {
+ var cb = GL.currentContext.clientBuffers[i];
+ if (!cb.clientside || !cb.enabled) continue;
+
+ GL.resetBufferBinding = true;
+
+ var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count);
+ var buf = GL.getTempVertexBuffer(size);
+ GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, buf);
+ GLctx.bufferSubData(0x8892 /*GL_ARRAY_BUFFER*/,
+ 0,
+ HEAPU8.subarray(cb.ptr, cb.ptr + size));
+ cb.vertexAttribPointerAdaptor.call(GLctx, i, cb.size, cb.type, cb.normalized, cb.stride, 0);
+ }
+ },postDrawHandleClientVertexAttribBindings:function postDrawHandleClientVertexAttribBindings() {
+ if (GL.resetBufferBinding) {
+ GLctx.bindBuffer(0x8892 /*GL_ARRAY_BUFFER*/, GL.buffers[GLctx.currentArrayBufferBinding]);
+ }
+ },createContext:function(canvas, webGLContextAttributes) {
+
+ // BUG: Workaround Safari WebGL issue: After successfully acquiring WebGL context on a canvas,
+ // calling .getContext() will always return that context independent of which 'webgl' or 'webgl2'
+ // context version was passed. See https://bugs.webkit.org/show_bug.cgi?id=222758 and
+ // https://github.com/emscripten-core/emscripten/issues/13295.
+ // TODO: Once the bug is fixed and shipped in Safari, adjust the Safari version field in above check.
+ if (!canvas.getContextSafariWebGL2Fixed) {
+ canvas.getContextSafariWebGL2Fixed = canvas.getContext;
+ canvas.getContext = function(ver, attrs) {
+ var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs);
+ return ((ver == 'webgl') == (gl instanceof WebGLRenderingContext)) ? gl : null;
+ }
+ }
+
+ var ctx =
+ (webGLContextAttributes.majorVersion > 1)
+ ?
+ canvas.getContext("webgl2", webGLContextAttributes)
+ :
+ (canvas.getContext("webgl", webGLContextAttributes)
+ // https://caniuse.com/#feat=webgl
+ );
+
+ if (!ctx) return 0;
+
+ var handle = GL.registerContext(ctx, webGLContextAttributes);
+
+ return handle;
+ },registerContext:function(ctx, webGLContextAttributes) {
+ // without pthreads a context is just an integer ID
+ var handle = GL.getNewId(GL.contexts);
+
+ var context = {
+ handle: handle,
+ attributes: webGLContextAttributes,
+ version: webGLContextAttributes.majorVersion,
+ GLctx: ctx
+ };
+
+ // Store the created context object so that we can access the context given a canvas without having to pass the parameters again.
+ if (ctx.canvas) ctx.canvas.GLctxObject = context;
+ GL.contexts[handle] = context;
+ if (typeof webGLContextAttributes.enableExtensionsByDefault === 'undefined' || webGLContextAttributes.enableExtensionsByDefault) {
+ GL.initExtensions(context);
+ }
+
+ context.maxVertexAttribs = context.GLctx.getParameter(0x8869 /*GL_MAX_VERTEX_ATTRIBS*/);
+ context.clientBuffers = [];
+ for (var i = 0; i < context.maxVertexAttribs; i++) {
+ context.clientBuffers[i] = { enabled: false, clientside: false, size: 0, type: 0, normalized: 0, stride: 0, ptr: 0, vertexAttribPointerAdaptor: null };
+ }
+
+ GL.generateTempBuffers(false, context);
+
+ return handle;
+ },makeContextCurrent:function(contextHandle) {
+
+ GL.currentContext = GL.contexts[contextHandle]; // Active Emscripten GL layer context object.
+ Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx; // Active WebGL context object.
+ return !(contextHandle && !GLctx);
+ },getContext:function(contextHandle) {
+ return GL.contexts[contextHandle];
+ },deleteContext:function(contextHandle) {
+ if (GL.currentContext === GL.contexts[contextHandle]) GL.currentContext = null;
+ if (typeof JSEvents === 'object') JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); // Release all JS event handlers on the DOM element that the GL context is associated with since the context is now deleted.
+ if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; // Make sure the canvas object no longer refers to the context object so there are no GC surprises.
+ GL.contexts[contextHandle] = null;
+ },initExtensions:function(context) {
+ // If this function is called without a specific context object, init the extensions of the currently active context.
+ if (!context) context = GL.currentContext;
+
+ if (context.initExtensionsDone) return;
+ context.initExtensionsDone = true;
+
+ var GLctx = context.GLctx;
+
+ // Detect the presence of a few extensions manually, this GL interop layer itself will need to know if they exist.
+
+ // Extensions that are only available in WebGL 1 (the calls will be no-ops if called on a WebGL 2 context active)
+ __webgl_enable_ANGLE_instanced_arrays(GLctx);
+ __webgl_enable_OES_vertex_array_object(GLctx);
+ __webgl_enable_WEBGL_draw_buffers(GLctx);
+ // Extensions that are available from WebGL >= 2 (no-op if called on a WebGL 1 context active)
+ __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");
+ }
+
+ __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')) {
+ // Call .getExtension() to enable that extension permanently.
+ GLctx.getExtension(ext);
+ }
+ });
+ }};
+
+ var __emscripten_webgl_power_preferences = ['default', 'low-power', 'high-performance'];
+ function _emscripten_webgl_do_create_context(target, attributes) {
+ assert(attributes);
+ var a = attributes >> 2;
+ var powerPreference = HEAP32[a + (24>>2)];
+ var contextAttributes = {
+ 'alpha': !!HEAP32[a + (0>>2)],
+ 'depth': !!HEAP32[a + (4>>2)],
+ 'stencil': !!HEAP32[a + (8>>2)],
+ 'antialias': !!HEAP32[a + (12>>2)],
+ 'premultipliedAlpha': !!HEAP32[a + (16>>2)],
+ 'preserveDrawingBuffer': !!HEAP32[a + (20>>2)],
+ 'powerPreference': __emscripten_webgl_power_preferences[powerPreference],
+ 'failIfMajorPerformanceCaveat': !!HEAP32[a + (28>>2)],
+ // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure.
+ majorVersion: HEAP32[a + (32>>2)],
+ minorVersion: HEAP32[a + (36>>2)],
+ enableExtensionsByDefault: HEAP32[a + (40>>2)],
+ explicitSwapControl: HEAP32[a + (44>>2)],
+ proxyContextToMainThread: HEAP32[a + (48>>2)],
+ renderViaOffscreenBackBuffer: HEAP32[a + (52>>2)]
+ };
+
+ var canvas = findCanvasEventTarget(target);
+
+ if (!canvas) {
+ return 0;
+ }
+
+ if (contextAttributes.explicitSwapControl) {
+ return 0;
+ }
+
+ var contextHandle = GL.createContext(canvas, contextAttributes);
+ return contextHandle;
+ }
+ function _emscripten_webgl_create_context(a0,a1
+ ) {
+ return _emscripten_webgl_do_create_context(a0,a1);
+ }
+
+ function _emscripten_webgl_init_context_attributes(attributes) {
+ assert(attributes);
+ var a = attributes >> 2;
+ for (var i = 0; i < (56>>2); ++i) {
+ HEAP32[a+i] = 0;
+ }
+
+ HEAP32[a + (0>>2)] =
+ HEAP32[a + (4>>2)] =
+ HEAP32[a + (12>>2)] =
+ HEAP32[a + (16>>2)] =
+ HEAP32[a + (32>>2)] =
+ HEAP32[a + (40>>2)] = 1;
+
+ }
+
+ 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
+ if (typeof _fflush !== 'undefined') _fflush(0);
+ var buffers = SYSCALLS.buffers;
+ if (buffers[1].length) SYSCALLS.printChar(1, 10);
+ if (buffers[2].length) SYSCALLS.printChar(2, 10);
+ }
+
+ var SYSCALLS = {mappings:{},buffers:[null,[],[]],printChar:function(stream, curr) {
+ var buffer = SYSCALLS.buffers[stream];
+ assert(buffer);
+ if (curr === 0 || curr === 10) {
+ (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0));
+ buffer.length = 0;
+ } else {
+ buffer.push(curr);
+ }
+ },varargs:undefined,get:function() {
+ assert(SYSCALLS.varargs != undefined);
+ SYSCALLS.varargs += 4;
+ var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)];
+ return ret;
+ },getStr:function(ptr) {
+ var ret = UTF8ToString(ptr);
+ return ret;
+ },get64:function(low, high) {
+ if (low >= 0) assert(high === 0);
+ else assert(high === -1);
+ return low;
+ }};
+ function _fd_write(fd, iov, iovcnt, pnum) {
+ // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0
+ var num = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAP32[(((iov)+(i*8))>>2)];
+ var len = HEAP32[(((iov)+(i*8 + 4))>>2)];
+ for (var j = 0; j < len; j++) {
+ SYSCALLS.printChar(fd, HEAPU8[ptr+j]);
+ }
+ num += len;
+ }
+ HEAP32[((pnum)>>2)] = num
+ return 0;
+ }
+
+ function _glAttachShader(program, shader) {
+ GLctx.attachShader(GL.programs[program], GL.shaders[shader]);
+ }
+
+ function _glBindBuffer(target, buffer) {
+ if (target == 0x8892 /*GL_ARRAY_BUFFER*/) {
+ GLctx.currentArrayBufferBinding = buffer;
+ } else if (target == 0x8893 /*GL_ELEMENT_ARRAY_BUFFER*/) {
+ GLctx.currentElementArrayBufferBinding = buffer;
+ }
+
+ if (target == 0x88EB /*GL_PIXEL_PACK_BUFFER*/) {
+ // In WebGL 2 glReadPixels entry point, we need to use a different WebGL 2 API function call when a buffer is bound to
+ // GL_PIXEL_PACK_BUFFER_BINDING point, so must keep track whether that binding point is non-null to know what is
+ // the proper API function to call.
+ GLctx.currentPixelPackBufferBinding = buffer;
+ } else if (target == 0x88EC /*GL_PIXEL_UNPACK_BUFFER*/) {
+ // In WebGL 2 gl(Compressed)Tex(Sub)Image[23]D entry points, we need to
+ // use a different WebGL 2 API function call when a buffer is bound to
+ // GL_PIXEL_UNPACK_BUFFER_BINDING point, so must keep track whether that
+ // binding point is non-null to know what is the proper API function to
+ // call.
+ GLctx.currentPixelUnpackBufferBinding = buffer;
+ }
+ GLctx.bindBuffer(target, GL.buffers[buffer]);
+ }
+
+ function _glBindVertexArray(vao) {
+ GLctx['bindVertexArray'](GL.vaos[vao]);
+ var ibo = GLctx.getParameter(0x8895 /*ELEMENT_ARRAY_BUFFER_BINDING*/);
+ GLctx.currentElementArrayBufferBinding = ibo ? (ibo.name | 0) : 0;
+ }
+
+ function _glBufferData(target, size, data, usage) {
+
+ if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible.
+ if (data) {
+ GLctx.bufferData(target, HEAPU8, usage, data, size);
+ } else {
+ GLctx.bufferData(target, size, usage);
+ }
+ } else {
+ // N.b. here first form specifies a heap subarray, second form an integer size, so the ?: code here is polymorphic. It is advised to avoid
+ // randomly mixing both uses in calling code, to avoid any potential JS engine JIT issues.
+ GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage);
+ }
+ }
+
+ function _glBufferSubData(target, offset, size, data) {
+ if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible.
+ GLctx.bufferSubData(target, offset, HEAPU8, data, size);
+ return;
+ }
+ GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
+ }
+
+ function _glClear(x0) { GLctx['clear'](x0) }
+
+ function _glClearColor(x0, x1, x2, x3) { GLctx['clearColor'](x0, x1, x2, x3) }
+
+ function _glClearDepth(x0) { GLctx['clearDepth'](x0) }
+
+ function _glCompileShader(shader) {
+ GLctx.compileShader(GL.shaders[shader]);
+ }
+
+ 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;
+ }
+
+ function _glCreateShader(shaderType) {
+ var id = GL.getNewId(GL.shaders);
+ GL.shaders[id] = GLctx.createShader(shaderType);
+
+ return id;
+ }
+
+ function _glDeleteBuffers(n, buffers) {
+ for (var i = 0; i < n; i++) {
+ var id = HEAP32[(((buffers)+(i*4))>>2)];
+ var buffer = GL.buffers[id];
+
+ // From spec: "glDeleteBuffers silently ignores 0's and names that do not
+ // correspond to existing buffer objects."
+ if (!buffer) continue;
+
+ GLctx.deleteBuffer(buffer);
+ buffer.name = 0;
+ GL.buffers[id] = null;
+
+ if (id == GLctx.currentArrayBufferBinding) GLctx.currentArrayBufferBinding = 0;
+ if (id == GLctx.currentElementArrayBufferBinding) GLctx.currentElementArrayBufferBinding = 0;
+ if (id == GLctx.currentPixelPackBufferBinding) GLctx.currentPixelPackBufferBinding = 0;
+ if (id == GLctx.currentPixelUnpackBufferBinding) GLctx.currentPixelUnpackBufferBinding = 0;
+ }
+ }
+
+ function _glDeleteProgram(id) {
+ if (!id) return;
+ var program = GL.programs[id];
+ if (!program) { // glDeleteProgram actually signals an error when deleting a nonexisting object, unlike some other GL delete functions.
+ GL.recordError(0x501 /* GL_INVALID_VALUE */);
+ return;
+ }
+ GLctx.deleteProgram(program);
+ program.name = 0;
+ GL.programs[id] = null;
+ }
+
+ function _glDeleteShader(id) {
+ if (!id) return;
+ var shader = GL.shaders[id];
+ if (!shader) { // glDeleteShader actually signals an error when deleting a nonexisting object, unlike some other GL delete functions.
+ GL.recordError(0x501 /* GL_INVALID_VALUE */);
+ return;
+ }
+ GLctx.deleteShader(shader);
+ GL.shaders[id] = null;
+ }
+
+ function _glDeleteVertexArrays(n, vaos) {
+ for (var i = 0; i < n; i++) {
+ var id = HEAP32[(((vaos)+(i*4))>>2)];
+ GLctx['deleteVertexArray'](GL.vaos[id]);
+ GL.vaos[id] = null;
+ }
+ }
+
+ function _glDepthFunc(x0) { GLctx['depthFunc'](x0) }
+
+ function _glDepthMask(flag) {
+ GLctx.depthMask(!!flag);
+ }
+
+ function _glDrawArrays(mode, first, count) {
+ // bind any client-side buffers
+ GL.preDrawHandleClientVertexAttribBindings(first + count);
+
+ GLctx.drawArrays(mode, first, count);
+
+ GL.postDrawHandleClientVertexAttribBindings();
+ }
+
+ function _glEnable(x0) { GLctx['enable'](x0) }
+
+ function _glEnableVertexAttribArray(index) {
+ var cb = GL.currentContext.clientBuffers[index];
+ cb.enabled = true;
+ GLctx.enableVertexAttribArray(index);
+ }
+
+ function __glGenObject(n, buffers, createFunction, objectTable
+ ) {
+ for (var i = 0; i < n; i++) {
+ var buffer = GLctx[createFunction]();
+ var id = buffer && GL.getNewId(objectTable);
+ if (buffer) {
+ buffer.name = id;
+ objectTable[id] = buffer;
+ } else {
+ GL.recordError(0x502 /* GL_INVALID_OPERATION */);
+ }
+ HEAP32[(((buffers)+(i*4))>>2)] = id;
+ }
+ }
+ function _glGenBuffers(n, buffers) {
+ __glGenObject(n, buffers, 'createBuffer', GL.buffers
+ );
+ }
+
+ function _glGenVertexArrays(n, arrays) {
+ __glGenObject(n, arrays, 'createVertexArray', GL.vaos
+ );
+ }
+
+ function _glGetAttribLocation(program, name) {
+ return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name));
+ }
+
+ function _glGetProgramInfoLog(program, maxLength, length, infoLog) {
+ var log = GLctx.getProgramInfoLog(GL.programs[program]);
+ if (log === null) log = '(unknown error)';
+ var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0;
+ if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull;
+ }
+
+ function _glGetProgramiv(program, pname, p) {
+ if (!p) {
+ // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense
+ // if p == null, issue a GL error to notify user about it.
+ GL.recordError(0x501 /* GL_INVALID_VALUE */);
+ return;
+ }
+
+ if (program >= GL.counter) {
+ GL.recordError(0x501 /* GL_INVALID_VALUE */);
+ return;
+ }
+
+ program = GL.programs[program];
+
+ if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
+ var log = GLctx.getProgramInfoLog(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;
+ } 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);
+ }
+ }
+ HEAP32[((p)>>2)] = program.maxAttributeLength;
+ } else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) {
+ if (!program.maxUniformBlockNameLength) {
+ for (var i = 0; i < GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); ++i) {
+ program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1);
+ }
+ }
+ HEAP32[((p)>>2)] = program.maxUniformBlockNameLength;
+ } else {
+ HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname);
+ }
+ }
+
+ function _glGetShaderInfoLog(shader, maxLength, length, infoLog) {
+ var log = GLctx.getShaderInfoLog(GL.shaders[shader]);
+ if (log === null) log = '(unknown error)';
+ var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0;
+ if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull;
+ }
+
+ function _glGetShaderiv(shader, pname, p) {
+ if (!p) {
+ // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense
+ // if p == null, issue a GL error to notify user about it.
+ GL.recordError(0x501 /* GL_INVALID_VALUE */);
+ return;
+ }
+ if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
+ var log = GLctx.getShaderInfoLog(GL.shaders[shader]);
+ if (log === null) log = '(unknown error)';
+ // The GLES2 specification says that if the shader has an empty info log,
+ // a value of 0 is returned. Otherwise the log has a null char appended.
+ // (An empty string is falsey, so we can just check that instead of
+ // looking at log.length.)
+ var logLength = log ? log.length + 1 : 0;
+ HEAP32[((p)>>2)] = logLength;
+ } else if (pname == 0x8B88) { // GL_SHADER_SOURCE_LENGTH
+ var source = GLctx.getShaderSource(GL.shaders[shader]);
+ // source may be a null, or the empty string, both of which are falsey
+ // values that we report a 0 length for.
+ var sourceLength = source ? source.length + 1 : 0;
+ HEAP32[((p)>>2)] = sourceLength;
+ } else {
+ HEAP32[((p)>>2)] = GLctx.getShaderParameter(GL.shaders[shader], pname);
+ }
+ }
+
+ /** @suppress {checkTypes} */
+ 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;
+ }
+ }
+ }
+ 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 */);
+ }
+ 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 = {};
+
+ }
+
+ function _glShaderSource(shader, count, string, length) {
+ var source = GL.getSource(shader, count, string, length);
+
+ 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 = [];
+ 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);
+ return;
+ }
+
+ if (count <= 18) {
+ // avoid allocation when uploading few enough uniforms
+ var view = miniTempWebGLFloatBuffers[16*count-1];
+ // hoist the heap out of the loop for size and for pthreads+growth.
+ var heap = HEAPF32;
+ value >>= 2;
+ for (var i = 0; i < 16 * count; i += 16) {
+ var dst = value + i;
+ view[i] = heap[dst];
+ view[i + 1] = heap[dst + 1];
+ view[i + 2] = heap[dst + 2];
+ view[i + 3] = heap[dst + 3];
+ view[i + 4] = heap[dst + 4];
+ view[i + 5] = heap[dst + 5];
+ view[i + 6] = heap[dst + 6];
+ view[i + 7] = heap[dst + 7];
+ view[i + 8] = heap[dst + 8];
+ view[i + 9] = heap[dst + 9];
+ view[i + 10] = heap[dst + 10];
+ view[i + 11] = heap[dst + 11];
+ view[i + 12] = heap[dst + 12];
+ view[i + 13] = heap[dst + 13];
+ view[i + 14] = heap[dst + 14];
+ view[i + 15] = heap[dst + 15];
+ }
+ } else
+ {
+ var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2);
+ }
+ GLctx.uniformMatrix4fv(webglGetUniformLocation(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;
+ }
+
+ function _glVertexAttribPointer(index, size, type, normalized, stride, ptr) {
+ var cb = GL.currentContext.clientBuffers[index];
+ if (!GLctx.currentArrayBufferBinding) {
+ cb.size = size;
+ cb.type = type;
+ cb.normalized = normalized;
+ cb.stride = stride;
+ cb.ptr = ptr;
+ cb.clientside = true;
+ cb.vertexAttribPointerAdaptor = function(index, size, type, normalized, stride, ptr) {
+ this.vertexAttribPointer(index, size, type, normalized, stride, ptr);
+ };
+ return;
+ }
+ cb.clientside = false;
+ GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
+ }
+
+ function _setTempRet0(val) {
+ setTempRet0(val);
+ }
+var GLctx;;
+var miniTempWebGLFloatBuffersStorage = new Float32Array(288);
+ for (/**@suppress{duplicate}*/var i = 0; i < 288; ++i) {
+ miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i+1);
+ }
+ ;
+var ASSERTIONS = true;
+
+
+
+/** @type {function(string, boolean=, number=)} */
+function intArrayFromString(stringy, dontAddNull, length) {
+ var len = length > 0 ? length : lengthBytesUTF8(stringy)+1;
+ var u8array = new Array(len);
+ var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
+ if (dontAddNull) u8array.length = numBytesWritten;
+ return u8array;
+}
+
+function intArrayToString(array) {
+ var ret = [];
+ for (var i = 0; i < array.length; i++) {
+ var chr = array[i];
+ if (chr > 0xFF) {
+ if (ASSERTIONS) {
+ assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.');
+ }
+ chr &= 0xFF;
+ }
+ ret.push(String.fromCharCode(chr));
+ }
+ return ret.join('');
+}
+
+
+var asmLibraryArg = {
+ "abort": _abort,
+ "emscripten_memcpy_big": _emscripten_memcpy_big,
+ "emscripten_request_animation_frame_loop": _emscripten_request_animation_frame_loop,
+ "emscripten_resize_heap": _emscripten_resize_heap,
+ "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_init_context_attributes": _emscripten_webgl_init_context_attributes,
+ "emscripten_webgl_make_context_current": _emscripten_webgl_make_context_current,
+ "fd_write": _fd_write,
+ "glAttachShader": _glAttachShader,
+ "glBindBuffer": _glBindBuffer,
+ "glBindVertexArray": _glBindVertexArray,
+ "glBufferData": _glBufferData,
+ "glBufferSubData": _glBufferSubData,
+ "glClear": _glClear,
+ "glClearColor": _glClearColor,
+ "glClearDepth": _glClearDepth,
+ "glCompileShader": _glCompileShader,
+ "glCreateProgram": _glCreateProgram,
+ "glCreateShader": _glCreateShader,
+ "glDeleteBuffers": _glDeleteBuffers,
+ "glDeleteProgram": _glDeleteProgram,
+ "glDeleteShader": _glDeleteShader,
+ "glDeleteVertexArrays": _glDeleteVertexArrays,
+ "glDepthFunc": _glDepthFunc,
+ "glDepthMask": _glDepthMask,
+ "glDrawArrays": _glDrawArrays,
+ "glEnable": _glEnable,
+ "glEnableVertexAttribArray": _glEnableVertexAttribArray,
+ "glGenBuffers": _glGenBuffers,
+ "glGenVertexArrays": _glGenVertexArrays,
+ "glGetAttribLocation": _glGetAttribLocation,
+ "glGetProgramInfoLog": _glGetProgramInfoLog,
+ "glGetProgramiv": _glGetProgramiv,
+ "glGetShaderInfoLog": _glGetShaderInfoLog,
+ "glGetShaderiv": _glGetShaderiv,
+ "glGetUniformLocation": _glGetUniformLocation,
+ "glLinkProgram": _glLinkProgram,
+ "glShaderSource": _glShaderSource,
+ "glUniformMatrix4fv": _glUniformMatrix4fv,
+ "glUseProgram": _glUseProgram,
+ "glVertexAttribPointer": _glVertexAttribPointer,
+ "setTempRet0": _setTempRet0
+};
+var asm = createWasm();
+/** @type {function(...*):?} */
+var ___wasm_call_ctors = Module["___wasm_call_ctors"] = createExportWrapper("__wasm_call_ctors");
+
+/** @type {function(...*):?} */
+var _main = Module["_main"] = createExportWrapper("main");
+
+/** @type {function(...*):?} */
+var ___errno_location = Module["___errno_location"] = createExportWrapper("__errno_location");
+
+/** @type {function(...*):?} */
+var _fflush = Module["_fflush"] = createExportWrapper("fflush");
+
+/** @type {function(...*):?} */
+var stackSave = Module["stackSave"] = createExportWrapper("stackSave");
+
+/** @type {function(...*):?} */
+var stackRestore = Module["stackRestore"] = createExportWrapper("stackRestore");
+
+/** @type {function(...*):?} */
+var stackAlloc = Module["stackAlloc"] = createExportWrapper("stackAlloc");
+
+/** @type {function(...*):?} */
+var _emscripten_stack_init = Module["_emscripten_stack_init"] = function() {
+ return (_emscripten_stack_init = Module["_emscripten_stack_init"] = Module["asm"]["emscripten_stack_init"]).apply(null, arguments);
+};
+
+/** @type {function(...*):?} */
+var _emscripten_stack_get_free = Module["_emscripten_stack_get_free"] = function() {
+ return (_emscripten_stack_get_free = Module["_emscripten_stack_get_free"] = Module["asm"]["emscripten_stack_get_free"]).apply(null, arguments);
+};
+
+/** @type {function(...*):?} */
+var _emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = function() {
+ return (_emscripten_stack_get_end = Module["_emscripten_stack_get_end"] = Module["asm"]["emscripten_stack_get_end"]).apply(null, arguments);
+};
+
+/** @type {function(...*):?} */
+var _malloc = Module["_malloc"] = createExportWrapper("malloc");
+
+/** @type {function(...*):?} */
+var _free = Module["_free"] = createExportWrapper("free");
+
+/** @type {function(...*):?} */
+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)") };
+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)") } });
+
+var calledRun;
+
+/**
+ * @constructor
+ * @this {ExitStatus}
+ */
+function ExitStatus(status) {
+ this.name = "ExitStatus";
+ this.message = "Program terminated with exit(" + status + ")";
+ this.status = status;
+}
+
+var calledMain = false;
+
+dependenciesFulfilled = function runCaller() {
+ // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
+ if (!calledRun) run();
+ if (!calledRun) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
+};
+
+function callMain(args) {
+ assert(runDependencies == 0, 'cannot call main when async dependencies remain! (listen on Module["onRuntimeInitialized"])');
+ assert(__ATPRERUN__.length == 0, 'cannot call main when preRun functions remain to be called');
+
+ var entryFunction = Module['_main'];
+
+ args = args || [];
+
+ var argc = args.length+1;
+ var argv = stackAlloc((argc + 1) * 4);
+ HEAP32[argv >> 2] = allocateUTF8OnStack(thisProgram);
+ for (var i = 1; i < argc; i++) {
+ HEAP32[(argv >> 2) + i] = allocateUTF8OnStack(args[i - 1]);
+ }
+ HEAP32[(argv >> 2) + argc] = 0;
+
+ try {
+
+ var ret = entryFunction(argc, argv);
+
+ // 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') {
+ return;
+ }
+ // 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;
+
+ }
+}
+
+function stackCheckInit() {
+ // This is normally called automatically during __wasm_call_ctors but need to
+ // get these values before even running any of the ctors so we call it redundantly
+ // here.
+ // TODO(sbc): Move writeStackCookie to native to to avoid this.
+ _emscripten_stack_init();
+ writeStackCookie();
+}
+
+/** @type {function(Array=)} */
+function run(args) {
+ args = args || arguments_;
+
+ if (runDependencies > 0) {
+ return;
+ }
+
+ stackCheckInit();
+
+ preRun();
+
+ // a preRun added a dependency, run will be called later
+ if (runDependencies > 0) {
+ return;
+ }
+
+ function doRun() {
+ // run may have just been called through dependencies being fulfilled just in this very frame,
+ // or while the async setStatus time below was happening
+ if (calledRun) return;
+ calledRun = true;
+ Module['calledRun'] = true;
+
+ if (ABORT) return;
+
+ initRuntime();
+
+ preMain();
+
+ if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']();
+
+ if (shouldRunNow) callMain(args);
+
+ postRun();
+ }
+
+ if (Module['setStatus']) {
+ Module['setStatus']('Running...');
+ setTimeout(function() {
+ setTimeout(function() {
+ Module['setStatus']('');
+ }, 1);
+ doRun();
+ }, 1);
+ } else
+ {
+ doRun();
+ }
+ checkStackCookie();
+}
+Module['run'] = run;
+
+function checkUnflushedContent() {
+ // Compiler settings do not allow exiting the runtime, so flushing
+ // the streams is not possible. but in ASSERTIONS mode we check
+ // if there was something to flush, and if so tell the user they
+ // should request that the runtime be exitable.
+ // Normally we would not even include flush() at all, but in ASSERTIONS
+ // builds we do so just for this check, and here we see if there is any
+ // content to flush, that is, we check if there would have been
+ // something a non-ASSERTIONS build would have not seen.
+ // How we flush the streams depends on whether we are in SYSCALLS_REQUIRE_FILESYSTEM=0
+ // mode (which has its own special function for this; otherwise, all
+ // the code is inside libc)
+ var oldOut = out;
+ var oldErr = err;
+ var has = false;
+ out = err = function(x) {
+ has = true;
+ }
+ try { // it doesn't matter if it fails
+ var flush = flush_NO_FILESYSTEM;
+ if (flush) flush();
+ } catch(e) {}
+ out = oldOut;
+ err = oldErr;
+ if (has) {
+ warnOnce('stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.');
+ warnOnce('(this may also be due to not including full filesystem support - try building with -s FORCE_FILESYSTEM=1)');
+ }
+}
+
+/** @param {boolean|number=} implicit */
+function exit(status, implicit) {
+ EXITSTATUS = status;
+
+ checkUnflushedContent();
+
+ if (keepRuntimeAlive()) {
+ // if exit() was called, we may warn the user if the runtime isn't actually being shut down
+ if (!implicit) {
+ var msg = 'program exited (with status: ' + status + '), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)';
+ err(msg);
+ }
+ } else {
+ exitRuntime();
+ }
+
+ procExit(status);
+}
+
+function procExit(code) {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ if (Module['onExit']) Module['onExit'](code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+}
+
+if (Module['preInit']) {
+ if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
+ while (Module['preInit'].length > 0) {
+ Module['preInit'].pop()();
+ }
+}
+
+// shouldRunNow refers to calling main(), not run().
+var shouldRunNow = true;
+
+if (Module['noInitialRun']) shouldRunNow = false;
+
+run();
+
+
+
+
+
diff --git a/2d/softbody/softbody_1/dist/output.wasm b/2d/softbody/softbody_1/dist/output.wasm
new file mode 100755
index 0000000..a0646b3
--- /dev/null
+++ 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
new file mode 100644
index 0000000..0b04426
--- /dev/null
+++ b/2d/softbody/softbody_1/main.cpp
@@ -0,0 +1,228 @@
+#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>
+
+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);
+ 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/3d/rigidbody.html b/3d/rigidbody.html
index ead43d0..e5b0270 100644
--- a/3d/rigidbody.html
+++ b/3d/rigidbody.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
@@ -69,9 +71,13 @@
<h1>Rigidbody in 3D</h1>
<section>
<section>
- <h2>Quaternion Time</h2>
+ <h2>Quaternions</h2>
+
+ </section>
+ <section>
+ <h2>Quaternions</h2>
<p>
- I hate to start off the article like this. I really do. But it really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>)
+ A discussion of 3D physics simulation woudl not really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>)
<br/><br/>
</p>
diff --git a/3d/rigidbody.html.content b/3d/rigidbody.html.content
index 5a3eca2..1a7150c 100644
--- a/3d/rigidbody.html.content
+++ b/3d/rigidbody.html.content
@@ -18,9 +18,13 @@
<h1>Rigidbody in 3D</h1>
<section>
<section>
- <h2>Quaternion Time</h2>
+ <h2>Quaternions</h2>
+
+ </section>
+ <section>
+ <h2>Quaternions</h2>
<p>
- I hate to start off the article like this. I really do. But it really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>)
+ A discussion of 3D physics simulation woudl not really wouldn't be a discussion of 3D simulation if we didn't jump right into quaternions. Before I start, however, I recommend you take a look at <a href='https://www.3dgep.com/understanding-quaternions'>this article</a>. Quaternions have been written about over and over throughout the years (and I have read many articles about them over and over throughout the years), so I will not waste your time describing every single detail here. The article that I linked to should provide you enough information to begin to understand what quaternions are and why they're important. That being said, I will provide a brief intro to quaternions here, as well as my own C++ implementation of their algebra. (This article is also quite useful: <a href='http://danceswithcode.net/engineeringnotes/quaternions/quaternions.html'>Dance's With Code Website</a>)
<br/><br/>
</p>
diff --git a/_wasm/intro/intro.cpp b/_wasm/intro/intro.cpp
index 8e1574b..3146eaf 100644
--- a/_wasm/intro/intro.cpp
+++ b/_wasm/intro/intro.cpp
@@ -44,14 +44,14 @@ struct OrthographicProgramData {
} uniformVariables;
};
-struct OrthographicVertex {
+struct Vertex2d {
Vector2 position;
Vector4 color;
};
// Create a triangle
struct TriangleObject {
- OrthographicVertex vertices[3];
+ Vertex2d vertices[3];
Vector2 velocity;
Vector2 position;
GLuint mVao;
@@ -66,13 +66,13 @@ struct TriangleObject {
glGenBuffers(1, &mVbo);
glBindBuffer(GL_ARRAY_BUFFER, mVbo);
- glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(OrthographicVertex), &vertices[0], GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, 3 * sizeof(Vertex2d), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(programData->attributes.position);
- glVertexAttribPointer(programData->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(OrthographicVertex), (GLvoid *)0);
+ glVertexAttribPointer(programData->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2d), (GLvoid *)0);
glEnableVertexAttribArray(programData->attributes.color);
- glVertexAttribPointer(programData->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(OrthographicVertex), (GLvoid *)offsetof(OrthographicVertex, color));
+ glVertexAttribPointer(programData->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex2d), (GLvoid *)offsetof(Vertex2d, color));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
diff --git a/index.html b/index.html
index 54d5553..ba53e56 100644
--- a/index.html
+++ b/index.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/roadmap.html b/roadmap.html
index 5e647f4..cf3a4e6 100644
--- a/roadmap.html
+++ b/roadmap.html
@@ -26,6 +26,8 @@
<li><label>Collisions</label></li>
<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>
</ul>
</li>
<li>
diff --git a/shared_cpp/OrthographicRenderer.cpp b/shared_cpp/Renderer2d.cpp
index 21c13a1..f91ed08 100644
--- a/shared_cpp/OrthographicRenderer.cpp
+++ b/shared_cpp/Renderer2d.cpp
@@ -1,4 +1,4 @@
-#include "OrthographicRenderer.h"
+#include "Renderer2d.h"
#include "WebglContext.h"
#include "mathlib.h"
@@ -20,7 +20,7 @@ const char* orthographicFragment =
" gl_FragColor = VertexColor; \n"
"}";
-void OrthographicRenderer::load(WebglContext* context) {
+void Renderer2d::load(WebglContext* context) {
printf("Compiling orthographic shader...\n");
shader = loadShader(orthographicVertex, orthographicFragment);
@@ -34,7 +34,7 @@ void OrthographicRenderer::load(WebglContext* context) {
printf("Orthographic shader compiled.\n");
}
-void OrthographicRenderer::render() {
+void Renderer2d::render() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
@@ -45,14 +45,14 @@ void OrthographicRenderer::render() {
setShaderMat4(uniforms.projection, projection);
}
-void OrthographicRenderer::unload() {
+void Renderer2d::unload() {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDeleteProgram(shader);
}
-void OrthographicShape::load(OrthographicVertex* inVertices, uint32 inNumVertices, OrthographicRenderer* renderer) {
+void Mesh2d::load(Vertex2d* inVertices, uint32 inNumVertices, Renderer2d* renderer, GLenum loadType) {
numVertices = inNumVertices;
useShader(renderer->shader);
@@ -61,19 +61,19 @@ void OrthographicShape::load(OrthographicVertex* inVertices, uint32 inNumVertice
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, inNumVertices * sizeof(OrthographicVertex), &inVertices[0], GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, inNumVertices * sizeof(Vertex2d), &inVertices[0], loadType);
glEnableVertexAttribArray(renderer->attributes.position);
- glVertexAttribPointer(renderer->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(OrthographicVertex), (GLvoid *)0);
+ glVertexAttribPointer(renderer->attributes.position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2d), (GLvoid *)0);
glEnableVertexAttribArray(renderer->attributes.color);
- glVertexAttribPointer(renderer->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(OrthographicVertex), (GLvoid *)offsetof(OrthographicVertex, color));
+ glVertexAttribPointer(renderer->attributes.color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex2d), (GLvoid *)offsetof(Vertex2d, color));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
-void OrthographicShape::render(OrthographicRenderer* renderer, GLenum drawType) {
+void Mesh2d::render(Renderer2d* renderer, GLenum drawType) {
setShaderMat4(renderer->uniforms.model, model);
glBindVertexArray(vao);
@@ -81,7 +81,7 @@ void OrthographicShape::render(OrthographicRenderer* renderer, GLenum drawType)
glBindVertexArray(0);
}
-void OrthographicShape::unload() {
+void Mesh2d::unload() {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
-} \ No newline at end of file
+}
diff --git a/shared_cpp/OrthographicRenderer.h b/shared_cpp/Renderer2d.h
index cef5305..afde20e 100644
--- a/shared_cpp/OrthographicRenderer.h
+++ b/shared_cpp/Renderer2d.h
@@ -7,7 +7,7 @@
struct WebglContext;
-struct OrthographicRenderer {
+struct Renderer2d {
Mat4x4 projection;
uint32 shader;
@@ -26,18 +26,18 @@ struct OrthographicRenderer {
void unload();
};
-struct OrthographicVertex {
+struct Vertex2d {
Vector2 position;
Vector4 color;
};
-struct OrthographicShape {
+struct Mesh2d {
uint32 vao;
uint32 vbo;
uint32 numVertices = 0;
Mat4x4 model;
- void load(OrthographicVertex* vertices, uint32 numVertices, OrthographicRenderer* renderer);
- void render(OrthographicRenderer* renderer, GLenum drawType = GL_TRIANGLES);
+ void load(Vertex2d* vertices, uint32 numVertices, Renderer2d* renderer, GLenum loadType = GL_STATIC_DRAW);
+ void render(Renderer2d* renderer, GLenum drawType = GL_TRIANGLES);
void unload();
-}; \ No newline at end of file
+};
diff --git a/shared_cpp/WebglHelper.h b/shared_cpp/WebglHelper.h
index dbdb23f..55dfe97 100644
--- a/shared_cpp/WebglHelper.h
+++ b/shared_cpp/WebglHelper.h
@@ -1,6 +1,6 @@
#pragma once
#include "mathlib.h"
-struct OrthographicRenderer;
+struct Renderer2d;
-void render2DArrow(Vector2 start, Vector2 end, OrthographicRenderer* renderer);
+void render2DArrow(Vector2 start, Vector2 end, Renderer2d* renderer);
diff --git a/shared_cpp/mathlib.cpp b/shared_cpp/mathlib.cpp
index 3402f0e..5996ba3 100644
--- a/shared_cpp/mathlib.cpp
+++ b/shared_cpp/mathlib.cpp
@@ -12,6 +12,13 @@
// ***************************************
// Vector2
+Vector2::Vector2() { }
+
+Vector2::Vector2(float inX, float inY) {
+ x = inX;
+ y = inY;
+}
+
Vector2 getRandomNormalVector2() {
Vector2 retval = {
static_cast<float>(rand()) / static_cast<float>(RAND_MAX),
@@ -291,6 +298,10 @@ Vector4 Vector4::cross(const Vector4& other) {
};
}
+Vector4 lerp(Vector4 start, Vector4 end, float t) {
+ return (end - start) * t + start;
+}
+
Vector4 Vector4::operator+(const Vector4& v2) {
return add(v2);
}
diff --git a/shared_cpp/mathlib.h b/shared_cpp/mathlib.h
index 5f9abff..0a39195 100644
--- a/shared_cpp/mathlib.h
+++ b/shared_cpp/mathlib.h
@@ -36,6 +36,8 @@ struct Vector2 {
float x = 0;
float y = 0;
+ Vector2();
+ Vector2(float inX, float inY);
Vector2 operator+(Vector2 other);
Vector2& operator+=(Vector2 other);
Vector2 operator-(Vector2 other);
@@ -113,6 +115,8 @@ struct Vector4 {
void printDebug(const char* name);
};
+Vector4 lerp(Vector4 start, Vector4 end, float t);
+
struct Mat4x4 {
float m[16] = {
1, 0, 0, 0,
diff --git a/tools/transpiler/pages.txt b/tools/transpiler/pages.txt
index 87bf1b4..26c77d1 100644
--- a/tools/transpiler/pages.txt
+++ b/tools/transpiler/pages.txt
@@ -6,6 +6,8 @@
>"Collisions"
>>/2d/_collisions/rectangle_rectangle.html "Rectangle-Rectangle"
>>/2d/_collisions/polygon_polygon.html "Separating Axis Theorem"
+>"Softbody"
+>>/2d/softbody/softbody_1.html "Springs"
&#127776; "3D"
>"Rigidbody"
>>/3d/rigidbody.html "Rigidbody in 3D"