diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jsifier.js | 1 | ||||
-rw-r--r-- | src/library_browser.js | 36 | ||||
-rw-r--r-- | src/library_gl.js | 14 | ||||
-rw-r--r-- | src/library_glut.js | 7 | ||||
-rw-r--r-- | src/library_sdl.js | 15 | ||||
-rw-r--r-- | src/proxyClient.js | 27 | ||||
-rw-r--r-- | src/proxyWorker.js | 87 | ||||
-rw-r--r-- | src/webGLClient.js | 108 | ||||
-rw-r--r-- | src/webGLWorker.js | 721 |
9 files changed, 964 insertions, 52 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index d1001dac..1f6440dd 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1899,6 +1899,7 @@ function JSify(data, functionsOnly) { print('}'); } if (PROXY_TO_WORKER) { + print(read('webGLWorker.js')); print(read('proxyWorker.js')); } if (DETERMINISTIC) { diff --git a/src/library_browser.js b/src/library_browser.js index 57ca5a24..8e86371e 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -41,6 +41,21 @@ mergeInto(LibraryManager.library, { Module['setStatus'](''); } } + }, + runIter: function(func) { + if (ABORT) return; + if (Module['preMainLoop']) Module['preMainLoop'](); + 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, @@ -405,7 +420,7 @@ mergeInto(LibraryManager.library, { window['webkitRequestAnimationFrame'] || window['msRequestAnimationFrame'] || window['oRequestAnimationFrame'] || - window['setTimeout']; + function(func) { setTimeout(func, 1000/60) }; } window.requestAnimationFrame(func); } @@ -954,28 +969,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 diff --git a/src/library_gl.js b/src/library_gl.js index 2659a9d9..71cc8454 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -1316,7 +1316,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform view = GL.miniTempBufferViews[0]; view[0] = {{{ makeGetValue('value', '0', 'float') }}}; @@ -1333,7 +1333,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform view = GL.miniTempBufferViews[1]; view[0] = {{{ makeGetValue('value', '0', 'float') }}}; @@ -1351,7 +1351,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform view = GL.miniTempBufferViews[2]; view[0] = {{{ makeGetValue('value', '0', 'float') }}}; @@ -1370,7 +1370,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform view = GL.miniTempBufferViews[3]; view[0] = {{{ makeGetValue('value', '0', 'float') }}}; @@ -1390,7 +1390,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform matrix view = GL.miniTempBufferViews[3]; for (var i = 0; i < 4; i++) { @@ -1409,7 +1409,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform matrix view = GL.miniTempBufferViews[8]; for (var i = 0; i < 9; i++) { @@ -1428,7 +1428,7 @@ var LibraryGL = { #endif location = GL.uniforms[location]; var view; - if (count == 1) { + if (count === 1) { // avoid allocation for the common case of uploading one uniform matrix view = GL.miniTempBufferViews[15]; for (var i = 0; i < 16; i++) { diff --git a/src/library_glut.js b/src/library_glut.js index 445e08a4..d6293d85 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -383,7 +383,7 @@ var LibraryGLUT = { function callback() { if (GLUT.idleFunc) { Runtime.dynCall('v', GLUT.idleFunc); - Browser.safeSetTimeout(callback, 0); + Browser.safeSetTimeout(callback, 4); // HTML spec specifies a 4ms minimum delay on the main thread; workers might get more, but we standardize here } } if (!GLUT.idleFunc) { @@ -489,8 +489,9 @@ var LibraryGLUT = { GLUT.requestedAnimationFrame = true; Browser.requestAnimationFrame(function() { GLUT.requestedAnimationFrame = false; - if (ABORT) return; - Runtime.dynCall('v', GLUT.displayFunc); + Browser.mainLoop.runIter(function() { + Runtime.dynCall('v', GLUT.displayFunc); + }); }); } }, diff --git a/src/library_sdl.js b/src/library_sdl.js index 07a618a3..104a0300 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1321,7 +1321,13 @@ var LibrarySDL = { height = canvas.height; } - Browser.setCanvasSize(width, height, true); + Browser.setCanvasSize(width, height, +#if PROXY_TO_WORKER == 0 + true // XXX why? +#else + false +#endif + ); // Free the old surface first. if (SDL.screen) { SDL.freeSurface(SDL.screen); @@ -2883,7 +2889,12 @@ var LibrarySDL = { return _emscripten_GetProcAddress(name_); }, - SDL_GL_SwapBuffers: function() {}, + SDL_GL_SwapBuffers: function() { +#if PROXY_TO_WORKER + // postMainLoop is where the proxy code listens, to know when to proxy buffered render commands + if (Module['postMainLoop']) Module['postMainLoop'](); +#endif + }, // SDL 2 diff --git a/src/proxyClient.js b/src/proxyClient.js index 2d1c76fe..1c9b6548 100644 --- a/src/proxyClient.js +++ b/src/proxyClient.js @@ -1,8 +1,6 @@ // proxy to/from worker -Module.ctx = Module.canvas.getContext('2d'); - // render var renderFrameData = null; @@ -26,11 +24,20 @@ window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequest // end render +// Frame throttling + +var frameId = 0; + +// Worker + var worker = new Worker('{{{ filename }}}.js'); +WebGLClient.prefetch(); // XXX not guaranteed to be before worker main() + var workerResponded = false; worker.onmessage = function worker_onmessage(event) { + //dump('\nclient got ' + JSON.stringify(event.data).substr(0, 150) + '\n'); if (!workerResponded) { workerResponded = true; if (Module.setStatus) Module.setStatus(''); @@ -52,10 +59,15 @@ worker.onmessage = function worker_onmessage(event) { } case 'canvas': { switch (data.op) { + case 'getContext': { + Module.ctx = Module.canvas.getContext(data.type, data.attributes); + if (data.type !== '2d') Module.glClient = new WebGLClient(); + break; + } case 'resize': { Module.canvas.width = data.width; Module.canvas.height = data.height; - Module.canvasData = Module.ctx.getImageData(0, 0, data.width, data.height); + if (Module.ctx && Module.ctx.getImageData) Module.canvasData = Module.ctx.getImageData(0, 0, data.width, data.height); worker.postMessage({ target: 'canvas', boundingClientRect: cloneObject(Module.canvas.getBoundingClientRect()) }); break; } @@ -74,6 +86,15 @@ worker.onmessage = function worker_onmessage(event) { } break; } + case 'gl': { + Module.glClient.onmessage(data); + break; + } + case 'tick': { + frameId = data.id; + worker.postMessage({ target: 'tock', id: frameId }); + break; + } default: throw 'what?'; } }; diff --git a/src/proxyWorker.js b/src/proxyWorker.js index cfe0c26e..70b55244 100644 --- a/src/proxyWorker.js +++ b/src/proxyWorker.js @@ -1,3 +1,7 @@ +function PropertyBag() { + this.addProperty = function(){}; + this.removeProperty = function(){}; +}; function EventListener() { this.listeners = {}; @@ -7,6 +11,14 @@ function EventListener() { this.listeners[event].push(func); }; + this.removeEventListener = function(event, func) { + var list = this.listeners[event]; + if (!list) return; + var me = list.indexOf(func); + if (me < 0) return; + list.splice(me, 1); + }; + this.fireEvent = function fireEvent(event) { event.preventDefault = function(){}; @@ -26,6 +38,8 @@ window.close = function window_close() { postMessage({ target: 'window', method: 'close' }); }; +var webGLWorker = new WebGLWorker(); + var document = new EventListener(); document.createElement = function document_createElement(what) { @@ -42,25 +56,29 @@ document.createElement = function document_createElement(what) { postMessage({ target: 'canvas', op: 'resize', width: canvas.width, height: canvas.height }); } }; - canvas.getContext = function canvas_getContext(type) { - assert(type == '2d'); - return { - getImageData: function(x, y, w, h) { - assert(x == 0 && y == 0 && w == canvas.width && h == canvas.height); - canvas.ensureData(); - return { - width: canvas.data.width, - height: canvas.data.height, - data: new Uint8Array(canvas.data.data) // TODO: can we avoid this copy? - }; - }, - putImageData: function(image, x, y) { - canvas.ensureData(); - assert(x == 0 && y == 0 && image.width == canvas.width && image.height == canvas.height); - canvas.data.data.set(image.data); // TODO: can we avoid this copy? - postMessage({ target: 'canvas', op: 'render', image: canvas.data }); - } - }; + canvas.getContext = function canvas_getContext(type, attributes) { + postMessage({ target: 'canvas', op: 'getContext', type: type, attributes: attributes }); + if (type === '2d') { + return { + getImageData: function(x, y, w, h) { + assert(x == 0 && y == 0 && w == canvas.width && h == canvas.height); + canvas.ensureData(); + return { + width: canvas.data.width, + height: canvas.data.height, + data: new Uint8Array(canvas.data.data) // TODO: can we avoid this copy? + }; + }, + putImageData: function(image, x, y) { + canvas.ensureData(); + assert(x == 0 && y == 0 && image.width == canvas.width && image.height == canvas.height); + canvas.data.data.set(image.data); // TODO: can we avoid this copy? + postMessage({ target: 'canvas', op: 'render', image: canvas.data }); + } + }; + } else { + return webGLWorker; + } }; canvas.boundingClientRect = {}; canvas.getBoundingClientRect = function canvas_getBoundingClientRect() { @@ -73,12 +91,15 @@ document.createElement = function document_createElement(what) { right: canvas.boundingClientRect.right }; }; + canvas.style = new PropertyBag(); return canvas; } default: throw 'document.createElement ' + what; } }; +document.documentElement = {}; + if (typeof console === 'undefined') { var console = { log: function(x) { @@ -98,6 +119,25 @@ Module.printErr = function Module_printErr(x) { postMessage({ target: 'stderr', content: x }); }; +// Browser hooks + +Browser.resizeListeners.push(function(width, height) { + postMessage({ target: 'canvas', op: 'resize', width: width, height: height }); +}); + +// Frame throttling + +var frameId = 0; +var clientFrameId = 0; + +var postMainLoop = Module['postMainLoop']; +Module['postMainLoop'] = function() { + if (postMainLoop) postMainLoop(); + // frame complete, send a frame id + postMessage({ target: 'tick', id: frameId++ }); + commandBuffer = []; +}; + // buffer messages until the program starts to run var messageBuffer = null; @@ -122,6 +162,7 @@ onmessage = function onmessage(message) { } messageBuffer.push(message); } + //dump('worker got ' + JSON.stringify(message.data) + '\n'); switch (message.data.target) { case 'document': { document.fireEvent(message.data.event); @@ -139,6 +180,14 @@ onmessage = function onmessage(message) { } else throw 'ey?'; break; } + case 'gl': { + webGLWorker.onmessage(message.data); + break; + } + case 'tock': { + clientFrameId = message.data.id; + break; + } default: throw 'wha? ' + message.data.target; } }; diff --git a/src/webGLClient.js b/src/webGLClient.js new file mode 100644 index 00000000..736b1ae3 --- /dev/null +++ b/src/webGLClient.js @@ -0,0 +1,108 @@ +// WebGLWorker client code + +function assert(x) { + if (!x) throw 'failed assert'; +} + +function WebGLClient() { + var objects = {}; + + function fixArgs(command, args) { + switch (command) { + case 'getProgramParameter': + case 'getShaderParameter': + case 'uniform1i': + case 'uniform1f': + case 'uniform4fv': + case 'uniformMatrix4fv': + case 'getUniformLocation': + case 'useProgram': + case 'linkProgram': + case 'bindAttribLocation': + case 'compileShader': + case 'shaderSource': args[0] = objects[args[0]]; break; + case 'attachShader': args[0] = objects[args[0]]; args[1] = objects[args[1]]; break; + case 'bindTexture': + case 'bindBuffer': args[1] = args[1] ? objects[args[1]] : null; break; + } + return args; + } + + function renderCommands(buffer) { + var ctx = Module.ctx; + var i = 0; + var len = buffer.length; + //dump('issuing commands, buffer len: ' + len + '\n'); + while (i < len) { + var command = buffer[i++]; + assert(typeof command === 'string') + var numArgs = buffer[i++]; + assert(typeof numArgs === 'number', command); + //dump('issue ' + [command, numArgs, 'peek:' + buffer.slice(i, i+5)] + '\n'); + if (numArgs === 0) { + //dump('issue: ' + command + '\n'); + if (command === 'getError') { + assert(ctx.getError() === ctx.NO_ERROR, 'we cannot handle errors, we are async proxied WebGL'); + } else { + ctx[command](); + } + } else if (numArgs > 0) { + var args = fixArgs(command, buffer.slice(i, i+numArgs)); + i += numArgs; + //dump('issue+: ' + command + '(' + args + '), ' + numArgs + '\n'); + if (command === 'getShaderParameter' || command === 'getProgramParameter') { + assert(ctx[command](args[0], args[1]), 'we cannot handle errors, we are async proxied WebGL'); + } else { + ctx[command].apply(ctx, args); + } + } else { + // negative means a constructor, last argument is the id to save as + numArgs = -numArgs - 1; + var args = fixArgs(command, buffer.slice(i, i+numArgs)); + i += numArgs; + var id = buffer[i++]; + //dump('issue-: ' + command + '(' + args + '), ' + numArgs + '\n'); + objects[id] = ctx[command].apply(ctx, args); + } + assert(i <= len); + } + } + + var commandBuffers = []; + + function renderAllCommands() { + // TODO: we can avoid running commands from buffers that are not the last, if they + // have no side effects, as each buffer is from a different frame + for (var i = 0; i < commandBuffers.length; i++) { + renderCommands(commandBuffers[i]); + } + commandBuffers.length = 0; + } + + this.onmessage = function(msg) { + //dump('client GL got ' + JSON.stringify(msg) + '\n'); + switch(msg.op) { + case 'render': { + if (commandBuffers.length === 0) { + // requestion a new frame, we will clear the buffers after rendering them + window.requestAnimationFrame(renderAllCommands); + } + commandBuffers.push(msg.commandBuffer); + break; + } + default: throw 'weird gl onmessage ' + JSON.stringify(msg); + } + }; +} + +WebGLClient.prefetch = function() { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('webgl-experimental') || canvas.getContext('webgl'); + if (!ctx) return; + var parameters = {}; + ['MAX_VERTEX_ATTRIBS', 'MAX_TEXTURE_IMAGE_UNITS'].forEach(function(name) { + parameters[ctx[name]] = ctx.getParameter(ctx[name]); + }); + worker.postMessage({ target: 'gl', op: 'setPrefetched', parameters: parameters, extensions: ctx.getSupportedExtensions() }); +}; + diff --git a/src/webGLWorker.js b/src/webGLWorker.js new file mode 100644 index 00000000..c16caa00 --- /dev/null +++ b/src/webGLWorker.js @@ -0,0 +1,721 @@ +// WebGLWorker worker code + +function WebGLBuffer(id) { + this.what = 'buffer'; + this.id = id; +} +function WebGLProgram(id) { + this.what = 'program'; + this.id = id; + this.shaders = []; + this.attributes = {}; + this.attributeVec = []; +} +function WebGLFramebuffer(id) { + this.what = 'frameBuffer'; + this.id = id; +} +function WebGLRenderbuffer(id) { + this.what = 'renderBuffer'; + this.id = id; +} +function WebGLTexture(id) { + this.what = 'texture'; + this.id = id; +} + +function WebGLWorker() { + //======= + // State + //======= + + this.prefetchedParameters = {}; + this.prefetchedExtensions = {}; + + var commandBuffer = []; + + var nextId = 1; + + var bindings = { + texture2D: null + }; + + //=========== + // Constants + //=========== + + /* ClearBufferMask */ + this.DEPTH_BUFFER_BIT = 0x00000100; + this.STENCIL_BUFFER_BIT = 0x00000400; + this.COLOR_BUFFER_BIT = 0x00004000; + + /* BeginMode */ + this.POINTS = 0x0000; + this.LINES = 0x0001; + this.LINE_LOOP = 0x0002; + this.LINE_STRIP = 0x0003; + this.TRIANGLES = 0x0004; + this.TRIANGLE_STRIP = 0x0005; + this.TRIANGLE_FAN = 0x0006; + + /* AlphaFunction (not supported in ES20) */ + /* NEVER */ + /* LESS */ + /* EQUAL */ + /* LEQUAL */ + /* GREATER */ + /* NOTEQUAL */ + /* GEQUAL */ + /* ALWAYS */ + + /* BlendingFactorDest */ + this.ZERO = 0; + this.ONE = 1; + this.SRC_COLOR = 0x0300; + this.ONE_MINUS_SRC_COLOR = 0x0301; + this.SRC_ALPHA = 0x0302; + this.ONE_MINUS_SRC_ALPHA = 0x0303; + this.DST_ALPHA = 0x0304; + this.ONE_MINUS_DST_ALPHA = 0x0305; + + /* BlendingFactorSrc */ + /* ZERO */ + /* ONE */ + this.DST_COLOR = 0x0306; + this.ONE_MINUS_DST_COLOR = 0x0307; + this.SRC_ALPHA_SATURATE = 0x0308; + /* SRC_ALPHA */ + /* ONE_MINUS_SRC_ALPHA */ + /* DST_ALPHA */ + /* ONE_MINUS_DST_ALPHA */ + + /* BlendEquationSeparate */ + this.FUNC_ADD = 0x8006; + this.BLEND_EQUATION = 0x8009; + this.BLEND_EQUATION_RGB = 0x8009; /* same as BLEND_EQUATION */ + this.BLEND_EQUATION_ALPHA = 0x883D; + + /* BlendSubtract */ + this.FUNC_SUBTRACT = 0x800A; + this.FUNC_REVERSE_SUBTRACT = 0x800B; + + /* Separate Blend Functions */ + this.BLEND_DST_RGB = 0x80C8; + this.BLEND_SRC_RGB = 0x80C9; + this.BLEND_DST_ALPHA = 0x80CA; + this.BLEND_SRC_ALPHA = 0x80CB; + this.CONSTANT_COLOR = 0x8001; + this.ONE_MINUS_CONSTANT_COLOR = 0x8002; + this.CONSTANT_ALPHA = 0x8003; + this.ONE_MINUS_CONSTANT_ALPHA = 0x8004; + this.BLEND_COLOR = 0x8005; + + /* Buffer Objects */ + this.ARRAY_BUFFER = 0x8892; + this.ELEMENT_ARRAY_BUFFER = 0x8893; + this.ARRAY_BUFFER_BINDING = 0x8894; + this.ELEMENT_ARRAY_BUFFER_BINDING = 0x8895; + + this.STREAM_DRAW = 0x88E0; + this.STATIC_DRAW = 0x88E4; + this.DYNAMIC_DRAW = 0x88E8; + + this.BUFFER_SIZE = 0x8764; + this.BUFFER_USAGE = 0x8765; + + this.CURRENT_VERTEX_ATTRIB = 0x8626; + + /* CullFaceMode */ + this.FRONT = 0x0404; + this.BACK = 0x0405; + this.FRONT_AND_BACK = 0x0408; + + /* DepthFunction */ + /* NEVER */ + /* LESS */ + /* EQUAL */ + /* LEQUAL */ + /* GREATER */ + /* NOTEQUAL */ + /* GEQUAL */ + /* ALWAYS */ + + /* EnableCap */ + /* TEXTURE_2D */ + this.CULL_FACE = 0x0B44; + this.BLEND = 0x0BE2; + this.DITHER = 0x0BD0; + this.STENCIL_TEST = 0x0B90; + this.DEPTH_TEST = 0x0B71; + this.SCISSOR_TEST = 0x0C11; + this.POLYGON_OFFSET_FILL = 0x8037; + this.SAMPLE_ALPHA_TO_COVERAGE = 0x809E; + this.SAMPLE_COVERAGE = 0x80A0; + + /* ErrorCode */ + this.NO_ERROR = 0; + this.INVALID_ENUM = 0x0500; + this.INVALID_VALUE = 0x0501; + this.INVALID_OPERATION = 0x0502; + this.OUT_OF_MEMORY = 0x0505; + + /* FrontFaceDirection */ + this.CW = 0x0900; + this.CCW = 0x0901; + + /* GetPName */ + this.LINE_WIDTH = 0x0B21; + this.ALIASED_POINT_SIZE_RANGE = 0x846D; + this.ALIASED_LINE_WIDTH_RANGE = 0x846E; + this.CULL_FACE_MODE = 0x0B45; + this.FRONT_FACE = 0x0B46; + this.DEPTH_RANGE = 0x0B70; + this.DEPTH_WRITEMASK = 0x0B72; + this.DEPTH_CLEAR_VALUE = 0x0B73; + this.DEPTH_FUNC = 0x0B74; + this.STENCIL_CLEAR_VALUE = 0x0B91; + this.STENCIL_FUNC = 0x0B92; + this.STENCIL_FAIL = 0x0B94; + this.STENCIL_PASS_DEPTH_FAIL = 0x0B95; + this.STENCIL_PASS_DEPTH_PASS = 0x0B96; + this.STENCIL_REF = 0x0B97; + this.STENCIL_VALUE_MASK = 0x0B93; + this.STENCIL_WRITEMASK = 0x0B98; + this.STENCIL_BACK_FUNC = 0x8800; + this.STENCIL_BACK_FAIL = 0x8801; + this.STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802; + this.STENCIL_BACK_PASS_DEPTH_PASS = 0x8803; + this.STENCIL_BACK_REF = 0x8CA3; + this.STENCIL_BACK_VALUE_MASK = 0x8CA4; + this.STENCIL_BACK_WRITEMASK = 0x8CA5; + this.VIEWPORT = 0x0BA2; + this.SCISSOR_BOX = 0x0C10; + /* SCISSOR_TEST */ + this.COLOR_CLEAR_VALUE = 0x0C22; + this.COLOR_WRITEMASK = 0x0C23; + this.UNPACK_ALIGNMENT = 0x0CF5; + this.PACK_ALIGNMENT = 0x0D05; + this.MAX_TEXTURE_SIZE = 0x0D33; + this.MAX_VIEWPORT_DIMS = 0x0D3A; + this.SUBPIXEL_BITS = 0x0D50; + this.RED_BITS = 0x0D52; + this.GREEN_BITS = 0x0D53; + this.BLUE_BITS = 0x0D54; + this.ALPHA_BITS = 0x0D55; + this.DEPTH_BITS = 0x0D56; + this.STENCIL_BITS = 0x0D57; + this.POLYGON_OFFSET_UNITS = 0x2A00; + /* POLYGON_OFFSET_FILL */ + this.POLYGON_OFFSET_FACTOR = 0x8038; + this.TEXTURE_BINDING_2D = 0x8069; + this.SAMPLE_BUFFERS = 0x80A8; + this.SAMPLES = 0x80A9; + this.SAMPLE_COVERAGE_VALUE = 0x80AA; + this.SAMPLE_COVERAGE_INVERT = 0x80AB; + + /* GetTextureParameter */ + /* TEXTURE_MAG_FILTER */ + /* TEXTURE_MIN_FILTER */ + /* TEXTURE_WRAP_S */ + /* TEXTURE_WRAP_T */ + + this.COMPRESSED_TEXTURE_FORMATS = 0x86A3; + + /* HintMode */ + this.DONT_CARE = 0x1100; + this.FASTEST = 0x1101; + this.NICEST = 0x1102; + + /* HintTarget */ + this.GENERATE_MIPMAP_HINT = 0x8192; + + /* DataType */ + this.BYTE = 0x1400; + this.UNSIGNED_BYTE = 0x1401; + this.SHORT = 0x1402; + this.UNSIGNED_SHORT = 0x1403; + this.INT = 0x1404; + this.UNSIGNED_INT = 0x1405; + this.FLOAT = 0x1406; + + /* PixelFormat */ + this.DEPTH_COMPONENT = 0x1902; + this.ALPHA = 0x1906; + this.RGB = 0x1907; + this.RGBA = 0x1908; + this.LUMINANCE = 0x1909; + this.LUMINANCE_ALPHA = 0x190A; + + /* PixelType */ + /* UNSIGNED_BYTE */ + this.UNSIGNED_SHORT_4_4_4_4 = 0x8033; + this.UNSIGNED_SHORT_5_5_5_1 = 0x8034; + this.UNSIGNED_SHORT_5_6_5 = 0x8363; + + /* Shaders */ + this.FRAGMENT_SHADER = 0x8B30; + this.VERTEX_SHADER = 0x8B31; + this.MAX_VERTEX_ATTRIBS = 0x8869; + this.MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB; + this.MAX_VARYING_VECTORS = 0x8DFC; + this.MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D; + this.MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; + this.MAX_TEXTURE_IMAGE_UNITS = 0x8872; + this.MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD; + this.SHADER_TYPE = 0x8B4F; + this.DELETE_STATUS = 0x8B80; + this.LINK_STATUS = 0x8B82; + this.VALIDATE_STATUS = 0x8B83; + this.ATTACHED_SHADERS = 0x8B85; + this.ACTIVE_UNIFORMS = 0x8B86; + this.ACTIVE_ATTRIBUTES = 0x8B89; + this.SHADING_LANGUAGE_VERSION = 0x8B8C; + this.CURRENT_PROGRAM = 0x8B8D; + + /* StencilFunction */ + this.NEVER = 0x0200; + this.LESS = 0x0201; + this.EQUAL = 0x0202; + this.LEQUAL = 0x0203; + this.GREATER = 0x0204; + this.NOTEQUAL = 0x0205; + this.GEQUAL = 0x0206; + this.ALWAYS = 0x0207; + + /* StencilOp */ + /* ZERO */ + this.KEEP = 0x1E00; + this.REPLACE = 0x1E01; + this.INCR = 0x1E02; + this.DECR = 0x1E03; + this.INVERT = 0x150A; + this.INCR_WRAP = 0x8507; + this.DECR_WRAP = 0x8508; + + /* StringName */ + this.VENDOR = 0x1F00; + this.RENDERER = 0x1F01; + this.VERSION = 0x1F02; + + /* TextureMagFilter */ + this.NEAREST = 0x2600; + this.LINEAR = 0x2601; + + /* TextureMinFilter */ + /* NEAREST */ + /* LINEAR */ + this.NEAREST_MIPMAP_NEAREST = 0x2700; + this.LINEAR_MIPMAP_NEAREST = 0x2701; + this.NEAREST_MIPMAP_LINEAR = 0x2702; + this.LINEAR_MIPMAP_LINEAR = 0x2703; + + /* TextureParameterName */ + this.TEXTURE_MAG_FILTER = 0x2800; + this.TEXTURE_MIN_FILTER = 0x2801; + this.TEXTURE_WRAP_S = 0x2802; + this.TEXTURE_WRAP_T = 0x2803; + + /* TextureTarget */ + this.TEXTURE_2D = 0x0DE1; + this.TEXTURE = 0x1702; + + this.TEXTURE_CUBE_MAP = 0x8513; + this.TEXTURE_BINDING_CUBE_MAP = 0x8514; + this.TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515; + this.TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516; + this.TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517; + this.TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; + this.TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; + this.TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; + this.MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C; + + /* TextureUnit */ + this.TEXTURE0 = 0x84C0; + this.TEXTURE1 = 0x84C1; + this.TEXTURE2 = 0x84C2; + this.TEXTURE3 = 0x84C3; + this.TEXTURE4 = 0x84C4; + this.TEXTURE5 = 0x84C5; + this.TEXTURE6 = 0x84C6; + this.TEXTURE7 = 0x84C7; + this.TEXTURE8 = 0x84C8; + this.TEXTURE9 = 0x84C9; + this.TEXTURE10 = 0x84CA; + this.TEXTURE11 = 0x84CB; + this.TEXTURE12 = 0x84CC; + this.TEXTURE13 = 0x84CD; + this.TEXTURE14 = 0x84CE; + this.TEXTURE15 = 0x84CF; + this.TEXTURE16 = 0x84D0; + this.TEXTURE17 = 0x84D1; + this.TEXTURE18 = 0x84D2; + this.TEXTURE19 = 0x84D3; + this.TEXTURE20 = 0x84D4; + this.TEXTURE21 = 0x84D5; + this.TEXTURE22 = 0x84D6; + this.TEXTURE23 = 0x84D7; + this.TEXTURE24 = 0x84D8; + this.TEXTURE25 = 0x84D9; + this.TEXTURE26 = 0x84DA; + this.TEXTURE27 = 0x84DB; + this.TEXTURE28 = 0x84DC; + this.TEXTURE29 = 0x84DD; + this.TEXTURE30 = 0x84DE; + this.TEXTURE31 = 0x84DF; + this.ACTIVE_TEXTURE = 0x84E0; + + /* TextureWrapMode */ + this.REPEAT = 0x2901; + this.CLAMP_TO_EDGE = 0x812F; + this.MIRRORED_REPEAT = 0x8370; + + /* Uniform Types */ + this.FLOAT_VEC2 = 0x8B50; + this.FLOAT_VEC3 = 0x8B51; + this.FLOAT_VEC4 = 0x8B52; + this.INT_VEC2 = 0x8B53; + this.INT_VEC3 = 0x8B54; + this.INT_VEC4 = 0x8B55; + this.BOOL = 0x8B56; + this.BOOL_VEC2 = 0x8B57; + this.BOOL_VEC3 = 0x8B58; + this.BOOL_VEC4 = 0x8B59; + this.FLOAT_MAT2 = 0x8B5A; + this.FLOAT_MAT3 = 0x8B5B; + this.FLOAT_MAT4 = 0x8B5C; + this.SAMPLER_2D = 0x8B5E; + this.SAMPLER_CUBE = 0x8B60; + + /* Vertex Arrays */ + this.VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622; + this.VERTEX_ATTRIB_ARRAY_SIZE = 0x8623; + this.VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624; + this.VERTEX_ATTRIB_ARRAY_TYPE = 0x8625; + this.VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A; + this.VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; + this.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; + + /* Read Format */ + this.IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A; + this.IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B; + + /* Shader Source */ + this.COMPILE_STATUS = 0x8B81; + + /* Shader Precision-Specified Types */ + this.LOW_FLOAT = 0x8DF0; + this.MEDIUM_FLOAT = 0x8DF1; + this.HIGH_FLOAT = 0x8DF2; + this.LOW_INT = 0x8DF3; + this.MEDIUM_INT = 0x8DF4; + this.HIGH_INT = 0x8DF5; + + /* Framebuffer Object. */ + this.FRAMEBUFFER = 0x8D40; + this.RENDERBUFFER = 0x8D41; + + this.RGBA4 = 0x8056; + this.RGB5_A1 = 0x8057; + this.RGB565 = 0x8D62; + this.DEPTH_COMPONENT16 = 0x81A5; + this.STENCIL_INDEX = 0x1901; + this.STENCIL_INDEX8 = 0x8D48; + this.DEPTH_STENCIL = 0x84F9; + + this.RENDERBUFFER_WIDTH = 0x8D42; + this.RENDERBUFFER_HEIGHT = 0x8D43; + this.RENDERBUFFER_INTERNAL_FORMAT = 0x8D44; + this.RENDERBUFFER_RED_SIZE = 0x8D50; + this.RENDERBUFFER_GREEN_SIZE = 0x8D51; + this.RENDERBUFFER_BLUE_SIZE = 0x8D52; + this.RENDERBUFFER_ALPHA_SIZE = 0x8D53; + this.RENDERBUFFER_DEPTH_SIZE = 0x8D54; + this.RENDERBUFFER_STENCIL_SIZE = 0x8D55; + + this.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0; + this.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1; + this.FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL |