summaryrefslogtreecommitdiff
path: root/2d
diff options
context:
space:
mode:
authorMatthew Kosarek <mattkae@protonmail.com>2021-05-18 20:30:33 -0400
committerMatthew Kosarek <mattkae@protonmail.com>2021-05-18 20:30:33 -0400
commitdf671b9de03f5db479878cff826e11c30602e010 (patch)
treecf8fe4bb748074bf5112533dee7ca11bb4894366 /2d
parenta00c0aab1eb5a7a55bef8ca08115bdd722ab5699 (diff)
(mkosarek) Just need better calculations for moment of inertia and I will be good
Diffstat (limited to '2d')
-rw-r--r--2d/_collisions/polygon_polygon/dist/output.js313
-rwxr-xr-x2d/_collisions/polygon_polygon/dist/output.wasmbin43549 -> 56810 bytes
-rw-r--r--2d/_collisions/polygon_polygon/main.cpp146
-rw-r--r--2d/_collisions/rectangle_rectangle/dist/output.js313
-rwxr-xr-x2d/_collisions/rectangle_rectangle/dist/output.wasmbin55719 -> 55607 bytes
5 files changed, 469 insertions, 303 deletions
diff --git a/2d/_collisions/polygon_polygon/dist/output.js b/2d/_collisions/polygon_polygon/dist/output.js
index e1dfee3..42a4ed5 100644
--- a/2d/_collisions/polygon_polygon/dist/output.js
+++ b/2d/_collisions/polygon_polygon/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 on the asm.js/wasm heap 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 in wasm memory 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 an UTF-8 string on the asm.js/wasm heap! (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 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);
@@ -1252,12 +1252,12 @@ function checkStackCookie() {
// include: runtime_assertions.js
-// Endianness check (note: assumes compiler arch was little-endian)
+// 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!';
+ if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -s SUPPORT_BIG_ENDIAN=1 to bypass)';
})();
function abortFnPtrError(ptr, sig) {
@@ -1274,8 +1274,6 @@ 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']) {
@@ -1292,6 +1290,7 @@ function initRuntime() {
checkStackCookie();
assert(!runtimeInitialized);
runtimeInitialized = true;
+
callRuntimeCallbacks(__ATINIT__);
}
@@ -1616,6 +1615,8 @@ 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)
@@ -1637,7 +1638,8 @@ function createWasm() {
function instantiateArrayBuffer(receiver) {
return getBinaryPromise().then(function(binary) {
- return WebAssembly.instantiate(binary, info);
+ var result = WebAssembly.instantiate(binary, info);
+ return result;
}).then(receiver, function(reason) {
err('failed to asynchronously prepare wasm: ' + reason);
@@ -1704,12 +1706,8 @@ 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.
@@ -1760,6 +1758,11 @@ var ASM_CONSTS = {
return error.stack.toString();
}
+ var runtimeKeepaliveCounter=0;
+ function keepRuntimeAlive() {
+ return noExitRuntime || runtimeKeepaliveCounter > 0;
+ }
+
function stackTrace() {
var js = jsStackTrace();
if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
@@ -1783,10 +1786,6 @@ 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)
@@ -1800,7 +1799,8 @@ var ASM_CONSTS = {
// anyhow)
}
function _emscripten_resize_heap(requestedSize) {
- var oldSize = _emscripten_get_heap_size();
+ 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);
@@ -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--);
@@ -2074,7 +2074,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:[],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) {
+ 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;
}
@@ -2085,7 +2085,7 @@ var ASM_CONSTS = {
}
return ret;
},MAX_TEMP_BUFFER_SIZE:2097152,numTempVertexBuffersPerSize:64,log2ceilLookup:function(i) {
- return 32 - Math.clz32(i-1);
+ return 32 - Math.clz32(i === 0 ? 0 : i - 1);
},generateTempBuffers:function(quads, context) {
var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
context.tempVertexBufferCounters1 = [];
@@ -2213,6 +2213,19 @@ 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)
?
@@ -2285,7 +2298,21 @@ var ASM_CONSTS = {
__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
+ // 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.
@@ -2297,49 +2324,6 @@ 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'];
@@ -2386,7 +2370,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;
}
@@ -2450,8 +2434,7 @@ 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) {
@@ -2511,7 +2494,11 @@ 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;
}
@@ -2519,6 +2506,7 @@ var ASM_CONSTS = {
function _glCreateShader(shaderType) {
var id = GL.getNewId(GL.shaders);
GL.shaders[id] = GLctx.createShader(shaderType);
+
return id;
}
@@ -2552,7 +2540,6 @@ var ASM_CONSTS = {
GLctx.deleteProgram(program);
program.name = 0;
GL.programs[id] = null;
- GL.programInfos[id] = null;
}
function _glDeleteShader(id) {
@@ -2645,42 +2632,35 @@ var ASM_CONSTS = {
return;
}
- var ptable = GL.programInfos[program];
- if (!ptable) {
- GL.recordError(0x502 /* GL_INVALID_OPERATION */);
- return;
- }
+ program = GL.programs[program];
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- var log = GLctx.getProgramInfoLog(GL.programs[program]);
+ 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 */) {
- HEAP32[((p)>>2)] = ptable.maxUniformLength;
+ 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 (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);
+ 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)] = ptable.maxAttributeLength;
+ HEAP32[((p)>>2)] = program.maxAttributeLength;
} else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) {
- 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);
+ 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)] = ptable.maxUniformBlockNameLength;
+ HEAP32[((p)>>2)] = program.maxUniformBlockNameLength;
} else {
- HEAP32[((p)>>2)] = GLctx.getProgramParameter(GL.programs[program], pname);
+ HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname);
}
}
@@ -2723,27 +2703,91 @@ 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 (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);
+ 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);
}
- 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;
+ // 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;
+ }
}
+ return -1;
}
function _glLinkProgram(program) {
- GLctx.linkProgram(GL.programs[program]);
- GL.populateUniformTable(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) {
@@ -2752,11 +2796,25 @@ 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(GL.uniforms[location], !!transpose, HEAPF32, value>>2, count*16);
+ GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16);
return;
}
@@ -2789,11 +2847,15 @@ var ASM_CONSTS = {
{
var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2);
}
- GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, view);
+ GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view);
}
function _glUseProgram(program) {
- GLctx.useProgram(GL.programs[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) {
@@ -3004,6 +3066,10 @@ 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)") };
@@ -3027,7 +3093,12 @@ 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, "abortStackOverflow")) Module["abortStackOverflow"] = function() { abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepaliveCounter")) Module["runtimeKeepaliveCounter"] = function() { abort("'runtimeKeepaliveCounter' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "keepRuntimeAlive")) Module["keepRuntimeAlive"] = function() { abort("'keepRuntimeAlive' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePush")) Module["runtimeKeepalivePush"] = function() { abort("'runtimeKeepalivePush' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePop")) Module["runtimeKeepalivePop"] = function() { abort("'runtimeKeepalivePop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "callUserCallback")) Module["callUserCallback"] = function() { abort("'callUserCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "maybeExit")) Module["maybeExit"] = function() { abort("'maybeExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3128,6 +3199,7 @@ 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)") };
@@ -3217,7 +3289,6 @@ function callMain(args) {
return;
} else if (e == 'unwind') {
// running an evented main loop, don't immediately exit
- noExitRuntime = true;
return;
} else {
var toLog = e;
@@ -3327,17 +3398,19 @@ 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 && noExitRuntime && status === 0) {
+ if (implicit && keepRuntimeAlive() && status === 0) {
return;
}
- if (noExitRuntime) {
+ 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)';
@@ -3345,8 +3418,6 @@ function exit(status, implicit) {
}
} else {
- EXITSTATUS = status;
-
exitRuntime();
if (Module['onExit']) Module['onExit'](status);
diff --git a/2d/_collisions/polygon_polygon/dist/output.wasm b/2d/_collisions/polygon_polygon/dist/output.wasm
index a472d0a..e355676 100755
--- a/2d/_collisions/polygon_polygon/dist/output.wasm
+++ b/2d/_collisions/polygon_polygon/dist/output.wasm
Binary files differ
diff --git a/2d/_collisions/polygon_polygon/main.cpp b/2d/_collisions/polygon_polygon/main.cpp
index b7e3ce5..916a057 100644
--- a/2d/_collisions/polygon_polygon/main.cpp
+++ b/2d/_collisions/polygon_polygon/main.cpp
@@ -19,7 +19,7 @@ struct Rigidbody {
float32 rotation = 0.f;
float32 mass = 1.f;
float32 cofOfRestition = 1.f;
- float32 momentOfInertia = 0.f;
+ float32 momentOfInertia = 1.f;
void reset() {
force = { 0, 0 };
@@ -75,7 +75,14 @@ struct ConvexPolygon {
float32 width = 0.f;
float32 height = 0.f;
+ Vector2* originalVertices;
+ Vector2* transformedVertices;
+ Edge* edges;
+
void load(OrthographicRenderer* renderer) {
+ transformedVertices = new Vector2[numVertices]; // This will be used for SAT calculations later
+ originalVertices = new Vector2[numVertices];
+
// Generate the shape with numVertices many sides in a "fan" shape (i.e. 3 vertices per vertex)
// The shape will have all equal sides, just to make it easier on me. Therefore, it will fit inside
// the conditions of a circle, which is fun. Before anyone gets mad: I know I can avoid recalculating
@@ -83,26 +90,33 @@ 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* vertices = new OrthographicVertex[verticesNeeded];
+ OrthographicVertex* shaderVertices = new OrthographicVertex[verticesNeeded];
for (int32 vidx = 0; vidx < numVertices; vidx++) {
int32 indexPosition = vidx * 3;
float32 firstAngle = angleIncrements * vidx;
- vertices[indexPosition].position = { cosf(firstAngle) * width, sinf(firstAngle) * height };
+ shaderVertices[indexPosition].position = { cosf(firstAngle) * width, sinf(firstAngle) * height };
- vertices[indexPosition + 1].position = { 0.f, 0.f };
+ originalVertices[vidx] = shaderVertices[indexPosition].position;
+
+ shaderVertices[indexPosition + 1].position = { 0.f, 0.f };
float32 secondAngle = angleIncrements * (vidx + 1);
- vertices[indexPosition + 2].position = { cosf(secondAngle) * width, sinf(secondAngle) * height };
+ shaderVertices[indexPosition + 2].position = { cosf(secondAngle) * width, sinf(secondAngle) * height };
// Apply some global stylings
for (int subIdx = 0; subIdx < 3; subIdx++) {
- vertices[indexPosition + subIdx].color = color.toNormalizedColor();
+ shaderVertices[indexPosition + subIdx].color = color.toNormalizedColor();
}
}
- shape.load(vertices, verticesNeeded, renderer);
- delete[] vertices;
+ shape.load(shaderVertices, verticesNeeded, renderer);
+ delete[] shaderVertices;
+
+ edges = new Edge[numVertices]; // This will be filled in later when we are doing our SAT calculation.
+
+ // Calculate moment of inertia
+ body.setMomentOfInertia((PI * body.mass) / 2.f);
}
void update(float32 dtSeconds) {
@@ -110,18 +124,38 @@ struct ConvexPolygon {
body.update(dtSeconds);
shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation);
+
+ // Populate the current position of our edges
+ for (int vidx = 0; vidx < numVertices; vidx++) {
+ Vector2 start = shape.model * originalVertices[vidx];
+ transformedVertices[vidx] = start;
+
+ Vector2 end = shape.model * originalVertices[vidx == numVertices - 1 ? 0 : vidx + 1];
+ edges[vidx] = { (end - start).getPerp().normalize(), start, end };
+ }
}
+ void restorePreviousBody() {
+ body = previousBody;
+ }
+
void render(OrthographicRenderer* renderer) {
shape.render(renderer);
}
void unload() {
shape.unload();
- }
-};
+ delete[] originalVertices;
+ originalVertices = NULL;
+ delete[] transformedVertices;
+ transformedVertices = NULL;
+
+ delete[] edges;
+ edges = NULL;
+ }
+};
EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
@@ -151,12 +185,24 @@ void load() {
if (index == 0) {
polygons[index].body.position = { context.width / 4.f, context.height / 4.f };
+ polygons[index].body.velocity = { 100.f, 200.f };
+ polygons[index].body.mass = 2.f;
+ polygons[index].body.rotationalVelocity = 0.2f;
} else if (index == 1) {
polygons[index].body.position = { context.width / 4.f, context.height * (3.f /4.f) };
+ polygons[index].body.velocity = { 50.f, -50.f };
+ polygons[index].body.mass = 4.f;
+ polygons[index].body.rotationalVelocity = -0.5f;
} else if (index == 2) {
polygons[index].body.position = { context.width * (3.f / 4.f), context.height * (3.f / 4.f) };
+ polygons[index].body.velocity = { -100.f, -50.f };
+ polygons[index].body.mass = 6.f;
+ polygons[index].body.rotationalVelocity = 0.9f;
} else if (index == 3) {
polygons[index].body.position = { context.width * (3.f / 4.f), context.height / 4.f };
+ polygons[index].body.velocity = { -150.f, 50.f };
+ polygons[index].body.mass = 8.f;
+ polygons[index].body.rotationalVelocity = 1.4f;
}
polygons[index].numVertices = (index + 1) * 3;
@@ -168,14 +214,16 @@ void load() {
};
polygons[index].load(&renderer);
}
+
+ printf("Main loop beginning\n");
mainLoop.run(update);
}
-Vector2 getProjection(Vector2* vertices, Vector2 axis) {
+Vector2 getProjection(Vector2* vertices, int numVertices, Vector2 axis) {
float32 min = axis.dot(vertices[0]);
float32 max = min;
- for (int v = 1; v < 4; v++) {
+ for (int v = 1; v < numVertices; v++) {
float32 d = axis.dot(vertices[v]);
if (d < min) {
@@ -188,7 +236,7 @@ Vector2 getProjection(Vector2* vertices, Vector2 axis) {
return Vector2 { min, max };
}
-/*bool projectionsOverlap(Vector2 first, Vector2 second) {
+bool projectionsOverlap(Vector2 first, Vector2 second) {
return first.x <= second.y && second.x <= first.y;
}
@@ -199,30 +247,19 @@ float32 getProjectionOverlap(Vector2 first, Vector2 second) {
}
const float32 EPSILON = 1.f;
-IntersectionResult getIntersection(Rectangle* first, Po* second) {
+IntersectionResult getIntersection(ConvexPolygon* first, ConvexPolygon* second) {
IntersectionResult ir;
// For two rectangles to overlap, it means that at least one of the corners of one is inside of the other
- Edge firstEdges[4];
- first->getEdges(firstEdges);
- Vector2 firstPoints[4];
- first->getPoints(firstPoints);
-
- Edge secondEdges[4];
- second->getEdges(secondEdges);
- Vector2 secondPoints[4];
- second->getPoints(secondPoints);
-
float32 minOverlap = FLT_MAX;
- Vector2 minOverlapAxis;
Edge* minOverlapEdge = NULL;
- bool minOverlapWasFirstRect = false;
+ bool minOverlapWasFirst = false;
- for (int i = 0; i < 4; i++) {
- Vector2 normal = firstEdges[i].normal;
+ for (int i = 0; i < first->numVertices; i++) {
+ Vector2 normal = first->edges[i].normal;
- Vector2 firstProj = getProjection(firstPoints, normal);
- Vector2 secondProj = getProjection(secondPoints, normal);
+ Vector2 firstProj = getProjection(first->transformedVertices, first->numVertices, normal);
+ Vector2 secondProj = getProjection(second->transformedVertices, second->numVertices, normal);
if (!projectionsOverlap(firstProj, secondProj)) {
return ir;
@@ -231,17 +268,16 @@ IntersectionResult getIntersection(Rectangle* first, Po* second) {
float32 overlap = getProjectionOverlap(firstProj, secondProj);
if (overlap < minOverlap) {
minOverlap = overlap;
- minOverlapAxis = normal;
- minOverlapEdge = &firstEdges[i];
- minOverlapWasFirstRect = true;
+ minOverlapEdge = &first->edges[i];
+ minOverlapWasFirst = true;
}
}
- for (int i = 0; i < 4; i++) {
- Vector2 normal = secondEdges[i].normal;
+ for (int i = 0; i < second->numVertices; i++) {
+ Vector2 normal = second->edges[i].normal;
- Vector2 firstProj = getProjection(firstPoints, normal);
- Vector2 secondProj = getProjection(secondPoints, normal);
+ Vector2 firstProj = getProjection(first->transformedVertices, first->numVertices, normal);
+ Vector2 secondProj = getProjection(second->transformedVertices, second->numVertices, normal);
if (!projectionsOverlap(firstProj, secondProj)) {
return ir;
@@ -250,33 +286,21 @@ IntersectionResult getIntersection(Rectangle* first, Po* second) {
float32 overlap = getProjectionOverlap(firstProj, secondProj);
if (overlap < minOverlap) {
minOverlap = overlap;
- minOverlapAxis = normal;
- minOverlapEdge = &secondEdges[i];
+ minOverlapEdge = &second->edges[i];
}
}
ir.intersect = true;
ir.relativeVelocity = first->body.velocity - second->body.velocity;
- ir.collisionNormal = minOverlapAxis;
-
- // Find the point of collision, this is kind of tricky, and it is just an approximation for now.
- // At this point, we know that we intersected along the minOverlapAxis, but we do not know where
- // that exactly happened. To remedy this will, we create two parallel lines: one at the top of the
- // normal area, and one at the bottom. For point on both of the Rectangles, we will check:
- // (1) if it is between these two planes
- // (2) if, for that rectangle, it is the closest point to the original normal vector
- // (3) or if it is equally distant from normal vector as another point (then this is a "flat" collision)
- //
- // The collision point MUST be between these two planes. We can then say the corner/face of the non-monoverlapAxis
- // Rectangle is the collision point. This enables us to then solve for their respective points of application fairly
- // easily. If the collision "point" is an entire face, we make the collision point be the center point.
- //
+ ir.collisionNormal = minOverlapEdge->normal;
+ // Time to find just where we intersected
Vector2 closestPoint;
float32 minDistance = FLT_MAX;
- for (int p = 0; p < 4; p++) {
- Vector2 point = minOverlapWasFirstRect ? secondPoints[p] : firstPoints[p];
+
+ for (int p = 0; p < (minOverlapWasFirst ? second->numVertices : first->numVertices); p++) {
+ Vector2 point = minOverlapWasFirst ? second->transformedVertices[p] : first->transformedVertices[p];
float32 distFromPointToStart = (minOverlapEdge->start - point).length();
float32 distFromPointToEnd = (minOverlapEdge->end - point).length();
@@ -287,12 +311,12 @@ IntersectionResult getIntersection(Rectangle* first, Po* second) {
minDistance = potentialMin;
}
}
-
+
ir.firstPointOfApplication = closestPoint - first->body.position;
ir.secondPointOfApplication = closestPoint - second->body.position;;
return ir;
-}*/
+}
void resolveCollision(Rigidbody* first, Rigidbody* second, IntersectionResult* ir) {
Vector2 relativeVelocity = ir->relativeVelocity;
@@ -322,10 +346,10 @@ void update(float32 deltaTimeSeconds, void* userData) {
}
// Check collisions with other rectangles
- /*for (int i = 0; i < 4; i++) {
- Rectangle* first = &rectangleList[i];
+ for (int i = 0; i < 4; i++) {
+ ConvexPolygon* first = &polygons[i];
for (int j = i + 1; j < 4; j++) {
- Rectangle* second = &rectangleList[j];
+ ConvexPolygon* second = &polygons[j];
IntersectionResult ir = getIntersection(first, second);
if (!ir.intersect) {
@@ -363,7 +387,7 @@ void update(float32 deltaTimeSeconds, void* userData) {
first->update(frameTimeRemaining);
second->update(frameTimeRemaining);
}
- }*/
+ }
// Check collisions with walls
for (int p = 0; p < 4; p++) {
diff --git a/2d/_collisions/rectangle_rectangle/dist/output.js b/2d/_collisions/rectangle_rectangle/dist/output.js
index e1dfee3..42a4ed5 100644
--- a/2d/_collisions/rectangle_rectangle/dist/output.js
+++ b/2d/_collisions/rectangle_rectangle/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 on the asm.js/wasm heap 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 in wasm memory 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 an UTF-8 string on the asm.js/wasm heap! (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 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);
@@ -1252,12 +1252,12 @@ function checkStackCookie() {
// include: runtime_assertions.js
-// Endianness check (note: assumes compiler arch was little-endian)
+// 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!';
+ if (h8[0] !== 0x73 || h8[1] !== 0x63) throw 'Runtime error: expected the system to be little-endian! (Run with -s SUPPORT_BIG_ENDIAN=1 to bypass)';
})();
function abortFnPtrError(ptr, sig) {
@@ -1274,8 +1274,6 @@ 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']) {
@@ -1292,6 +1290,7 @@ function initRuntime() {
checkStackCookie();
assert(!runtimeInitialized);
runtimeInitialized = true;
+
callRuntimeCallbacks(__ATINIT__);
}
@@ -1616,6 +1615,8 @@ 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)
@@ -1637,7 +1638,8 @@ function createWasm() {
function instantiateArrayBuffer(receiver) {
return getBinaryPromise().then(function(binary) {
- return WebAssembly.instantiate(binary, info);
+ var result = WebAssembly.instantiate(binary, info);
+ return result;
}).then(receiver, function(reason) {
err('failed to asynchronously prepare wasm: ' + reason);
@@ -1704,12 +1706,8 @@ 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.
@@ -1760,6 +1758,11 @@ var ASM_CONSTS = {
return error.stack.toString();
}
+ var runtimeKeepaliveCounter=0;
+ function keepRuntimeAlive() {
+ return noExitRuntime || runtimeKeepaliveCounter > 0;
+ }
+
function stackTrace() {
var js = jsStackTrace();
if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
@@ -1783,10 +1786,6 @@ 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)
@@ -1800,7 +1799,8 @@ var ASM_CONSTS = {
// anyhow)
}
function _emscripten_resize_heap(requestedSize) {
- var oldSize = _emscripten_get_heap_size();
+ 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);
@@ -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--);
@@ -2074,7 +2074,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:[],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) {
+ 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;
}
@@ -2085,7 +2085,7 @@ var ASM_CONSTS = {
}
return ret;
},MAX_TEMP_BUFFER_SIZE:2097152,numTempVertexBuffersPerSize:64,log2ceilLookup:function(i) {
- return 32 - Math.clz32(i-1);
+ return 32 - Math.clz32(i === 0 ? 0 : i - 1);
},generateTempBuffers:function(quads, context) {
var largestIndex = GL.log2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
context.tempVertexBufferCounters1 = [];
@@ -2213,6 +2213,19 @@ 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)
?
@@ -2285,7 +2298,21 @@ var ASM_CONSTS = {
__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
- GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
+ // 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.
@@ -2297,49 +2324,6 @@ 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'];
@@ -2386,7 +2370,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;
}
@@ -2450,8 +2434,7 @@ 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) {
@@ -2511,7 +2494,11 @@ 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;
}
@@ -2519,6 +2506,7 @@ var ASM_CONSTS = {
function _glCreateShader(shaderType) {
var id = GL.getNewId(GL.shaders);
GL.shaders[id] = GLctx.createShader(shaderType);
+
return id;
}
@@ -2552,7 +2540,6 @@ var ASM_CONSTS = {
GLctx.deleteProgram(program);
program.name = 0;
GL.programs[id] = null;
- GL.programInfos[id] = null;
}
function _glDeleteShader(id) {
@@ -2645,42 +2632,35 @@ var ASM_CONSTS = {
return;
}
- var ptable = GL.programInfos[program];
- if (!ptable) {
- GL.recordError(0x502 /* GL_INVALID_OPERATION */);
- return;
- }
+ program = GL.programs[program];
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
- var log = GLctx.getProgramInfoLog(GL.programs[program]);
+ 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 */) {
- HEAP32[((p)>>2)] = ptable.maxUniformLength;
+ 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 (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);
+ 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)] = ptable.maxAttributeLength;
+ HEAP32[((p)>>2)] = program.maxAttributeLength;
} else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) {
- 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);
+ 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)] = ptable.maxUniformBlockNameLength;
+ HEAP32[((p)>>2)] = program.maxUniformBlockNameLength;
} else {
- HEAP32[((p)>>2)] = GLctx.getProgramParameter(GL.programs[program], pname);
+ HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname);
}
}
@@ -2723,27 +2703,91 @@ 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 (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);
+ 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);
}
- 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;
+ // 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;
+ }
}
+ return -1;
}
function _glLinkProgram(program) {
- GLctx.linkProgram(GL.programs[program]);
- GL.populateUniformTable(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) {
@@ -2752,11 +2796,25 @@ 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(GL.uniforms[location], !!transpose, HEAPF32, value>>2, count*16);
+ GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16);
return;
}
@@ -2789,11 +2847,15 @@ var ASM_CONSTS = {
{
var view = HEAPF32.subarray((value)>>2, (value+count*64)>>2);
}
- GLctx.uniformMatrix4fv(GL.uniforms[location], !!transpose, view);
+ GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view);
}
function _glUseProgram(program) {
- GLctx.useProgram(GL.programs[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) {
@@ -3004,6 +3066,10 @@ 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)") };
@@ -3027,7 +3093,12 @@ 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, "abortStackOverflow")) Module["abortStackOverflow"] = function() { abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepaliveCounter")) Module["runtimeKeepaliveCounter"] = function() { abort("'runtimeKeepaliveCounter' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "keepRuntimeAlive")) Module["keepRuntimeAlive"] = function() { abort("'keepRuntimeAlive' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePush")) Module["runtimeKeepalivePush"] = function() { abort("'runtimeKeepalivePush' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "runtimeKeepalivePop")) Module["runtimeKeepalivePop"] = function() { abort("'runtimeKeepalivePop' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "callUserCallback")) Module["callUserCallback"] = function() { abort("'callUserCallback' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
+if (!Object.getOwnPropertyDescriptor(Module, "maybeExit")) Module["maybeExit"] = function() { abort("'maybeExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reallyNegative")) Module["reallyNegative"] = function() { abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "unSign")) Module["unSign"] = function() { abort("'unSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
if (!Object.getOwnPropertyDescriptor(Module, "reSign")) Module["reSign"] = function() { abort("'reSign' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
@@ -3128,6 +3199,7 @@ 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)") };
@@ -3217,7 +3289,6 @@ function callMain(args) {
return;
} else if (e == 'unwind') {
// running an evented main loop, don't immediately exit
- noExitRuntime = true;
return;
} else {
var toLog = e;
@@ -3327,17 +3398,19 @@ 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 && noExitRuntime && status === 0) {
+ if (implicit && keepRuntimeAlive() && status === 0) {
return;
}
- if (noExitRuntime) {
+ 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)';
@@ -3345,8 +3418,6 @@ function exit(status, implicit) {
}
} else {
- EXITSTATUS = status;
-
exitRuntime();
if (Module['onExit']) Module['onExit'](status);
diff --git a/2d/_collisions/rectangle_rectangle/dist/output.wasm b/2d/_collisions/rectangle_rectangle/dist/output.wasm
index f5eaef0..5a17a67 100755
--- a/2d/_collisions/rectangle_rectangle/dist/output.wasm
+++ b/2d/_collisions/rectangle_rectangle/dist/output.wasm
Binary files differ