aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jsifier.js1
-rw-r--r--src/library_browser.js36
-rw-r--r--src/library_gl.js14
-rw-r--r--src/library_glut.js7
-rw-r--r--src/library_sdl.js15
-rw-r--r--src/proxyClient.js27
-rw-r--r--src/proxyWorker.js87
-rw-r--r--src/webGLClient.js108
-rw-r--r--src/webGLWorker.js721
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