summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Kosarek <mattkae@protonmail.com>2021-03-16 22:03:10 -0400
committerMatthew Kosarek <mattkae@protonmail.com>2021-03-16 22:03:10 -0400
commit1a08dd2bd6839f0be4b12dc5317ab0b00ca23ae1 (patch)
treef204817e3dd98358016006d04c39f6ff84c52754
parent98d7d6cb702af2708f20e7cf16ee10a9f71b578a (diff)
Proper update loop for a WebAssembly scene running
-rwxr-xr-x[-rw-r--r--]frontend/_wasm/build.sh0
-rw-r--r--frontend/_wasm/intro.html6
-rw-r--r--frontend/_wasm/mathlib.h17
-rw-r--r--frontend/_wasm/output.js116
-rwxr-xr-x[-rw-r--r--]frontend/_wasm/output.wasmbin26645 -> 29351 bytes
-rw-r--r--frontend/_wasm/wasm.cpp124
-rw-r--r--frontend/_wasm/wasm.js11
-rw-r--r--frontend/index.css60
8 files changed, 240 insertions, 94 deletions
diff --git a/frontend/_wasm/build.sh b/frontend/_wasm/build.sh
index 98bf2c4..98bf2c4 100644..100755
--- a/frontend/_wasm/build.sh
+++ b/frontend/_wasm/build.sh
diff --git a/frontend/_wasm/intro.html b/frontend/_wasm/intro.html
index 853d7ac..9b0d6d5 100644
--- a/frontend/_wasm/intro.html
+++ b/frontend/_wasm/intro.html
@@ -42,10 +42,10 @@
<div class="opengl_canvas_sidebar">
</div>
- <button class="play_button">
+ <button class="play_button" id="wasm_canvas_play_button">
Play
</button>
- <button class="stop_button">
+ <button class="stop_button" id="wasm_canvas_stop_button">
Stop
</button>
</div>
@@ -53,4 +53,4 @@
</section>
</main>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/frontend/_wasm/mathlib.h b/frontend/_wasm/mathlib.h
index bc84b72..93ddbbd 100644
--- a/frontend/_wasm/mathlib.h
+++ b/frontend/_wasm/mathlib.h
@@ -86,6 +86,13 @@ struct Mat4x4 {
return result;
}
+ Mat4x4 translateByVec2(Vector2 v) {
+ Mat4x4 result = copy();
+ result.m[12] += v.x;
+ result.m[13] += v.y;
+ return result;
+ }
+
Mat4x4 rotate2D(float angle) {
Mat4x4 result = copy();
result.m[0] = cos(angle);
@@ -112,4 +119,12 @@ struct Mat4x4 {
result.m[13] = -(top + bottom) / (top - bottom);
return result;
}
-}; \ No newline at end of file
+
+ void print() {
+ printf("[ ");
+ for (int idx = 0; idx < 16; idx++) {
+ printf("%d, ", idx);
+ }
+ printf(" ]\n");
+ }
+};
diff --git a/frontend/_wasm/output.js b/frontend/_wasm/output.js
index 0a0a401..ee8462a 100644
--- a/frontend/_wasm/output.js
+++ b/frontend/_wasm/output.js
@@ -252,9 +252,7 @@ moduleOverrides = null;
// 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')) {
+if (Module['arguments']) arguments_ = Module['arguments'];if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) {
Object.defineProperty(Module, 'arguments', {
configurable: true,
get: function() {
@@ -262,9 +260,7 @@ if (!Object.getOwnPropertyDescriptor(Module, 'arguments')) {
}
});
}
-
-if (Module['thisProgram']) thisProgram = Module['thisProgram'];
-if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) {
+if (Module['thisProgram']) thisProgram = Module['thisProgram'];if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) {
Object.defineProperty(Module, 'thisProgram', {
configurable: true,
get: function() {
@@ -272,9 +268,7 @@ if (!Object.getOwnPropertyDescriptor(Module, 'thisProgram')) {
}
});
}
-
-if (Module['quit']) quit_ = Module['quit'];
-if (!Object.getOwnPropertyDescriptor(Module, 'quit')) {
+if (Module['quit']) quit_ = Module['quit'];if (!Object.getOwnPropertyDescriptor(Module, 'quit')) {
Object.defineProperty(Module, 'quit', {
configurable: true,
get: function() {
@@ -294,7 +288,6 @@ assert(typeof Module['readAsync'] === 'undefined', 'Module.readAsync option was
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,
@@ -303,7 +296,6 @@ if (!Object.getOwnPropertyDescriptor(Module, 'read')) {
}
});
}
-
if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) {
Object.defineProperty(Module, 'readAsync', {
configurable: true,
@@ -312,7 +304,6 @@ if (!Object.getOwnPropertyDescriptor(Module, 'readAsync')) {
}
});
}
-
if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) {
Object.defineProperty(Module, 'readBinary', {
configurable: true,
@@ -321,7 +312,6 @@ if (!Object.getOwnPropertyDescriptor(Module, 'readBinary')) {
}
});
}
-
if (!Object.getOwnPropertyDescriptor(Module, 'setWindowTitle')) {
Object.defineProperty(Module, 'setWindowTitle', {
configurable: true,
@@ -572,9 +562,7 @@ function getCompilerSetting(name) {
// 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')) {
+var wasmBinary;if (Module['wasmBinary']) wasmBinary = Module['wasmBinary'];if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) {
Object.defineProperty(Module, 'wasmBinary', {
configurable: true,
get: function() {
@@ -582,8 +570,7 @@ if (!Object.getOwnPropertyDescriptor(Module, 'wasmBinary')) {
}
});
}
-var noExitRuntime = Module['noExitRuntime'] || true;
-if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) {
+var noExitRuntime;if (Module['noExitRuntime']) noExitRuntime = Module['noExitRuntime'];if (!Object.getOwnPropertyDescriptor(Module, 'noExitRuntime')) {
Object.defineProperty(Module, 'noExitRuntime', {
configurable: true,
get: function() {
@@ -1195,8 +1182,7 @@ function updateGlobalBufferAndViews(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')) {
+var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216;if (!Object.getOwnPropertyDescriptor(Module, 'INITIAL_MEMORY')) {
Object.defineProperty(Module, 'INITIAL_MEMORY', {
configurable: true,
get: function() {
@@ -1774,6 +1760,15 @@ var ASM_CONSTS = {
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_get_heap_size() {
return HEAPU8.length;
}
@@ -1791,31 +1786,32 @@ var ASM_CONSTS = {
// anyhow)
}
function _emscripten_resize_heap(requestedSize) {
+ requestedSize = requestedSize >>> 0;
var oldSize = _emscripten_get_heap_size();
// 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
+ // 1. When resizing, always produce a resized heap that is at least 16MB (to avoid tiny heap sizes receiving lots of repeated resizes at startup)
+ // 2. Always increase heap size to at least the requested size, rounded up to next page multiple.
+ // 3a. 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.
+ // 3b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap linearly: increase the heap size by at least MEMORY_GROWTH_LINEAR_STEP bytes.
+ // 4. 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
+ // 5. 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 was set for how much we can grow. We should not exceed that
// (the wasm binary specifies it, so if we tried, we'd fail anyhow).
- // In CAN_ADDRESS_2GB mode, stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate full 4GB Wasm memories, the size will wrap
- // back to 0 bytes in Wasm side for any code that deals with heap sizes, which would require special casing all heap size related code to treat
- // 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;
}
+ var minHeapSize = 16777216;
+
// 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) {
@@ -1823,7 +1819,7 @@ var ASM_CONSTS = {
// but limit overreserving (default to capping at +96MB overgrowth at most)
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 );
- var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
+ var newSize = Math.min(maxHeapSize, alignUp(Math.max(minHeapSize, requestedSize, overGrownHeapSize), 65536));
var replacement = emscripten_realloc_buffer(newSize);
if (replacement) {
@@ -1963,6 +1959,62 @@ var ASM_CONSTS = {
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);
+ var idx = eventStruct >> 2;
+ HEAP32[idx + 0] = e.screenX;
+ HEAP32[idx + 1] = e.screenY;
+ HEAP32[idx + 2] = e.clientX;
+ HEAP32[idx + 3] = e.clientY;
+ HEAP32[idx + 4] = e.ctrlKey;
+ HEAP32[idx + 5] = e.shiftKey;
+ HEAP32[idx + 6] = e.altKey;
+ HEAP32[idx + 7] = e.metaKey;
+ HEAP16[idx*2 + 16] = e.button;
+ HEAP16[idx*2 + 17] = e.buttons;
+
+ HEAP32[idx + 9] = e["movementX"]
+ ;
+
+ HEAP32[idx + 10] = e["movementY"]
+ ;
+
+ var rect = getBoundingClientRect(target);
+ HEAP32[idx + 11] = e.clientX - rect.left;
+ HEAP32[idx + 12] = e.clientY - rect.top;
+
+ }
+ function registerMouseEventCallback(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) {
+ if (!JSEvents.mouseEvent) JSEvents.mouseEvent = _malloc( 64 );
+ 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');
@@ -2762,8 +2814,10 @@ function intArrayToString(array) {
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,
@@ -2907,8 +2961,6 @@ if (!Object.getOwnPropertyDescriptor(Module, "ENV")) Module["ENV"] = function()
if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_CODES")) Module["ERRNO_CODES"] = function() { abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "ERRNO_MESSAGES")) Module["ERRNO_MESSAGES"] = function() { abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "setErrNo")) Module["setErrNo"] = function() { abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "readSockaddr")) Module["readSockaddr"] = function() { abort("'readSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "writeSockaddr")) Module["writeSockaddr"] = function() { abort("'writeSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() { abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "getHostByName")) Module["getHostByName"] = function() { abort("'getHostByName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "GAI_ERRNO_MESSAGES")) Module["GAI_ERRNO_MESSAGES"] = function() { abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3272,6 +3324,8 @@ var shouldRunNow = true;
if (Module['noInitialRun']) shouldRunNow = false;
+noExitRuntime = true;
+
run();
diff --git a/frontend/_wasm/output.wasm b/frontend/_wasm/output.wasm
index bde2a03..2ec3de9 100644..100755
--- a/frontend/_wasm/output.wasm
+++ b/frontend/_wasm/output.wasm
Binary files differ
diff --git a/frontend/_wasm/wasm.cpp b/frontend/_wasm/wasm.cpp
index 91d440f..8673c80 100644
--- a/frontend/_wasm/wasm.cpp
+++ b/frontend/_wasm/wasm.cpp
@@ -1,6 +1,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <sys/time.h>
#include <emscripten.h>
#include <emscripten/html5.h>
#include <GLES2/gl2.h>
@@ -50,6 +51,7 @@ struct OrthographicVertex {
// Create a triangle
struct TriangleObject {
OrthographicVertex vertices[3];
+ Vector2 velocity;
GLuint mVao;
GLuint mVbo;
Mat4x4 model;
@@ -88,6 +90,28 @@ struct TriangleObject {
};
+struct Scene {
+ Mat4x4 projection;
+ TriangleObject triangleObject;
+ OrthographicProgramData programData;
+ bool isTerminated = false;
+};
+
+long long timeInMilliseconds(void) {
+ struct timeval tv;
+
+ gettimeofday(&tv,NULL);
+ return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
+}
+
+long elapsedTime = 0;
+long lastTime = 0;
+int numFrames = 0;
+
+EM_BOOL update(double time, void* userData);
+EM_BOOL runScene(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+EM_BOOL terminateScene(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+
int main() {
printf("Initializing the canvas...\n");
emscripten_set_canvas_element_size( "#wasm_canvas", 640, 480 );
@@ -111,35 +135,83 @@ int main() {
}
emscripten_webgl_make_context_current(context);
printf("Canvas ready.\n");
-
- printf("Compiling shaders...\n");
- GLuint shader = loadShader(orthographicVertex, orthographicFragment);
- useShader(shader);
- OrthographicProgramData programData;
- programData.shader = shader;
- programData.attributes.position = getShaderAttribute(shader, "position");
- programData.attributes.color = getShaderAttribute(shader, "color");
- programData.uniformVariables.projection = getShaderUniform(shader, "projection");
- programData.uniformVariables.model = getShaderUniform(shader, "model");
- printf("Compiling ready.\n");
-
- TriangleObject triangle;
- triangle.vertices[0] = { Vector2 { 50, 50 }, Vector4 { 1.f, 0.f, 0.f, 1.f }};
- triangle.vertices[1] = { Vector2 { 150, 300 }, Vector4 { 0.f, 1.f, 0.f, 1.f }};
- triangle.vertices[2] = { Vector2 { 250, 50 }, Vector4 { 0.f, 0.f, 1.f, 1.f }};
- triangle.initialize(&programData);
-
- Mat4x4 projection = Mat4x4().getOrthographicMatrix(0, 480, 0, 640);
-
- glEnable(GL_DEPTH_TEST);
+
+ emscripten_set_click_callback("#wasm_canvas_play_button", NULL, false, runScene);
+ emscripten_set_click_callback("#wasm_canvas_stop_button", NULL, false, terminateScene);
+ return EXIT_SUCCESS;
+}
+
+Scene scene;
+
+EM_BOOL runScene(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Compiling shaders...\n");
+ scene.programData.shader = loadShader(orthographicVertex, orthographicFragment);
+ printf("Shaders compiled.\n");
+
+
+ printf("Initializing scene...\n");
+ useShader(scene.programData.shader);
+ scene.programData.attributes.position = getShaderAttribute(scene.programData.shader, "position");
+ scene.programData.attributes.color = getShaderAttribute(scene.programData.shader, "color");
+ scene.programData.uniformVariables.projection = getShaderUniform(scene.programData.shader, "projection");
+ scene.programData.uniformVariables.model = getShaderUniform(scene.programData.shader, "model");
+
+ scene.triangleObject.vertices[0] = { Vector2 { 220, 365 }, Vector4 { 1.f, 0.f, 0.f, 1.f }};
+ scene.triangleObject.vertices[1] = { Vector2 { 320, 480 }, Vector4 { 0.f, 1.f, 0.f, 1.f }};
+ scene.triangleObject.vertices[2] = { Vector2 { 420, 365 }, Vector4 { 0.f, 0.f, 1.f, 1.f }};
+ scene.triangleObject.initialize(&scene.programData);
+
+ scene.projection = Mat4x4().getOrthographicMatrix(0, 640, 0, 480);
+ scene.isTerminated = false;
+ printf("Scene initialized.\n");
+
+ emscripten_request_animation_frame_loop(update, &scene);
+ return true;
+}
+
+EM_BOOL update(double time, void* userData) {
+ Scene* scene = (Scene*)userData;
+ if (scene->isTerminated) {
+ return false;
+ }
+
+ if (lastTime == 0) {
+ lastTime = time;
+ return true;
+ }
+
+ long deltaTime = time - lastTime;
+ lastTime = time;
+ elapsedTime += deltaTime;
+ numFrames++;
+
+ if (elapsedTime >= 1000.0) {
+ printf("Frames Per Second: %d\n", numFrames);
+ numFrames = 0;
+ elapsedTime = 0.0;
+ }
+
+ float deltaTimeSeconds = static_cast<float>(deltaTime) / 1000.f;
+
+ // Update
+ scene->triangleObject.velocity = scene->triangleObject.velocity + Vector2 { 0, static_cast<float>(-9.8 * deltaTimeSeconds) };
+ scene->triangleObject.model = scene->triangleObject.model.translateByVec2(scene->triangleObject.velocity * deltaTimeSeconds);
+
+ // Render
+ glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- useShader(shader);
- setShaderMat4(programData.uniformVariables.projection, projection);
- triangle.render(&programData);
+ useShader(scene->programData.shader);
+ setShaderMat4(scene->programData.uniformVariables.projection, scene->projection);
+ scene->triangleObject.render(&scene->programData);
- return EXIT_SUCCESS;
-} \ No newline at end of file
+ return true;
+}
+
+EM_BOOL terminateScene(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ scene.isTerminated = true;
+ return true;
+}
diff --git a/frontend/_wasm/wasm.js b/frontend/_wasm/wasm.js
index 6a3bfae..37d5faf 100644
--- a/frontend/_wasm/wasm.js
+++ b/frontend/_wasm/wasm.js
@@ -3,8 +3,17 @@
(function() {
function main() {
+ $('#wasm_canvas_play_button').on('click', function() {
+ $(this).hide();
+ $("#wasm_canvas_stop_button").show();
+ });
+
+ $('#wasm_canvas_stop_button').on('click', function() {
+ $(this).hide();
+ $("#wasm_canvas_play_button").show();
+ });
}
$(document).ready(main);
-})() \ No newline at end of file
+})()
diff --git a/frontend/index.css b/frontend/index.css
index 010d543..9f23e96 100644
--- a/frontend/index.css
+++ b/frontend/index.css
@@ -1,31 +1,36 @@
+html {
+ width: 100vw;
+ background: #2f3032;
+}
+
body {
+ background: #2f3032;
+ min-height: calc(100vh - 64px);
+ background: -webkit-radial-gradient(top, #383A56, #303133);
+ background: -moz-radial-gradient(top, #383A56, #303133);
+ background: radial-gradient(to bottom, #383A56, #303133);
font-size: 16px;
font-family: "Helvetica", sans-serif;
- line-height: 1.5rem;
- width: 100%;
- height: 100vh;
- margin: 0rem;
- padding: 0rem;
+ line-height: 1.75rem;
+ width: 960px;
+ margin: auto;
overflow-x: auto;
overflow-y: auto;
- background-color: #2f3032;
color: white;
+ margin-top: 32px;
+ margin-bottom: 32px;
+ border-radius: 8px;
+ border: 1px solid #383A56;
+ padding: 32px;
}
header {
+ border-bottom: 2px solid #2f3032;
padding-top: 1rem;
padding-bottom: 1rem;
font-size: 20px;
- margin: auto;
- width: 1260px;
- max-width: 1260px;
text-align: center;
border-radius: 0px 0px 3px 3px;
-
- background: #383A56;
- background: -webkit-radial-gradient(top, #383A56, #303133, #303133);
- background: -moz-radial-gradient(top, #383A56, #303133, #303133);
- background: radial-gradient(to bottom, #383A56, #303133, #303133);
}
header > h1 {
@@ -37,10 +42,6 @@ header > h1 {
main {
display: flex;
flex-direction: row;
- width: 1260px;
- margin: auto;
- max-width: 1260px;
- flex: 1 1 100%;
margin-bottom: 1rem;
overflow-y: hidden;
}
@@ -198,7 +199,7 @@ article .opengl_canvas_container {
width: 100%;
text-align: center;
display: flex;
- flex-direction: row;
+ flex-direction: column;
justify-content: center;
border-radius: 3px;
}
@@ -210,7 +211,7 @@ article .opengl_canvas_container .play_button {
height: 128px;
position: absolute;
top: calc(50% - 56px);
- left: calc(50% - 214px);
+ left: calc(50% - 56px);
border: 1px solid white;
color: white;
background-color: transparent;
@@ -222,7 +223,7 @@ article .opengl_canvas_container .play_button {
}
.opengl_canvas_container canvas {
- border-radius: 3px 0px 0px 3px;
+ border-radius: 3px 3px 0px 0px;
border: 1px solid #b0a565;
}
@@ -256,22 +257,17 @@ article pre {
}
.opengl_canvas_sidebar {
- width: 312px;
- height: 480px;
border: 1px solid #b0a565;
- border-left: none;
-
- display: flex;
- flex-direction: column;
- text-align: left;
- justify-content: space-between;
+ border-radius: 0px 0px 3px 3px;
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
}
.opengl_canvas_sidebar .opengl_value_tracker {
+ grid-column: 1 span /4;
font-size: 14px;
- display: flex;
- flex-direction: column;
- text-align: left;
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
}
.opengl_canvas_sidebar .opengl_value_tracker > li {