aboutsummaryrefslogtreecommitdiff
path: root/src/library_glut.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_glut.js')
-rw-r--r--src/library_glut.js438
1 files changed, 438 insertions, 0 deletions
diff --git a/src/library_glut.js b/src/library_glut.js
new file mode 100644
index 00000000..d33f8436
--- /dev/null
+++ b/src/library_glut.js
@@ -0,0 +1,438 @@
+
+var LibraryGLUT = {
+ $GLUT: {
+ initTime: null,
+ idleFunc: null,
+ displayFunc: null,
+ keyboardFunc: null,
+ keyboardUpFunc: null,
+ specialFunc: null,
+ specialUpFunc: null,
+ reshapeFunc: null,
+ motionFunc: null,
+ passiveMotionFunc: null,
+ mouseFunc: null,
+ lastX: 0,
+ lastY: 0,
+ buttons: 0,
+ modifiers: 0,
+ initWindowWidth: 256,
+ initWindowHeight: 256,
+ // Set when going fullscreen
+ windowX: 0,
+ windowY: 0,
+ windowWidth: 0,
+ windowHeight: 0,
+
+ 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;
+ if (event['shiftKey'])
+ GLUT.modifiers += 1; /* GLUT_ACTIVE_SHIFT */
+ if (event['ctrlKey'])
+ GLUT.modifiers += 2; /* GLUT_ACTIVE_CTRL */
+ if (event['altKey'])
+ GLUT.modifiers += 4; /* GLUT_ACTIVE_ALT */
+ },
+
+ onMousemove: function(event) {
+ /* Send motion event only if the motion changed, prevents
+ * spamming our app with uncessary callback call. It does happen in
+ * Chrome on Windows.
+ */
+ var newX = event['clientX'] - Module['canvas'].offsetLeft;
+ var newY = event['clientY'] - Module['canvas'].offsetTop;
+ if (newX == GLUT.lastX && newY == GLUT.lastY)
+ return;
+
+ 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);
+ } else if (GLUT.buttons != 0 && GLUT.motionFunc) {
+ event.preventDefault();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.motionFunc](GLUT.lastX, GLUT.lastY);
+ }
+ },
+
+ getSpecialKey: function(keycode) {
+ var key = null;
+ switch (keycode) {
+ case 0x70 /*DOM_VK_F1*/: key = 1 /* GLUT_KEY_F1 */; break;
+ case 0x71 /*DOM_VK_F2*/: key = 2 /* GLUT_KEY_F2 */; break;
+ case 0x72 /*DOM_VK_F3*/: key = 3 /* GLUT_KEY_F3 */; break;
+ case 0x73 /*DOM_VK_F4*/: key = 4 /* GLUT_KEY_F4 */; break;
+ case 0x74 /*DOM_VK_F5*/: key = 5 /* GLUT_KEY_F5 */; break;
+ case 0x75 /*DOM_VK_F6*/: key = 6 /* GLUT_KEY_F6 */; break;
+ case 0x76 /*DOM_VK_F7*/: key = 7 /* GLUT_KEY_F7 */; break;
+ case 0x77 /*DOM_VK_F8*/: key = 8 /* GLUT_KEY_F8 */; break;
+ case 0x78 /*DOM_VK_F9*/: key = 9 /* GLUT_KEY_F9 */; break;
+ case 0x79 /*DOM_VK_F10*/: key = 10 /* GLUT_KEY_F10 */; break;
+ case 0x7a /*DOM_VK_F11*/: key = 11 /* GLUT_KEY_F11 */; break;
+ case 0x7b /*DOM_VK_F12*/: key = 12 /* GLUT_KEY_F12 */; break;
+ case 0x25 /*DOM_VK_LEFT*/: key = 100 /* GLUT_KEY_LEFT */; break;
+ case 0x26 /*DOM_VK_UP*/: key = 101 /* GLUT_KEY_UP */; break;
+ case 0x27 /*DOM_VK_RIGHT*/: key = 102 /* GLUT_KEY_RIGHT */; break;
+ case 0x28 /*DOM_VK_DOWN*/: key = 103 /* GLUT_KEY_DOWN */; break;
+ case 0x21 /*DOM_VK_PAGE_UP*/: key = 104 /* GLUT_KEY_PAGE_UP */; break;
+ case 0x22 /*DOM_VK_PAGE_DOWN*/: key = 105 /* GLUT_KEY_PAGE_DOWN */; break;
+ case 0x24 /*DOM_VK_HOME*/: key = 106 /* GLUT_KEY_HOME */; break;
+ case 0x23 /*DOM_VK_END*/: key = 107 /* GLUT_KEY_END */; break;
+ case 0x2d /*DOM_VK_INSERT*/: key = 108 /* GLUT_KEY_INSERT */; break;
+
+ case 16 /*DOM_VK_SHIFT*/:
+ case 0x05 /*DOM_VK_LEFT_SHIFT*/:
+ key = 112 /* GLUT_KEY_SHIFT_L */;
+ break;
+ case 0x06 /*DOM_VK_RIGHT_SHIFT*/:
+ key = 113 /* GLUT_KEY_SHIFT_R */;
+ break;
+
+ case 17 /*DOM_VK_CONTROL*/:
+ case 0x03 /*DOM_VK_LEFT_CONTROL*/:
+ key = 114 /* GLUT_KEY_CONTROL_L */;
+ break;
+ case 0x04 /*DOM_VK_RIGHT_CONTROL*/:
+ key = 115 /* GLUT_KEY_CONTROL_R */;
+ break;
+
+ case 18 /*DOM_VK_ALT*/:
+ case 0x02 /*DOM_VK_LEFT_ALT*/:
+ key = 116 /* GLUT_KEY_ALT_L */;
+ break;
+ case 0x01 /*DOM_VK_RIGHT_ALT*/:
+ key = 117 /* GLUT_KEY_ALT_R */;
+ break;
+ };
+ return key;
+ },
+
+ 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) {
+ if (GLUT.specialFunc || GLUT.keyboardFunc) {
+ var key = GLUT.getSpecialKey(event['keyCode']);
+ if (key !== null) {
+ if( GLUT.specialFunc ) {
+ event.preventDefault();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.specialFunc](key, GLUT.lastX, GLUT.lastY);
+ }
+ }
+ else
+ {
+ key = GLUT.getASCIIKey(event);
+ if( key !== null && GLUT.keyboardFunc ) {
+ event.preventDefault();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.keyboardFunc](key, GLUT.lastX, GLUT.lastY);
+ }
+ }
+ }
+ },
+
+ onKeyup: function(event) {
+ if (GLUT.specialUpFunc || GLUT.keyboardUpFunc) {
+ var key = GLUT.getSpecialKey(event['keyCode']);
+ if (key !== null) {
+ if(GLUT.specialUpFunc) {
+ event.preventDefault ();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.specialUpFunc](key, GLUT.lastX, GLUT.lastY);
+ }
+ }
+ else
+ {
+ key = GLUT.getASCIIKey(event);
+ if( key !== null && GLUT.keyboardUpFunc ) {
+ event.preventDefault ();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.keyboardUpFunc](key, GLUT.lastX, GLUT.lastY);
+ }
+ }
+ }
+ },
+
+ onMouseButtonDown: function(event){
+ GLUT.savePosition(event);
+ GLUT.buttons |= (1 << event['button']);
+
+ 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);
+ }
+ },
+
+ onMouseButtonUp: function(event){
+ GLUT.savePosition(event);
+ GLUT.buttons &= ~(1 << event['button']);
+
+ if(GLUT.mouseFunc) {
+ event.preventDefault();
+ GLUT.saveModifiers(event);
+ FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 1/*GLUT_UP*/, GLUT.lastX, GLUT.lastY);
+ }
+ },
+
+ // TODO add fullscreen API ala:
+ // http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
+ onFullScreenEventChange: function(event){
+ var width;
+ var height;
+ if (document["fullScreen"] || document["mozFullScreen"] || document["webkitIsFullScreen"]) {
+ width = screen["width"];
+ height = screen["height"];
+ } else {
+ width = GLUT.windowWidth;
+ height = GLUT.windowHeight;
+ // TODO set position
+ document.removeEventListener('fullscreenchange', GLUT.onFullScreenEventChange, true);
+ document.removeEventListener('mozfullscreenchange', GLUT.onFullScreenEventChange, true);
+ document.removeEventListener('webkitfullscreenchange', GLUT.onFullScreenEventChange, true);
+ }
+ Module['canvas'].width = width;
+ Module['canvas'].height = height;
+ /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */
+ if (GLUT.reshapeFunc) {
+ // console.log("GLUT.reshapeFunc (from FS): " + width + ", " + height);
+ FUNCTION_TABLE[GLUT.reshapeFunc](width, height);
+ }
+ _glutPostRedisplay();
+ },
+
+ requestFullScreen: function() {
+ var RFS = Module["canvas"]['requestFullscreen'] ||
+ Module["canvas"]['requestFullScreen'] ||
+ Module["canvas"]['mozRequestFullScreen'] ||
+ Module["canvas"]['webkitRequestFullScreen'] ||
+ (function() {});
+ RFS.apply(Module["canvas"], []);
+ },
+
+ cancelFullScreen: function() {
+ var CFS = document['exitFullscreen'] ||
+ document['cancelFullScreen'] ||
+ document['mozCancelFullScreen'] ||
+ document['webkitCancelFullScreen'] ||
+ (function() {});
+ CFS.apply(document, []);
+ }
+ },
+
+ glutGetModifiers: function() { return GLUT.modifiers; },
+
+ glutInit: function(argcp, argv) {
+ // Ignore arguments
+ GLUT.initTime = Date.now();
+ },
+
+ glutInitWindowSize: function(width, height) {
+ Module['canvas'].width = GLUT.initWindowWidth = width;
+ Module['canvas'].height = GLUT.initWindowHeight = height;
+ },
+
+ glutInitWindowPosition: function(x, y) {
+ // Ignore for now
+ },
+
+ 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) {
+ 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) {
+ window.setTimeout(function() { FUNCTION_TABLE[func](value); }, msec);
+ },
+
+ glutDisplayFunc: function(func) {
+ GLUT.displayFunc = func;
+ },
+
+ glutKeyboardFunc: function(func) {
+ GLUT.keyboardFunc = func;
+ },
+
+ glutKeyboardUpFunc: function(func) {
+ GLUT.keyboardUpFunc = func;
+ },
+
+ glutSpecialFunc: function(func) {
+ GLUT.specialFunc = func;
+ },
+
+ glutSpecialUpFunc: function(func) {
+ GLUT.specialUpFunc = func;
+ },
+
+ glutReshapeFunc: function(func) {
+ GLUT.reshapeFunc = func;
+ },
+
+ glutMotionFunc: function(func) {
+ GLUT.motionFunc = func;
+ },
+
+ glutPassiveMotionFunc: function(func) {
+ GLUT.passiveMotionFunc = func;
+ },
+
+ glutMouseFunc: function(func) {
+ GLUT.mouseFunc = func;
+ },
+
+ glutCreateWindow__deps: ['$Browser'],
+ glutCreateWindow: function(name) {
+ Module.ctx = Browser.createContext(Module['canvas'], true, true);
+ return 1;
+ },
+
+ glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'],
+ glutReshapeWindow: function(width, height) {
+ GLUT.cancelFullScreen();
+ // console.log("glutReshapeWindow: " + width + ", " + height);
+ Module['canvas'].width = width;
+ Module['canvas'].height = height;
+ if (GLUT.reshapeFunc) {
+ // console.log("GLUT.reshapeFunc: " + width + ", " + height);
+ 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() {
+ GLUT.windowX = 0; // TODO
+ GLUT.windowY = 0; // TODO
+ GLUT.windowWidth = Module['canvas'].width;
+ GLUT.windowHeight = Module['canvas'].height;
+ document.addEventListener('fullscreenchange', GLUT.onFullScreenEventChange, true);
+ document.addEventListener('mozfullscreenchange', GLUT.onFullScreenEventChange, true);
+ document.addEventListener('webkitfullscreenchange', GLUT.onFullScreenEventChange, true);
+ GLUT.requestFullScreen();
+ },
+
+ glutInitDisplayMode: function(mode) {},
+ glutSwapBuffers: function() {},
+
+ glutPostRedisplay: function() {
+ if (GLUT.displayFunc) {
+ Browser.requestAnimationFrame(FUNCTION_TABLE[GLUT.displayFunc]);
+ }
+ },
+
+ glutMainLoop__deps: ['$GLUT', 'glutReshapeWindow', 'glutPostRedisplay'],
+ glutMainLoop: function() {
+
+ 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 called, simulating infinite loop by throwing so we get right into the JS event loop';
+ },
+
+};
+
+autoAddDeps(LibraryGLUT, '$GLUT');
+mergeInto(LibraryManager.library, LibraryGLUT);
+