diff options
Diffstat (limited to 'src/library_browser.js')
-rw-r--r-- | src/library_browser.js | 180 |
1 files changed, 126 insertions, 54 deletions
diff --git a/src/library_browser.js b/src/library_browser.js index 1740eaed..a3e68209 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -41,6 +41,26 @@ mergeInto(LibraryManager.library, { Module['setStatus'](''); } } + }, + runIter: function(func) { + if (ABORT) return; + if (Module['preMainLoop']) { + var preRet = Module['preMainLoop'](); + if (preRet === false) { + return; // |return false| skips a frame + } + } + try { + func(); + } catch (e) { + if (e instanceof ExitStatus) { + return; + } else { + if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]); + throw e; + } + } + if (Module['postMainLoop']) Module['postMainLoop'](); } }, isFullScreen: false, @@ -51,7 +71,7 @@ mergeInto(LibraryManager.library, { init: function() { if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers - if (Browser.initted || ENVIRONMENT_IS_WORKER) return; + if (Browser.initted || ENVIRONMENT_IS_WORKER) return; // workers do not support Image and Audio elements Browser.initted = true; try { @@ -242,6 +262,8 @@ mergeInto(LibraryManager.library, { return null; } #endif + if (useWebGL && Module.ctx) return Module.ctx; // no need to recreate singleton GL context + var ctx; var errorInfo = '?'; function onContextCreationError(event) { @@ -282,49 +304,98 @@ mergeInto(LibraryManager.library, { } if (useWebGL) { #if GL_DEBUG - // Useful to debug native webgl apps: var Module = { printErr: function(x) { console.log(x) } }; - var tempCtx = ctx; - var wrapper = {}; - for (var prop in tempCtx) { - (function(prop) { - switch (typeof tempCtx[prop]) { - case 'function': { - wrapper[prop] = function gl_wrapper() { - if (GL.debug) { - var printArgs = Array.prototype.slice.call(arguments).map(Runtime.prettyPrint); - Module.printErr('[gl_f:' + prop + ':' + printArgs + ']'); - } - var ret = tempCtx[prop].apply(tempCtx, arguments); - if (GL.debug && typeof ret != 'undefined') { - Module.printErr('[ gl:' + prop + ':return:' + Runtime.prettyPrint(ret) + ']'); - } - return ret; - } - break; + function wrapDebugGL(ctx) { + + var printObjectList = []; + + function prettyPrint(arg) { + if (typeof arg == 'undefined') return '!UNDEFINED!'; + if (typeof arg == 'boolean') arg = arg + 0; + if (!arg) return arg; + var index = printObjectList.indexOf(arg); + if (index >= 0) return '<' + arg + '|'; // + index + '>'; + if (arg.toString() == '[object HTMLImageElement]') { + return arg + '\n\n'; + } + if (arg.byteLength) { + return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}'; // Useful for correct arrays, less so for compiled arrays, see the code below for that + var buf = new ArrayBuffer(32); + var i8buf = new Int8Array(buf); + var i16buf = new Int16Array(buf); + var f32buf = new Float32Array(buf); + switch(arg.toString()) { + case '[object Uint8Array]': + i8buf.set(arg.subarray(0, 32)); + break; + case '[object Float32Array]': + f32buf.set(arg.subarray(0, 5)); + break; + case '[object Uint16Array]': + i16buf.set(arg.subarray(0, 16)); + break; + default: + alert('unknown array for debugging: ' + arg); + throw 'see alert'; } - case 'number': case 'string': { - wrapper.__defineGetter__(prop, function() { - //Module.printErr('[gl_g:' + prop + ':' + tempCtx[prop] + ']'); - return tempCtx[prop]; - }); - wrapper.__defineSetter__(prop, function(value) { - if (GL.debug) { - Module.printErr('[gl_s:' + prop + ':' + value + ']'); + var ret = '{' + arg.byteLength + ':\n'; + var arr = Array.prototype.slice.call(i8buf); + ret += 'i8:' + arr.toString().replace(/,/g, ',') + '\n'; + arr = Array.prototype.slice.call(f32buf, 0, 8); + ret += 'f32:' + arr.toString().replace(/,/g, ',') + '}'; + return ret; + } + if (typeof arg == 'object') { + printObjectList.push(arg); + return '<' + arg + '|'; // + (printObjectList.length-1) + '>'; + } + if (typeof arg == 'number') { + if (arg > 0) return '0x' + arg.toString(16) + ' (' + arg + ')'; + } + return arg; + } + + var wrapper = {}; + for (var prop in ctx) { + (function(prop) { + switch (typeof ctx[prop]) { + case 'function': { + wrapper[prop] = function gl_wrapper() { + var printArgs = Array.prototype.slice.call(arguments).map(prettyPrint); + dump('[gl_f:' + prop + ':' + printArgs + ']\n'); + var ret = ctx[prop].apply(ctx, arguments); + if (typeof ret != 'undefined') { + dump('[ gl:' + prop + ':return:' + prettyPrint(ret) + ']\n'); + } + return ret; } - tempCtx[prop] = value; - }); - break; + break; + } + case 'number': case 'string': { + wrapper.__defineGetter__(prop, function() { + //dump('[gl_g:' + prop + ':' + ctx[prop] + ']\n'); + return ctx[prop]; + }); + wrapper.__defineSetter__(prop, function(value) { + dump('[gl_s:' + prop + ':' + value + ']\n'); + ctx[prop] = value; + }); + break; + } } - } - })(prop); + })(prop); + } + return wrapper; } - ctx = wrapper; #endif + // possible GL_DEBUG entry point: ctx = wrapDebugGL(ctx); + // Set the background of the WebGL canvas to black canvas.style.backgroundColor = "black"; } if (setInModule) { - GLctx = Module.ctx = ctx; + if (!useWebGL) assert(typeof GLctx === 'undefined', 'cannot set in module if GLctx is used, but we are a non-GL context that would replace it'); + Module.ctx = ctx; + if (useWebGL) GLctx = ctx; Module.useWebGL = useWebGL; Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() }); Browser.init(); @@ -395,9 +466,25 @@ mergeInto(LibraryManager.library, { canvasContainer.requestFullScreen(); }, + nextRAF: 0, + + fakeRequestAnimationFrame: function(func) { + // try to keep 60fps between calls to here + var now = Date.now(); + if (Browser.nextRAF === 0) { + Browser.nextRAF = now + 1000/60; + } else { + while (now + 2 >= Browser.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0 + Browser.nextRAF += 1000/60; + } + } + var delay = Math.max(Browser.nextRAF - now, 0); + setTimeout(func, delay); + }, + requestAnimationFrame: function requestAnimationFrame(func) { if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js) - setTimeout(func, 1000/60); + Browser.fakeRequestAnimationFrame(func); } else { if (!window.requestAnimationFrame) { window.requestAnimationFrame = window['requestAnimationFrame'] || @@ -405,7 +492,7 @@ mergeInto(LibraryManager.library, { window['webkitRequestAnimationFrame'] || window['msRequestAnimationFrame'] || window['oRequestAnimationFrame'] || - window['setTimeout']; + Browser.fakeRequestAnimationFrame; } window.requestAnimationFrame(func); } @@ -954,28 +1041,13 @@ mergeInto(LibraryManager.library, { Browser.mainLoop.method = ''; // just warn once per call to set main loop } - if (Module['preMainLoop']) { - Module['preMainLoop'](); - } - - try { + Browser.mainLoop.runIter(function() { if (typeof arg !== 'undefined') { Runtime.dynCall('vi', func, [arg]); } else { Runtime.dynCall('v', func); } - } catch (e) { - if (e instanceof ExitStatus) { - return; - } else { - if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]); - throw e; - } - } - - if (Module['postMainLoop']) { - Module['postMainLoop'](); - } + }); if (Browser.mainLoop.shouldPause) { // catch pauses from the main loop itself |