aboutsummaryrefslogtreecommitdiff
path: root/src/library_browser.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_browser.js')
-rw-r--r--src/library_browser.js343
1 files changed, 251 insertions, 92 deletions
diff --git a/src/library_browser.js b/src/library_browser.js
index 17dff2eb..075bd8bf 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -3,24 +3,30 @@
// Utilities for browser environments
mergeInto(LibraryManager.library, {
- emscripten_set_main_loop: function(func, fps) {
- fps = fps || 60; // TODO: use requestAnimationFrame
- _emscripten_set_main_loop.cancel = false;
- var jsFunc = FUNCTION_TABLE[func];
- function doOne() {
- if (_emscripten_set_main_loop.cancel) return;
- jsFunc();
- setTimeout(doOne, 1000/fps); // doing this each time means that on exception, we stop
- }
- setTimeout(doOne, 1000/fps);
- },
-
- emscripten_cancel_main_loop: function(func) {
- _emscripten_set_main_loop.cancel = true;
- },
-
+ $Browser__postset: 'Module["requestFullScreen"] = function() { Browser.requestFullScreen() };\n' + // exports
+ 'Module["requestAnimationFrame"] = function(func) { Browser.requestAnimationFrame(func) };\n' +
+ 'Module["pauseMainLoop"] = function() { Browser.mainLoop.pause() };\n' +
+ 'Module["resumeMainLoop"] = function() { Browser.mainLoop.resume() };\n',
$Browser: {
- createContext: function(canvas, useWebGL) {
+ mainLoop: {
+ scheduler: null,
+ shouldPause: false,
+ paused: false,
+ pause: function() {
+ Browser.mainLoop.shouldPause = true;
+ },
+ resume: function() {
+ if (Browser.mainLoop.paused) {
+ Browser.mainLoop.paused = false;
+ Browser.mainLoop.scheduler();
+ }
+ Browser.mainLoop.shouldPause = false;
+ },
+ },
+ pointerLock: false,
+ moduleContextCreatedCallbacks: [],
+
+ createContext: function(canvas, useWebGL, setInModule) {
#if !USE_TYPED_ARRAYS
if (useWebGL) {
Module.print('(USE_TYPED_ARRAYS needs to be enabled for WebGL)');
@@ -39,50 +45,19 @@ mergeInto(LibraryManager.library, {
// Useful to debug native webgl apps: var Module = { printErr: function(x) { console.log(x) } };
var tempCtx = ctx;
var wrapper = {};
- wrapper.objectMap = new WeakMap();
- wrapper.objectCounter = 1;
for (var prop in tempCtx) {
(function(prop) {
switch (typeof tempCtx[prop]) {
case 'function': {
wrapper[prop] = function() {
- var printArgs = Array.prototype.slice.call(arguments).map(function(arg) {
- if (wrapper.objectMap[arg]) return '<' + arg + '|' + wrapper.objectMap[arg] + '>';
- if (arg.toString() == '[object HTMLImageElement]') {
- return arg + '\n\n';
- }
- if (arg.byteLength) {
- var buf = new ArrayBuffer(32);
- var i8buf = new Int8Array(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;
- default:
- alert('unknown array for debugging: ' + arg);
- throw 'see alert';
- }
- 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;
- }
- return arg;
- });
- Module.printErr('[gl_f:' + prop + ':' + printArgs + ']');
+ 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);
- var printRet = ret;
- if (typeof ret == 'object') {
- wrapper.objectMap[ret] = wrapper.objectCounter++;
- printRet = '<' + ret + '|' + wrapper.objectMap[ret] + '>';
+ if (GL.debug && typeof ret != 'undefined') {
+ Module.printErr('[ gl:' + prop + ':return:' + Runtime.prettyPrint(ret) + ']');
}
- Module.printErr('[ gl:' + prop + ':return:' + printRet + ']');
return ret;
}
break;
@@ -93,7 +68,9 @@ mergeInto(LibraryManager.library, {
return tempCtx[prop];
});
wrapper.__defineSetter__(prop, function(value) {
- Module.printErr('[gl_s:' + prop + ':' + value + ']');
+ if (GL.debug) {
+ Module.printErr('[gl_s:' + prop + ':' + value + ']');
+ }
tempCtx[prop] = value;
});
break;
@@ -105,50 +82,232 @@ mergeInto(LibraryManager.library, {
#endif
// Set the background of the WebGL canvas to black
canvas.style.backgroundColor = "black";
+
+ // Warn on context loss
+ canvas.addEventListener('webglcontextlost', function(event) {
+ alert('WebGL context lost. You will need to reload the page.');
+ }, false);
+ }
+ if (setInModule) {
+ Module.ctx = ctx;
+ Module.useWebGL = useWebGL;
+ Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
}
return ctx;
},
- // Given binary data for an image, in a format like PNG or JPG, we convert it
- // to flat pixel data. We do so using the browser's native code.
- // This is deprecated, it is preferred to load binary files, createObjectURL, etc.,
- // see the sdl_* tests.
- /*decodeImage: function(pixels, format) {
- function encodeBase64(data) {
- var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
- var PAD = '=';
- var ret = '';
- var leftchar = 0;
- var leftbits = 0;
- for (var i = 0; i < data.length; i++) {
- leftchar = (leftchar << 8) | data[i];
- leftbits += 8;
- while (leftbits >= 6) {
- var curr = (leftchar >> (leftbits-6)) & 0x3f;
- leftbits -= 6;
- ret += BASE[curr];
- }
+ requestFullScreen: function() {
+ var canvas = Module.canvas;
+ function fullScreenChange() {
+ if (Module['onFullScreen']) Module['onFullScreen']();
+ if (document['webkitFullScreenElement'] === canvas ||
+ document['mozFullScreenElement'] === canvas ||
+ document['fullScreenElement'] === canvas) {
+ canvas.requestPointerLock = canvas['requestPointerLock'] ||
+ canvas['mozRequestPointerLock'] ||
+ canvas['webkitRequestPointerLock'];
+ canvas.requestPointerLock();
}
- if (leftbits == 2) {
- ret += BASE[(leftchar&3) << 4];
- ret += PAD + PAD;
- } else if (leftbits == 4) {
- ret += BASE[(leftchar&0xf) << 2];
- ret += PAD;
+ }
+
+ document.addEventListener('fullscreenchange', fullScreenChange, false);
+ document.addEventListener('mozfullscreenchange', fullScreenChange, false);
+ document.addEventListener('webkitfullscreenchange', fullScreenChange, false);
+
+ function pointerLockChange() {
+ Browser.pointerLock = document['pointerLockElement'] === canvas ||
+ document['mozPointerLockElement'] === canvas ||
+ document['webkitPointerLockElement'] === canvas;
+ }
+
+ document.addEventListener('pointerlockchange', pointerLockChange, false);
+ document.addEventListener('mozpointerlockchange', pointerLockChange, false);
+ document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
+
+ canvas.requestFullScreen = canvas['requestFullScreen'] ||
+ canvas['mozRequestFullScreen'] ||
+ (canvas['webkitRequestFullScreen'] ? function() { canvas['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
+ canvas.requestFullScreen();
+ },
+
+ requestAnimationFrame: function(func) {
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = window['requestAnimationFrame'] ||
+ window['mozRequestAnimationFrame'] ||
+ window['webkitRequestAnimationFrame'] ||
+ window['msRequestAnimationFrame'] ||
+ window['oRequestAnimationFrame'] ||
+ window['setTimeout'];
+ }
+ window.requestAnimationFrame(func);
+ },
+
+ getMovementX: function(event) {
+ return event['movementX'] ||
+ event['mozMovementX'] ||
+ event['webkitMovementX'] ||
+ 0;
+ },
+
+ getMovementY: function(event) {
+ return event['movementY'] ||
+ event['mozMovementY'] ||
+ event['webkitMovementY'] ||
+ 0;
+ },
+
+ xhrLoad: function(url, onload, onerror) {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, true);
+ xhr.responseType = 'arraybuffer';
+ xhr.onload = function() {
+ if (xhr.status == 200) {
+ onload(xhr.response);
+ } else {
+ onerror();
}
- return ret;
+ };
+ xhr.onerror = onerror;
+ xhr.send(null);
+ },
+
+ asyncLoad: function(url, callback) {
+ Browser.xhrLoad(url, function(arrayBuffer) {
+ assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
+ callback(new Uint8Array(arrayBuffer));
+ removeRunDependency();
+ }, function(event) {
+ throw 'Loading data file "' + url + '" failed.';
+ });
+ addRunDependency();
+ }
+ },
+
+ emscripten_async_wget: function(url, file, onload, onerror) {
+ url = Pointer_stringify(url);
+
+ Browser.xhrLoad(url, function(response) {
+ var absolute = Pointer_stringify(file);
+ var index = absolute.lastIndexOf('/');
+ FS.createDataFile(
+ absolute.substr(0, index),
+ absolute.substr(index +1),
+ new Uint8Array(response),
+ true, true);
+
+ if (onload) {
+ FUNCTION_TABLE[onload](file);
+ }
+ }, function(event) {
+ if (onerror) {
+ FUNCTION_TABLE[onerror](file);
}
- var image = new Image();
- image.src = 'data:image/' + format + ';base64,' + encodeBase64(pixels);
- assert(image.complete, 'Image could not be decoded'); // page reload might fix it, decoding is async... need .onload handler...
- var canvas = document.createElement('canvas');
- canvas.width = image.width;
- canvas.height = image.height;
- var ctx = canvas.getContext('2d');
- ctx.drawImage(image, 0, 0);
- var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
- return imageData;
- },*/
+ });
+ },
+
+ emscripten_async_run_script__deps: ['emscripten_run_script'],
+ emscripten_async_run_script: function(script, millis) {
+ Module['noExitRuntime'] = true;
+
+ // TODO: cache these to avoid generating garbage
+ setTimeout(function() {
+ _emscripten_run_script(script);
+ }, millis);
+ },
+
+ emscripten_set_main_loop: function(func, fps) {
+ Module['noExitRuntime'] = true;
+
+ var jsFunc = FUNCTION_TABLE[func];
+ var wrapper = function() {
+ if (Browser.mainLoop.shouldPause) {
+ // catch pauses from non-main loop sources
+ Browser.mainLoop.paused = true;
+ Browser.mainLoop.shouldPause = false;
+ return;
+ }
+ jsFunc();
+ if (Browser.mainLoop.shouldPause) {
+ // catch pauses from the main loop itself
+ Browser.mainLoop.paused = true;
+ Browser.mainLoop.shouldPause = false;
+ return;
+ }
+ Browser.mainLoop.scheduler();
+ }
+ if (fps && fps > 0) {
+ Browser.mainLoop.scheduler = function() {
+ setTimeout(wrapper, 1000/fps); // doing this each time means that on exception, we stop
+ }
+ } else {
+ Browser.mainLoop.scheduler = function() {
+ Browser.requestAnimationFrame(wrapper);
+ }
+ }
+ Browser.mainLoop.scheduler();
+ },
+
+ emscripten_cancel_main_loop: function(func) {
+ Browser.mainLoop.scheduler = null;
+ Browser.mainLoop.shouldPause = true;
+ },
+
+ emscripten_pause_main_loop: function(func) {
+ Browser.mainLoop.pause();
+ },
+
+ emscripten_resume_main_loop: function(func) {
+ Browser.mainLoop.resume();
+ },
+
+ emscripten_async_call: function(func, millis) {
+ Module['noExitRuntime'] = true;
+
+ var asyncCall = Runtime.getFuncWrapper(func);
+ if (millis >= 0) {
+ setTimeout(asyncCall, millis);
+ } else {
+ Browser.requestAnimationFrame(asyncCall);
+ }
+ },
+
+ emscripten_hide_mouse: function() {
+ var styleSheet = document.styleSheets[0];
+ var rules = styleSheet.cssRules;
+ for (var i = 0; i < rules.length; i++) {
+ if (rules[i].cssText.substr(0, 5) == 'canvas') {
+ styleSheet.deleteRule(i);
+ i--;
+ }
+ }
+ styleSheet.insertRule('canvas.emscripten { border: 1px solid black; cursor: none; }', 0);
+ },
+
+ emscripten_set_canvas_size: function(width, height) {
+ Module['canvas'].width = width;
+ Module['canvas'].height = height;
+ },
+
+ emscripten_get_now: function() {
+ if (window['performance'] && window['performance']['now']) {
+ return window['performance']['now']();
+ } else {
+ return Date.now();
+ }
}
});
+/* Useful stuff for browser debugging
+
+function slowLog(label, text) {
+ if (!slowLog.labels) slowLog.labels = {};
+ if (!slowLog.labels[label]) slowLog.labels[label] = 0;
+ var now = Date.now();
+ if (now - slowLog.labels[label] > 1000) {
+ Module.print(label + ': ' + text);
+ slowLog.labels[label] = now;
+ }
+}
+
+*/
+