summaryrefslogtreecommitdiff
path: root/2d/rigidbody
diff options
context:
space:
mode:
authorMatthew Kosarek <mattkae@protonmail.com>2021-05-24 13:32:27 -0400
committerMatthew Kosarek <mattkae@protonmail.com>2021-05-24 13:32:27 -0400
commitc5e5d7c939a2640763775b0688ed698c51ec28c1 (patch)
treeeaa9f5493cf218471f96207d2fa86a9192f07606 /2d/rigidbody
parentd5326e9f605e11fc33a7f37cc0ae674258de2424 (diff)
Applying force to the object using the mouse cursor
Diffstat (limited to '2d/rigidbody')
-rw-r--r--2d/rigidbody/rigidbody_1.html31
-rw-r--r--2d/rigidbody/rigidbody_1.html.content13
-rw-r--r--2d/rigidbody/rigidbody_1/dist/output.js319
-rwxr-xr-x2d/rigidbody/rigidbody_1/dist/output.wasmbin33767 -> 47023 bytes
-rw-r--r--2d/rigidbody/rigidbody_1/main.cpp113
5 files changed, 247 insertions, 229 deletions
diff --git a/2d/rigidbody/rigidbody_1.html b/2d/rigidbody/rigidbody_1.html
index 8fdcd07..83cc237 100644
--- a/2d/rigidbody/rigidbody_1.html
+++ b/2d/rigidbody/rigidbody_1.html
@@ -18,14 +18,14 @@
<span>&#127936;<span>2D</span></span>
<ul class="inner-tree">
<li><label>Rigidbody</label></li>
- <li><a href="/2d/rigidbody/rigidbody_1.html">Linear Forces</a></li>
+ <li><a title="/2d/rigidbody/rigidbody_1.html" href="/2d/rigidbody/rigidbody_1.html">Linear Forces</a></li>
<li><label>Collisions</label></li>
- <li><a href="/2d/_collisions/circle_line.html">Circle-Line</a></li>
- <li><a href="/2d/_collisions/rectangle_line.html">Rectangle-Line</a></li>
- <li><a href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
- <li><a href="/2d/_collisions/pill_line.html">Pill-Line</a></li>
- <li><a href="/2d/_collisions/pill_pill.html">Pill-Pill</a></li>
- <li><a href="/2d/_collisions/polygon_polygon.html">Polygon-Polygon</a></li>
+ <li><a title="/2d/_collisions/circle_line.html" href="/2d/_collisions/circle_line.html">Circle-Line</a></li>
+ <li><a title="/2d/_collisions/rectangle_line.html" href="/2d/_collisions/rectangle_line.html">Rectangle-Line</a></li>
+ <li><a title="/2d/_collisions/rectangle_rectangle.html" href="/2d/_collisions/rectangle_rectangle.html">Rectangle-Rectangle</a></li>
+ <li><a title="/2d/_collisions/pill_line.html" href="/2d/_collisions/pill_line.html">Pill-Line</a></li>
+ <li><a title="/2d/_collisions/pill_pill.html" href="/2d/_collisions/pill_pill.html">Pill-Pill</a></li>
+ <li><a title="/2d/_collisions/polygon_polygon.html" href="/2d/_collisions/polygon_polygon.html">Polygon-Polygon</a></li>
</ul>
</li>
<li>
@@ -36,13 +36,13 @@
<li>
<span>&#128295;<span>WebAssembly</span></span>
<ul class="inner-tree">
- <li><a href="/intro/intro.html">Introduction</a></li>
+ <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 href="/roadmap.html">Roadmap</a></li>
+ <li><a title="/roadmap.html" href="/roadmap.html">Roadmap</a></li>
</ul>
</li>
</ul>
@@ -80,19 +80,8 @@
<h2>
Live Example
</h2>
- <div>
- <div class="vector_group">
- <label>Force (N)</label>
-
- <input id="force_x" type="number" placeholder="X (Default = 10 N)" step="any"/>
- <input id="force_y" type="number" placeholder="Y (Default = 20 N)" step="any"/>
- </div>
-
- <button id="apply_force">Apply Force</button>
-
- </div>
<div class="opengl_canvas_container">
- <canvas id="gl_canvas" width="640" height="480"></canvas>
+ <canvas id="gl_canvas" width="800" height="600"></canvas>
<button id="gl_canvas_play" class="play_button">
Play
</button>
diff --git a/2d/rigidbody/rigidbody_1.html.content b/2d/rigidbody/rigidbody_1.html.content
index c316188..6ca1619 100644
--- a/2d/rigidbody/rigidbody_1.html.content
+++ b/2d/rigidbody/rigidbody_1.html.content
@@ -31,19 +31,8 @@
<h2>
Live Example
</h2>
- <div>
- <div class="vector_group">
- <label>Force (N)</label>
-
- <input id="force_x" type="number" placeholder="X (Default = 10 N)" step="any"/>
- <input id="force_y" type="number" placeholder="Y (Default = 20 N)" step="any"/>
- </div>
-
- <button id="apply_force">Apply Force</button>
-
- </div>
<div class="opengl_canvas_container">
- <canvas id="gl_canvas" width="640" height="480"></canvas>
+ <canvas id="gl_canvas" width="800" height="600"></canvas>
<button id="gl_canvas_play" class="play_button">
Play
</button>
diff --git a/2d/rigidbody/rigidbody_1/dist/output.js b/2d/rigidbody/rigidbody_1/dist/output.js
index 42a4ed5..9ba383a 100644
--- a/2d/rigidbody/rigidbody_1/dist/output.js
+++ b/2d/rigidbody/rigidbody_1/dist/output.js
@@ -609,7 +609,7 @@ if (typeof WebAssembly !== 'object') {
function setValue(ptr, value, type, noSafe) {
type = type || 'i8';
if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
- switch (type) {
+ switch(type) {
case 'i1': HEAP8[((ptr)>>0)] = value; break;
case 'i8': HEAP8[((ptr)>>0)] = value; break;
case 'i16': HEAP16[((ptr)>>1)] = value; break;
@@ -627,7 +627,7 @@ function setValue(ptr, value, type, noSafe) {
function getValue(ptr, type, noSafe) {
type = type || 'i8';
if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
- switch (type) {
+ switch(type) {
case 'i1': return HEAP8[((ptr)>>0)];
case 'i8': return HEAP8[((ptr)>>0)];
case 'i16': return HEAP16[((ptr)>>1)];
@@ -808,7 +808,7 @@ function UTF8ArrayToString(heap, idx, maxBytesToRead) {
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!');
+ if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string on the asm.js/wasm heap to a JS string!');
u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heap[idx++] & 63);
}
@@ -884,7 +884,7 @@ function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {
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).');
+ if (u >= 0x200000) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (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);
@@ -1252,12 +1252,12 @@ function checkStackCookie() {
// include: runtime_assertions.js
-// Endianness check
+// Endianness check (note: assumes compiler arch was little-endian)
(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)';
+ if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian!';
})();
function abortFnPtrError(ptr, sig) {
@@ -1274,6 +1274,8 @@ var __ATPOSTRUN__ = []; // functions called after the main() is called
var runtimeInitialized = false;
var runtimeExited = false;
+__ATINIT__.push({ func: function() { ___wasm_call_ctors() } });
+
function preRun() {
if (Module['preRun']) {
@@ -1290,7 +1292,6 @@ function initRuntime() {
checkStackCookie();
assert(!runtimeInitialized);
runtimeInitialized = true;
-
callRuntimeCallbacks(__ATINIT__);
}
@@ -1615,8 +1616,6 @@ function createWasm() {
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)
@@ -1638,8 +1637,7 @@ function createWasm() {
function instantiateArrayBuffer(receiver) {
return getBinaryPromise().then(function(binary) {
- var result = WebAssembly.instantiate(binary, info);
- return result;
+ return WebAssembly.instantiate(binary, info);
}).then(receiver, function(reason) {
err('failed to asynchronously prepare wasm: ' + reason);
@@ -1706,8 +1704,12 @@ var ASM_CONSTS = {
+ function abortStackOverflow(allocSize) {
+ abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (_emscripten_stack_get_free() + allocSize) + ' bytes available!');
+ }
+
function callRuntimeCallbacks(callbacks) {
- while (callbacks.length > 0) {
+ while(callbacks.length > 0) {
var callback = callbacks.shift();
if (typeof callback == 'function') {
callback(Module); // Pass the module as the first argument.
@@ -1758,11 +1760,6 @@ var ASM_CONSTS = {
return error.stack.toString();
}
- var runtimeKeepaliveCounter=0;
- function keepRuntimeAlive() {
- return noExitRuntime || runtimeKeepaliveCounter > 0;
- }
-
function stackTrace() {
var js = jsStackTrace();
if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
@@ -1786,6 +1783,10 @@ var ASM_CONSTS = {
return requestAnimationFrame(tick);
}
+ function _emscripten_get_heap_size() {
+ return HEAPU8.length;
+ }
+
function emscripten_realloc_buffer(size) {
try {
// round size grow request up to wasm page size (fixed 64KB per spec)
@@ -1799,8 +1800,7 @@ var ASM_CONSTS = {
// anyhow)
}
function _emscripten_resize_heap(requestedSize) {
- var oldSize = HEAPU8.length;
- 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);
@@ -1827,7 +1827,7 @@ var ASM_CONSTS = {
// 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) {
+ 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 );
@@ -1845,7 +1845,7 @@ var ASM_CONSTS = {
}
var JSEvents={inEventHandler:0,removeAllEventListeners:function() {
- for (var i = JSEvents.eventHandlers.length-1; i >= 0; --i) {
+ for(var i = JSEvents.eventHandlers.length-1; i >= 0; --i) {
JSEvents._removeHandler(i);
}
JSEvents.eventHandlers = [];
@@ -1859,13 +1859,13 @@ var ASM_CONSTS = {
function arraysHaveEqualContent(arrA, arrB) {
if (arrA.length != arrB.length) return false;
- for (var i in arrA) {
+ 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) {
+ for(var i in JSEvents.deferredCalls) {
var call = JSEvents.deferredCalls[i];
if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) {
return;
@@ -1879,7 +1879,7 @@ var ASM_CONSTS = {
JSEvents.deferredCalls.sort(function(x,y) { return x.precedence < y.precedence; });
},removeDeferredCalls:function(targetFunction) {
- for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
+ for(var i = 0; i < JSEvents.deferredCalls.length; ++i) {
if (JSEvents.deferredCalls[i].targetFunction == targetFunction) {
JSEvents.deferredCalls.splice(i, 1);
--i;
@@ -1891,14 +1891,14 @@ var ASM_CONSTS = {
if (!JSEvents.canPerformEventHandlerRequests()) {
return;
}
- for (var i = 0; i < JSEvents.deferredCalls.length; ++i) {
+ 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) {
+ for(var i = 0; i < JSEvents.eventHandlers.length; ++i) {
if (JSEvents.eventHandlers[i].target == target &&
(!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) {
JSEvents._removeHandler(i--);
@@ -1929,7 +1929,7 @@ var ASM_CONSTS = {
JSEvents.eventHandlers.push(eventHandler);
JSEvents.registerRemoveEventListeners();
} else {
- for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
+ 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--);
@@ -2028,6 +2028,11 @@ var ASM_CONSTS = {
return 0;
}
+ function _emscripten_set_mousemove_callback_on_thread(target, userData, useCapture, callbackfunc, targetThread) {
+ registerMouseEventCallback(target, userData, useCapture, callbackfunc, 8, "mousemove", 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');
@@ -2074,7 +2079,7 @@ var ASM_CONSTS = {
// Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted.
return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw'));
}
- var GL={counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode) {
+ var GL={counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],uniforms:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},timerQueriesEXT:[],queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],programInfos:{},stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode) {
if (!GL.lastError) {
GL.lastError = errorCode;
}
@@ -2085,7 +2090,7 @@ var ASM_CONSTS = {
}
return ret;
},MAX_TEMP_BUFFER_SIZE:2097152,numTempVertexBuffersPerSize:64,log2ceilLookup:function(i) {
- return 32 - Math.clz32(i === 0 ? 0 : i - 1);
+ return 32 - Math.clz32(i-1);
},generateTempBuffers:function(quads, context) {
var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
context.tempVertexBufferCounters1 = [];
@@ -2213,19 +2218,6 @@ var ASM_CONSTS = {
}
},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)
?
@@ -2298,21 +2290,7 @@ var ASM_CONSTS = {
__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
- // On WebGL 2, EXT_disjoint_timer_query is replaced with an alternative
- // that's based on core APIs, and exposes only the queryCounterEXT()
- // entrypoint.
- if (context.version >= 2) {
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query_webgl2");
- }
-
- // However, Firefox exposes the WebGL 1 version on WebGL 2 as well and
- // thus we look for the WebGL 1 version again if the WebGL 2 version
- // isn't present. https://bugzilla.mozilla.org/show_bug.cgi?id=1328882
- if (context.version < 2 || !GLctx.disjointTimerQueryExt)
- {
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
- }
-
+ GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
__webgl_enable_WEBGL_multi_draw(GLctx);
// .getSupportedExtensions() can return null if context is lost, so coerce to empty array.
@@ -2324,6 +2302,49 @@ var ASM_CONSTS = {
GLctx.getExtension(ext);
}
});
+ },populateUniformTable:function(program) {
+ var p = GL.programs[program];
+ var ptable = GL.programInfos[program] = {
+ uniforms: {},
+ maxUniformLength: 0, // This is eagerly computed below, since we already enumerate all uniforms anyway.
+ maxAttributeLength: -1, // This is lazily computed and cached, computed when/if first asked, "-1" meaning not computed yet.
+ maxUniformBlockNameLength: -1 // Lazily computed as well
+ };
+
+ var utable = ptable.uniforms;
+ // A program's uniform table maps the string name of an uniform to an integer location of that uniform.
+ // The global GL.uniforms map maps integer locations to WebGLUniformLocations.
+ var numUniforms = GLctx.getProgramParameter(p, 0x8B86/*GL_ACTIVE_UNIFORMS*/);
+ for (var i = 0; i < numUniforms; ++i) {
+ var u = GLctx.getActiveUniform(p, i);
+
+ var name = u.name;
+ ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1);
+
+ // If we are dealing with an array, e.g. vec4 foo[3], strip off the array index part to canonicalize that "foo", "foo[]",
+ // and "foo[0]" will mean the same. Loop below will populate foo[1] and foo[2].
+ if (name.slice(-1) == ']') {
+ name = name.slice(0, name.lastIndexOf('['));
+ }
+
+ // Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then
+ // only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i.
+ // Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices.
+ var loc = GLctx.getUniformLocation(p, name);
+ if (loc) {
+ var id = GL.getNewId(GL.uniforms);
+ utable[name] = [u.size, id];
+ GL.uniforms[id] = loc;
+
+ for (var j = 1; j < u.size; ++j) {
+ var n = name + '['+j+']';
+ loc = GLctx.getUniformLocation(p, n);
+ id = GL.getNewId(GL.uniforms);
+
+ GL.uniforms[id] = loc;
+ }
+ }
+ }
}};
var __emscripten_webgl_power_preferences=['default', 'low-power', 'high-performance'];
@@ -2370,7 +2391,7 @@ var ASM_CONSTS = {
function _emscripten_webgl_init_context_attributes(attributes) {
assert(attributes);
var a = attributes >> 2;
- for (var i = 0; i < (56>>2); ++i) {
+ for(var i = 0; i < (56>>2); ++i) {
HEAP32[a+i] = 0;
}
@@ -2434,7 +2455,8 @@ var ASM_CONSTS = {
}
function _glAttachShader(program, shader) {
- GLctx.attachShader(GL.programs[program], GL.shaders[shader]);
+ GLctx.attachShader(GL.programs[program],
+ GL.shaders[shader]);
}
function _glBindBuffer(target, buffer) {
@@ -2494,11 +2516,7 @@ var ASM_CONSTS = {
function _glCreateProgram() {
var id = GL.getNewId(GL.programs);
var program = GLctx.createProgram();
- // Store additional information needed for each shader program:
program.name = id;
- // Lazy cache results of glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH)
- program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0;
- program.uniformIdCounter = 1;
GL.programs[id] = program;
return id;
}
@@ -2506,7 +2524,6 @@ var ASM_CONSTS = {
function _glCreateShader(shaderType) {
var id = GL.getNewId(GL.shaders);
GL.shaders[id] = GLctx.createShader(shaderType);
-
return id;
}
@@ -2540,6 +2557,7 @@ var ASM_CONSTS = {
GLctx.deleteProgram(program);
program.name = 0;
GL.programs[id] = null;
+ GL.programInfos[id] = null;
}
function _glDeleteShader(id) {
@@ -2632,35 +2650,42 @@ var ASM_CONSTS = {
return;
}
- program = GL.programs[program];
+ var ptable = GL.programInfos[program];
+ if (!ptable) {
+ GL.recordError(0x502 /* GL_INVALID_OPERATION */);
+ return;
+ }
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- var log = GLctx.getProgramInfoLog(program);
+ var log = GLctx.getProgramInfoLog(GL.programs[program]);
if (log === null) log = '(unknown error)';
HEAP32[((p)>>2)] = log.length + 1;
} else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) {
- if (!program.maxUniformLength) {
- for (var i = 0; i < GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); ++i) {
- program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i).name.length+1);
- }
- }
- HEAP32[((p)>>2)] = program.maxUniformLength;
+ HEAP32[((p)>>2)] = ptable.maxUniformLength;
} else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) {
- if (!program.maxAttributeLength) {
- for (var i = 0; i < GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/); ++i) {
- program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i).name.length+1);
+ if (ptable.maxAttributeLength == -1) {
+ program = GL.programs[program];
+ var numAttribs = GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/);
+ ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned.
+ for (var i = 0; i < numAttribs; ++i) {
+ var activeAttrib = GLctx.getActiveAttrib(program, i);
+ ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1);
}
}
- HEAP32[((p)>>2)] = program.maxAttributeLength;
+ HEAP32[((p)>>2)] = ptable.maxAttributeLength;
} else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) {
- if (!program.maxUniformBlockNameLength) {
- for (var i = 0; i < GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); ++i) {
- program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1);
+ if (ptable.maxUniformBlockNameLength == -1) {
+ program = GL.programs[program];
+ var numBlocks = GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/);
+ ptable.maxUniformBlockNameLength = 0;
+ for (var i = 0; i < numBlocks; ++i) {
+ var activeBlockName = GLctx.getActiveUniformBlockName(program, i);
+ ptable.maxUniformBlockNameLength = Math.max(ptable.maxUniformBlockNameLength, activeBlockName.length+1);
}
}
- HEAP32[((p)>>2)] = program.maxUniformBlockNameLength;
+ HEAP32[((p)>>2)] = ptable.maxUniformBlockNameLength;
} else {
- HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname);
+ HEAP32[((p)>>2)] = GLctx.getProgramParameter(GL.programs[program], pname);
}
}
@@ -2703,91 +2728,27 @@ var ASM_CONSTS = {
return parseInt(str);
}
function _glGetUniformLocation(program, name) {
- // Returns the index of '[' character in an uniform that represents an array of uniforms (e.g. colors[10])
- // Closure does counterproductive inlining: https://github.com/google/closure-compiler/issues/3203, so prevent
- // inlining manually.
- /** @noinline */
- function getLeftBracePos(name) {
- return name.slice(-1) == ']' && name.lastIndexOf('[');
- }
-
name = UTF8ToString(name);
- program = GL.programs[program];
- var uniformLocsById = program.uniformLocsById; // Maps GLuint -> WebGLUniformLocation
- var uniformSizeAndIdsByName = program.uniformSizeAndIdsByName; // Maps name -> [uniform array length, GLuint]
- var i, j;
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 = getLeftBracePos(name);
-
- // 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 = getLeftBracePos(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;
- }
- }
- }
-
// 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);
+ if (name[name.length - 1] == ']') {
+ var leftBrace = name.lastIndexOf('[');
+ arrayIndex = name[leftBrace+1] != ']' ? jstoi_q(name.slice(leftBrace + 1)) : 0; // "index]", parseInt will ignore the ']' at the end; but treat "foo[]" as "foo[0]"
+ name = name.slice(0, leftBrace);
}
- // Have we cached the location of this uniform before?
- var sizeAndId = uniformSizeAndIdsByName[uniformBaseName]; // A pair [array length, GLint of the uniform location]
-
- // If an uniform with this name exists, and if its index is within the array limits (if it's even an array),
- // query the WebGLlocation, or return an existing cached location.
- if (sizeAndId && arrayIndex < sizeAndId[0]) {
- arrayIndex += sizeAndId[1]; // Add the base location of the uniform to the array index offset.
- if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) {
- return arrayIndex;
- }
+ var uniformInfo = GL.programInfos[program] && GL.programInfos[program].uniforms[name]; // returns pair [ dimension_of_uniform_array, uniform_location ]
+ if (uniformInfo && arrayIndex >= 0 && arrayIndex < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1.
+ return uniformInfo[1] + arrayIndex;
+ } else {
+ return -1;
}
- return -1;
}
function _glLinkProgram(program) {
- program = GL.programs[program];
- GLctx.linkProgram(program);
- // Invalidate earlier computed uniform->ID mappings, those have now become stale
- program.uniformLocsById = 0; // Mark as null-like so that glGetUniformLocation() knows to populate this again.
- program.uniformSizeAndIdsByName = {};
-
+ GLctx.linkProgram(GL.programs[program]);
+ GL.populateUniformTable(program);
}
function _glShaderSource(shader, count, string, length) {
@@ -2796,25 +2757,11 @@ var ASM_CONSTS = {
GLctx.shaderSource(GL.shaders[shader], source);
}
- function webglGetUniformLocation(location) {
- var p = GLctx.currentProgram;
- 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 (webglLoc >= 0) {
- p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? '[' + webglLoc + ']' : ''));
- }
- // Else an already cached WebGLUniformLocation, return it.
- return webglLoc;
- }
-
var miniTempWebGLFloatBuffers=[];
function _glUniformMatrix4fv(location, count, transpose, value) {
if (GL.currentContext.version >= 2) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible.
- GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16);
+ GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, HEAPF32, value>>2, count*16);
return;
}
@@ -2847,15 +2794,11 @@ var ASM_CONSTS = {
{
var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2);
}
- GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view);
+ GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, view);
}
function _glUseProgram(program) {
- program = GL.programs[program];
- GLctx.useProgram(program);
- // Record the currently active program so that we can access the uniform
- // mapping table of that program.
- GLctx.currentProgram = program;
+ GLctx.useProgram(GL.programs[program]);
}
function _glVertexAttribPointer(index, size, type, normalized, stride, ptr) {
@@ -2921,6 +2864,7 @@ var asmLibraryArg = {
"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_set_mousemove_callback_on_thread": _emscripten_set_mousemove_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,
@@ -3066,10 +3010,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, "inetPton4")) Module["inetPton4"] = function() { abort("'inetPton4' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetNtop4")) Module["inetNtop4"] = function() { abort("'inetNtop4' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetPton6")) Module["inetPton6"] = function() { abort("'inetPton6' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "inetNtop6")) Module["inetNtop6"] = function() { abort("'inetNtop6' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "readSockaddr")) Module["readSockaddr"] = function() { abort("'readSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "writeSockaddr")) Module["writeSockaddr"] = function() { abort("'writeSockaddr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "DNS")) Module["DNS"] = function() { abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3093,12 +3033,7 @@ if (!Object.getOwnPropertyDescriptor(Module, "dynCallLegacy")) Module["dynCallLe
if (!Object.getOwnPropertyDescriptor(Module, "getDynCaller")) Module["getDynCaller"] = function() { abort("'getDynCaller' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "dynCall")) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "callRuntimeCallbacks")) Module["callRuntimeCallbacks"] = function() { abort("'callRuntimeCallbacks' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepaliveCounter")) Module["runtimeKeepaliveCounter"] = function() { abort("'runtimeKeepaliveCounter' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "keepRuntimeAlive")) Module["keepRuntimeAlive"] = function() { abort("'keepRuntimeAlive' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePush")) Module["runtimeKeepalivePush"] = function() { abort("'runtimeKeepalivePush' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePop")) Module["runtimeKeepalivePop"] = function() { abort("'runtimeKeepalivePop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "callUserCallback")) Module["callUserCallback"] = function() { abort("'callUserCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "maybeExit")) Module["maybeExit"] = function() { abort("'maybeExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "abortStackOverflow")) Module["abortStackOverflow"] = function() { abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3199,7 +3134,6 @@ if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGet")) Module["emsc
if (!Object.getOwnPropertyDescriptor(Module, "computeUnpackAlignedImageSize")) Module["computeUnpackAlignedImageSize"] = function() { abort("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetTexPixelData")) Module["emscriptenWebGLGetTexPixelData"] = function() { abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetUniform")) Module["emscriptenWebGLGetUniform"] = function() { abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
-if (!Object.getOwnPropertyDescriptor(Module, "webglGetUniformLocation")) Module["webglGetUniformLocation"] = function() { abort("'webglGetUniformLocation' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetVertexAttrib")) Module["emscriptenWebGLGetVertexAttrib"] = function() { abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLGetBufferBinding")) Module["emscriptenWebGLGetBufferBinding"] = function() { abort("'emscriptenWebGLGetBufferBinding' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "emscriptenWebGLValidateMapBufferTarget")) Module["emscriptenWebGLValidateMapBufferTarget"] = function() { abort("'emscriptenWebGLValidateMapBufferTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3289,6 +3223,7 @@ function callMain(args) {
return;
} else if (e == 'unwind') {
// running an evented main loop, don't immediately exit
+ noExitRuntime = true;
return;
} else {
var toLog = e;
@@ -3398,19 +3333,17 @@ function checkUnflushedContent() {
/** @param {boolean|number=} implicit */
function exit(status, implicit) {
- EXITSTATUS = status;
-
checkUnflushedContent();
// if this is just main exit-ing implicitly, and the status is 0, then we
// don't need to do anything here and can just leave. if the status is
// non-zero, though, then we need to report it.
// (we may have warned about this earlier, if a situation justifies doing so)
- if (implicit && keepRuntimeAlive() && status === 0) {
+ if (implicit && noExitRuntime && status === 0) {
return;
}
- if (keepRuntimeAlive()) {
+ if (noExitRuntime) {
// 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)';
@@ -3418,6 +3351,8 @@ function exit(status, implicit) {
}
} else {
+ EXITSTATUS = status;
+
exitRuntime();
if (Module['onExit']) Module['onExit'](status);
diff --git a/2d/rigidbody/rigidbody_1/dist/output.wasm b/2d/rigidbody/rigidbody_1/dist/output.wasm
index 2a9924f..c091140 100755
--- a/2d/rigidbody/rigidbody_1/dist/output.wasm
+++ b/2d/rigidbody/rigidbody_1/dist/output.wasm
Binary files differ
diff --git a/2d/rigidbody/rigidbody_1/main.cpp b/2d/rigidbody/rigidbody_1/main.cpp
index 26d24e2..8d4ab0e 100644
--- a/2d/rigidbody/rigidbody_1/main.cpp
+++ b/2d/rigidbody/rigidbody_1/main.cpp
@@ -43,6 +43,8 @@ struct Rigidbody {
struct Rectangle {
OrthographicShape shape;
Rigidbody body;
+ Vector2 originalPoints[4];
+ Vector2 transformedPoints[4];
void load(OrthographicRenderer* renderer, Vector4 color, float32 width, float32 height) {
color = color.toNormalizedColor();
@@ -62,6 +64,11 @@ struct Rectangle {
vertices[i].color = color;
}
+ originalPoints[0] = vertices[0].position;
+ originalPoints[1] = vertices[1].position;
+ originalPoints[2] = vertices[2].position;
+ originalPoints[3] = vertices[4].position;
+
shape.load(vertices, 6, renderer);
body.reset();
}
@@ -69,6 +76,54 @@ struct Rectangle {
void update(float32 dtSeconds) {
body.update(dtSeconds);
shape.model = Mat4x4().translateByVec2(body.position);
+
+ // Note: This helps us check if the cursor is within the bounds of the
+ // rectangle later on.
+ for (int idx = 0; idx < 4; idx++) {
+ transformedPoints[idx] = shape.model * originalPoints[idx];
+ }
+ }
+
+ void render(OrthographicRenderer* renderer) {
+ shape.render(renderer);
+ }
+
+ void unload() {
+ shape.unload();
+ }
+};
+
+struct Circle {
+ OrthographicShape shape;
+ Rigidbody body;
+
+ float32 radius = 5.f;
+
+ void load(OrthographicRenderer* 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];
+ for (int idx = 0; idx < numSegments; idx++) {
+ int vIdx = idx * 3;
+
+ 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);
+ body.reset();
+ }
+
+ void update(float32 dtSeconds) {
+ shape.model = Mat4x4().translateByVec2(body.position);
}
void render(OrthographicRenderer* renderer) {
@@ -82,6 +137,7 @@ struct Rectangle {
EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
void load();
void update(float32 time, void* userData);
@@ -91,11 +147,15 @@ WebglContext context;
OrthographicRenderer renderer;
MainLoop mainLoop;
Rectangle rectangle;
+Circle pointer;
+bool isIntersectingPointer = false;
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);
+ emscripten_set_mousemove_callback("#gl_canvas", NULL, false, onMouseMove);
+
return 0;
}
@@ -106,11 +166,40 @@ void load() {
rectangle.body.position = Vector2 { context.width / 3.f, context.height / 3.f };
rectangle.body.velocity = Vector2 { 100.f, 250.f };
+ pointer.load(&renderer, Vector4 { 25.f, 235.f, 235.f, 255.f });
+
mainLoop.run(update);
}
+bool isPointInRectangle(Vector2 p, Rectangle r) {
+ // https://math.stackexchange.com/a/190373
+ Vector2 A = r.transformedPoints[0];
+ Vector2 B = r.transformedPoints[1];
+ Vector2 D = r.transformedPoints[3];
+
+ float32 amDotAb = (p - A).dot(B - A);
+ float32 abDotAb = (B - A).dot(B - A);
+
+ float32 amDotAd = (p - A).dot(D - A);
+ float32 aDDotAd = (D - A).dot(D - A);
+
+ return amDotAb > 0 && amDotAb < abDotAb && amDotAd > 0 && amDotAd < aDDotAd;
+
+}
+
void update(float32 deltaTimeSeconds, void* userData) {
rectangle.update(deltaTimeSeconds);
+ pointer.update(deltaTimeSeconds);
+
+ if (isPointInRectangle(pointer.body.position, rectangle)) {
+ if (!isIntersectingPointer) {
+ isIntersectingPointer = true;
+ rectangle.body.force += pointer.body.force;
+ }
+ } else if (isIntersectingPointer) {
+ isIntersectingPointer = false;
+ }
+
// Check collisions with walls so we don't go out of the scene. Simply reflect here.
if (rectangle.body.position.x <= 0.f) {
@@ -121,24 +210,26 @@ void update(float32 deltaTimeSeconds, void* userData) {
rectangle.body.position.y = 0.f;
rectangle.body.velocity = rectangle.body.velocity - Vector2 { 0.f, 1.f } * (2 * (rectangle.body.velocity.dot(Vector2 { 0.f, 1.f })));
}
- if (rectangle.body.position.x >= 640.f) {
- rectangle.body.position.x = 640.f;
+ if (rectangle.body.position.x >= 800.f) {
+ rectangle.body.position.x = 800.f;
rectangle.body.velocity = rectangle.body.velocity - Vector2 { -1.f, 0.f } * (2 * (rectangle.body.velocity.dot(Vector2{ -1.f, 0.f })));
}
- if (rectangle.body.position.y >= 480.f) {
- rectangle.body.position.y = 480.f;
+ if (rectangle.body.position.y >= 600.f) {
+ rectangle.body.position.y = 600.f;
rectangle.body.velocity = rectangle.body.velocity - Vector2 { 0.f, -1.f } * (2 * (rectangle.body.velocity.dot(Vector2 { 0.f, -1.f }))) ;
}
// Renderer
renderer.render();
rectangle.render(&renderer);
+ pointer.render(&renderer);
}
void unload() {
mainLoop.stop();
renderer.unload();
rectangle.unload();
+ pointer.unload();
}
//
@@ -156,3 +247,17 @@ EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, voi
unload();
return true;
}
+
+EM_BOOL onMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) {
+ if (!mainLoop.isRunning) {
+ return true;
+ }
+
+ pointer.body.force.x = static_cast<float32>(mouseEvent->movementX) * 1000.f;
+ pointer.body.force.y = static_cast<float32>(-mouseEvent->movementY) * 1000.f;
+
+ pointer.body.position.x = static_cast<float32>(mouseEvent->targetX);
+ pointer.body.position.y = static_cast<float32>(600.f - mouseEvent->targetY);
+
+ return true;
+}