diff options
Diffstat (limited to 'src/library_glut.js')
-rw-r--r-- | src/library_glut.js | 252 |
1 files changed, 209 insertions, 43 deletions
diff --git a/src/library_glut.js b/src/library_glut.js index 0736d5ae..5d9fb672 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -2,6 +2,7 @@ var LibraryGLUT = { $GLUT: { initTime: null, + idleFunc: null, displayFunc: null, keyboardFunc: null, keyboardUpFunc: null, @@ -15,6 +16,14 @@ var LibraryGLUT = { lastY: 0, buttons: 0, modifiers: 0, + initWindowWidth: 256, + initWindowHeight: 256, + + savePosition: function(event) { + /* TODO maybe loop here ala http://www.quirksmode.org/js/findpos.html */ + GLUT.lastX = event['clientX'] - Module['canvas'].offsetLeft; + GLUT.lastY = event['clientY'] - Module['canvas'].offsetTop; + }, saveModifiers: function(event) { GLUT.modifiers = 0; @@ -27,9 +36,8 @@ var LibraryGLUT = { }, onMousemove: function(event) { - GLUT.lastX = event['clientX']; - GLUT.lastY = event['clientY']; - if (GLUT.buttons == 0 && GLUT.passiveMotionFunc) { + GLUT.savePosition(event); + if (GLUT.buttons == 0 && event.target == Module["canvas"] && GLUT.passiveMotionFunc) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.passiveMotionFunc](GLUT.lastX, GLUT.lastY); @@ -68,9 +76,42 @@ var LibraryGLUT = { return key; }, - getASCIIKey: function(keycode) { - // TODO apply modifiers, etc - return keycode; + getASCIIKey: function(event) { + if (event['ctrlKey'] || event['altKey'] || event['metaKey']) return null; + + var keycode = event['keyCode']; + + /* The exact list is soooo hard to find in a canonical place! */ + + if (48 <= keycode && keycode <= 57) + return keycode; // numeric TODO handle shift? + if (65 <= keycode && keycode <= 90) + return event['shiftKey'] ? keycode : keycode + 32; + if (106 <= keycode && keycode <= 111) + return keycode - 106 + 42; // *,+-./ TODO handle shift? + + switch (keycode) { + case 27: // escape + case 32: // space + case 61: // equal + return keycode; + } + + var s = event['shiftKey']; + switch (keycode) { + case 186: return s ? 58 : 59; // colon / semi-colon + case 187: return s ? 43 : 61; // add / equal (these two may be wrong) + case 188: return s ? 60 : 44; // less-than / comma + case 189: return s ? 95 : 45; // dash + case 190: return s ? 62 : 46; // greater-than / period + case 191: return s ? 63 : 47; // forward slash + case 219: return s ? 123 : 91; // open bracket + case 220: return s ? 124 : 47; // back slash + case 221: return s ? 125 : 93; // close braket + case 222: return s ? 34 : 39; // single quote + } + + return null; }, onKeydown: function(event) { @@ -85,11 +126,11 @@ var LibraryGLUT = { } else { - key = GLUT.getASCIIKey(event['keyCode']); + key = GLUT.getASCIIKey(event); if( key !== null && GLUT.keyboardFunc ) { event.preventDefault(); GLUT.saveModifiers(event); - FUNCTION_TABLE[GLUT.keyboardFunc](event['keyCode'], GLUT.lastX, GLUT.lastY); + FUNCTION_TABLE[GLUT.keyboardFunc](key, GLUT.lastX, GLUT.lastY); } } } @@ -107,22 +148,24 @@ var LibraryGLUT = { } else { - key = GLUT.getASCIIKey(event['keyCode']); + key = GLUT.getASCIIKey(event); if( key !== null && GLUT.keyboardUpFunc ) { event.preventDefault (); GLUT.saveModifiers(event); - FUNCTION_TABLE[GLUT.keyboardUpFunc](event['keyCode'], GLUT.lastX, GLUT.lastY); + FUNCTION_TABLE[GLUT.keyboardUpFunc](key, GLUT.lastX, GLUT.lastY); } } } }, onMouseButtonDown: function(event){ - GLUT.lastX = event['clientX']; - GLUT.lastY = event['clientY']; + GLUT.savePosition(event); GLUT.buttons |= (1 << event['button']); - if(GLUT.mouseFunc){ + if(event.target == Module["canvas"] && GLUT.mouseFunc){ + try { + event.target.setCapture(); + } catch (e) {} event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 0/*GLUT_DOWN*/, GLUT.lastX, GLUT.lastY); @@ -130,8 +173,7 @@ var LibraryGLUT = { }, onMouseButtonUp: function(event){ - GLUT.lastX = event['clientX']; - GLUT.lastY = event['clientY']; + GLUT.savePosition(event); GLUT.buttons &= ~(1 << event['button']); if(GLUT.mouseFunc) { @@ -140,6 +182,48 @@ var LibraryGLUT = { FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 1/*GLUT_UP*/, GLUT.lastX, GLUT.lastY); } }, + + requestFullScreen: function() { + var RFS = function() {}; + if (Module["canvas"]['requestFullscreen']) { + RFS = Module["canvas"]['requestFullscreen']; + } else if (Module["canvas"]['requestFullScreen']) { + RFS = Module["canvas"]['requestFullScreen']; + } else if (Module["canvas"]['mozRequestFullScreen']) { + RFS = Module["canvas"]['mozRequestFullScreen']; + } else if (Module["canvas"]['webkitRequestFullScreen']) { + RFS = Module["canvas"]['webkitRequestFullScreen']; + } + RFS.apply(Module["canvas"], []); + }, + + cancelFullScreen: function() { + var CFS = function() {}; + if (document['exitFullscreen']) { + CFS = document['exitFullscreen']; + } else if (document['cancelFullScreen']) { + CFS = document['cancelFullScreen']; + } else if (document['mozCancelFullScreen']) { + CFS = document['mozCancelFullScreen']; + } else if (document['webkitCancelFullScreen']) { + CFS = document['webkitCancelFullScreen']; + } + CFS.apply(document, []); + }, + + requestAnimationFrame: function(func) { + var RAF = window['setTimeout']; + if (window['requestAnimationFrame']) { + RAF = window['requestAnimationFrame']; + } else if (window['mozRequestAnimationFrame']) { + RAF = window['mozRequestAnimationFrame']; + } else if (window['webkitRequestAnimationFrame']) { + RAF = window['webkitRequestAnimationFrame']; + } else if (window['msRequestAnimationFrame']) { + RAF = window['msRequestAnimationFrame']; + } + RAF.apply(window, [func]); + }, }, glutGetModifiers: function() { return GLUT.modifiers; }, @@ -147,30 +231,50 @@ var LibraryGLUT = { glutInit: function(argcp, argv) { // Ignore arguments GLUT.initTime = Date.now(); - window.addEventListener("keydown", GLUT.onKeydown, true); - window.addEventListener("keyup", GLUT.onKeyup, true); - window.addEventListener("mousemove", GLUT.onMousemove, true); - window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); - window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); }, glutInitWindowSize: function(width, height) { - Module['canvas'].width = width; - Module['canvas'].height = height; + Module['canvas'].width = GLUT.initWindowWidth = width; + Module['canvas'].height = GLUT.initWindowHeight = height; }, glutGet: function(type) { switch (type) { + case 100: /* GLUT_WINDOW_X */ + return 0; /* TODO */ + case 101: /* GLUT_WINDOW_Y */ + return 0; /* TODO */ + case 102: /* GLUT_WINDOW_WIDTH */ + return Module['canvas'].width; + case 103: /* GLUT_WINDOW_HEIGHT */ + return Module['canvas'].height; + case 500: /* GLUT_INIT_WINDOW_X */ + return 0; /* TODO */ + case 501: /* GLUT_INIT_WINDOW_Y */ + return 0; /* TODO */ + case 502: /* GLUT_INIT_WINDOW_WIDTH */ + return GLUT.initWindowWidth; + case 503: /* GLUT_INIT_WINDOW_HEIGHT */ + return GLUT.initWindowHeight; case 700: /* GLUT_ELAPSED_TIME */ var now = Date.now(); return now - GLUT.initTime; + default: throw "glutGet(" + type + ") not implemented yet"; } }, glutIdleFunc: function(func) { - window.setTimeout(FUNCTION_TABLE[func], 0); + var callback = function() { + if (GLUT.idleFunc) { + FUNCTION_TABLE[GLUT.idleFunc](); + window.setTimeout(callback, 0); + } + } + if (!GLUT.idleFunc) + window.setTimeout(callback, 0); + GLUT.idleFunc = func; }, glutTimerFunc: function(msec, func, value) { @@ -216,9 +320,10 @@ var LibraryGLUT = { glutCreateWindow: function(name) { #if USE_TYPED_ARRAYS try { - var ctx = Module.canvas.getContext('experimental-webgl'); + var ctx = Module["canvas"].getContext('experimental-webgl'); if (!ctx) throw 'Could not create canvas :('; #if GL_DEBUG + // Useful to debug native webgl apps: var Module = { printErr: function(x) { console.log(x) } }; var wrapper = {}; wrapper.objectMap = new WeakMap(); wrapper.objectCounter = 1; @@ -229,7 +334,31 @@ var LibraryGLUT = { wrapper[prop] = function() { var printArgs = Array.prototype.slice.call(arguments).map(function(arg) { if (wrapper.objectMap[arg]) return '<' + arg + '|' + wrapper.objectMap[arg] + '>'; - if (arg.subarray) return '{' + arg + '|' + arg.length /*+ '|' + Array.prototype.slice.call(arg).toString().replace(/,/g, ', ')*/ + '}'; + 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 + ']'); @@ -264,7 +393,7 @@ var LibraryGLUT = { #endif // Set the background of the canvas to black, because glut gives us a // window which has a black background by default. - Module.canvas.style.backgroundColor = "black"; + Module["canvas"].style.backgroundColor = "black"; } catch (e) { Module.print('(canvas not available)'); } @@ -274,33 +403,70 @@ var LibraryGLUT = { return 1; }, + glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'], + glutReshapeWindow: function(width, height) { + GLUT.cancelFullScreen(); + Module['canvas'].width = width; + Module['canvas'].height = height; + if (GLUT.reshapeFunc) { + FUNCTION_TABLE[GLUT.reshapeFunc](width, height); + } + _glutPostRedisplay(); + }, + + glutPositionWindow__deps: ['$GLUT', 'glutPostRedisplay'], + glutPositionWindow: function(x, y) { + GLUT.cancelFullScreen(); + /* TODO */ + _glutPostRedisplay(); + }, + + glutFullScreen__deps: ['$GLUT', 'glutPostRedisplay'], + glutFullScreen: function() { + var width = screen["width"]; + var height = screen["height"]; + /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ + Module['canvas'].width = width; + Module['canvas'].height = height; + if (GLUT.reshapeFunc) { + FUNCTION_TABLE[GLUT.reshapeFunc](width, height); + } + GLUT.requestFullScreen(); + window.setTimeout(function() { + _glutPostRedisplay(); + }, 0); + }, + glutInitDisplayMode: function(mode) {}, glutSwapBuffers: function() {}, glutPostRedisplay: function() { if (GLUT.displayFunc) { - var RAF = window['setTimeout']; - if (window['requestAnimationFrame']) { - RAF = window['requestAnimationFrame']; - } else if (window['mozRequestAnimationFrame']) { - RAF = window['mozRequestAnimationFrame']; - } else if (window['webkitRequestAnimationFrame']) { - RAF = window['webkitRequestAnimationFrame']; - } else if (window['msRequestAnimationFrame']) { - RAF = window['msRequestAnimationFrame']; - } - RAF.apply(window, [FUNCTION_TABLE[GLUT.displayFunc]]); + GLUT.requestAnimationFrame(FUNCTION_TABLE[GLUT.displayFunc]); } }, - glutMainLoop__deps: ['$GLUT', 'glutPostRedisplay'], + glutMainLoop__deps: ['$GLUT', 'glutReshapeWindow', 'glutPostRedisplay'], glutMainLoop: function() { - if (GLUT.reshapeFunc) { - FUNCTION_TABLE[GLUT.reshapeFunc](Module['canvas'].width, - Module['canvas'].height); - } + + window.addEventListener("keydown", GLUT.onKeydown, true); + window.addEventListener("keyup", GLUT.onKeyup, true); + window.addEventListener("mousemove", GLUT.onMousemove, true); + window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); + window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); + + __ATEXIT__.push({ func: function() { + window.removeEventListener("keydown", GLUT.onKeydown, true); + window.removeEventListener("keyup", GLUT.onKeyup, true); + window.removeEventListener("mousemove", GLUT.onMousemove, true); + window.removeEventListener("mousedown", GLUT.onMouseButtonDown, true); + window.removeEventListener("mouseup", GLUT.onMouseButtonUp, true); + Module["canvas"].width = Module["canvas"].height = 1; + } }); + + _glutReshapeWindow(Module['canvas'].width, Module['canvas'].height); _glutPostRedisplay(); - throw 'GLUT mainloop should never return'; + throw 'GLUT mainloop called, simulating infinite loop by throwing so we get right into the JS event loop'; }, }; |