aboutsummaryrefslogtreecommitdiff
path: root/src/webGLWorker.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/webGLWorker.js')
-rw-r--r--src/webGLWorker.js910
1 files changed, 910 insertions, 0 deletions
diff --git a/src/webGLWorker.js b/src/webGLWorker.js
new file mode 100644
index 00000000..90a1bed9
--- /dev/null
+++ b/src/webGLWorker.js
@@ -0,0 +1,910 @@
+// 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;
+ this.binding = 0;
+}
+
+function WebGLWorker() {
+ //=======
+ // State
+ //=======
+
+ var commandBuffer = [];
+
+ var nextId = 1; // valid ids are > 0
+
+ var bindings = {
+ texture2D: null,
+ arrayBuffer: null,
+ elementArrayBuffer: null,
+ program: 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 = 0x8CD2;
+ this.FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3;
+
+ this.COLOR_ATTACHMENT0 = 0x8CE0;
+ this.DEPTH_ATTACHMENT = 0x8D00;
+ this.STENCIL_ATTACHMENT = 0x8D20;
+ this.DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+ this.NONE = 0;
+
+ this.FRAMEBUFFER_COMPLETE = 0x8CD5;
+ this.FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+ this.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+ this.FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+ this.FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+ this.FRAMEBUFFER_BINDING = 0x8CA6;
+ this.RENDERBUFFER_BINDING = 0x8CA7;
+ this.MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+ this.INVALID_FRAMEBUFFER_OPERATION = 0x0506;
+
+ /* WebGL-specific enums */
+ this.UNPACK_FLIP_Y_WEBGL = 0x9240;
+ this.UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+ this.CONTEXT_LOST_WEBGL = 0x9242;
+ this.UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+ this.BROWSER_DEFAULT_WEBGL = 0x9244;
+
+ //==========
+ // Functions
+ //==========
+
+ var that = this;
+
+ // Helpers
+
+ this.onmessage = function(msg) {
+ //dump('worker GL got ' + JSON.stringify(msg) + '\n');
+ switch(msg.op) {
+ case 'setPrefetched': {
+ WebGLWorker.prototype.prefetchedParameters = msg.parameters;
+ WebGLWorker.prototype.prefetchedExtensions = msg.extensions;
+ break;
+ }
+ default: throw 'weird gl onmessage ' + JSON.stringify(msg);
+ }
+ };
+
+ function revname(name) {
+ for (var x in that) if (that[x] === name) return x;
+ return null;
+ }
+
+ // GL
+
+ this.getParameter = function(name) {
+ assert(name);
+ if (name in this.prefetchedParameters) return this.prefetchedParameters[name];
+ switch (name) {
+ case this.TEXTURE_BINDING_2D: {
+ return bindings.texture2D;
+ }
+ case this.ARRAY_BUFFER_BINDING: {
+ return bindings.arrayBuffer;
+ }
+ case this.ELEMENT_ARRAY_BUFFER_BINDING: {
+ return bindings.elementArrayBuffer;
+ }
+ case this.CURRENT_PROGRAM: {
+ return bindings.program;
+ }
+ default: throw 'TODO: get parameter ' + name + ' : ' + revname(name);
+ }
+ };
+ this.getExtension = function(name) {
+ var i = this.prefetchedExtensions.indexOf(name);
+ if (i < 0) return null;
+ commandBuffer.push(1, name);
+ return true; // TODO: return an object here
+ };
+ this.getSupportedExtensions = function() {
+ return this.prefetchedExtensions;
+ };
+ this.enable = function(cap) {
+ commandBuffer.push(2, cap);
+ };
+ this.disable = function(cap) {
+ commandBuffer.push(3, cap);
+ };
+ this.clear = function(mask) {
+ commandBuffer.push(4, mask);
+ };
+ this.clearColor = function(r, g, b, a) {
+ commandBuffer.push(5, r, g, b, a);
+ };
+ this.createShader = function(type) {
+ var id = nextId++;
+ commandBuffer.push(6, type, id);
+ return { id: id, what: 'shader', type: type };
+ };
+ this.deleteShader = function(shader) {
+ if (!shader) return;
+ commandBuffer.push(7, shader.id);
+ };
+ this.shaderSource = function(shader, source) {
+ shader.source = source;
+ commandBuffer.push(8, shader.id, source);
+ };
+ this.compileShader = function(shader) {
+ commandBuffer.push(9, shader.id);
+ };
+ this.getShaderInfoLog = function(shader) {
+ return ''; // optimistic assumption of success; no proxying
+ };
+ this.createProgram = function() {
+ var id = nextId++;
+ commandBuffer.push(10, id);
+ return new WebGLProgram(id);
+ };
+ this.deleteProgram = function(program) {
+ if (!program) return;
+ commandBuffer.push(11, program.id);
+ };
+ this.attachShader = function(program, shader) {
+ program.shaders.push(shader);
+ commandBuffer.push(12, program.id, shader.id);
+ };
+ this.bindAttribLocation = function(program, index, name) {
+ program.attributes[name] = { what: 'attribute', name: name, size: -1, location: index }; // fill in size later
+ program.attributeVec[index] = name;
+ commandBuffer.push(13, program.id, index, name);
+ };
+ this.getAttribLocation = function(program, name) {
+ // all existing attribs are cached locally
+ if (name in program.attributes) return program.attributes[name].location;
+ return -1;
+ };
+ this.linkProgram = function(program) {
+ // parse shader sources
+ function parseElementType(shader, type, obj, vec) {
+ var source = shader.source;
+ source = source.replace(/\n/g, '|\n'); // barrier between lines, to make regexing easier
+ var newItems = source.match(new RegExp(type + '\\s+\\w+\\s+[\\w,\\s\[\\]]+;', 'g'));
+ if (!newItems) return;
+ newItems.forEach(function(item) {
+ var m = new RegExp(type + '\\s+\\w+\\s+([\\w,\\s\[\\]]+);').exec(item);
+ assert(m);
+ m[1].split(',').map(function(name) { name = name.trim(); return name.search(/\s/) >= 0 ? '' : name }).filter(function(name) { return !!name }).forEach(function(name) {
+ var size = 1;
+ var open = name.indexOf('[');
+ var fullname = name;
+ if (open >= 0) {
+ var close = name.indexOf(']');
+ size = parseInt(name.substring(open+1, close));
+ name = name.substr(0, open);
+ fullname = name + '[0]';
+ }
+ if (!obj[name]) {
+ obj[name] = { what: type, name: fullname, size: size, location: -1 };
+ if (vec) vec.push(name);
+ }
+ });
+ });
+ }
+
+ program.uniforms = {};
+ program.uniformVec = [];
+
+ var existingAttributes = {};
+
+ program.shaders.forEach(function(shader) {
+ parseElementType(shader, 'uniform', program.uniforms, program.uniformVec);
+ parseElementType(shader, 'attribute', existingAttributes, null);
+ });
+
+ // bind not-yet bound attributes
+ for (var attr in existingAttributes) {
+ if (!(attr in program.attributes)) {
+ var index = program.attributeVec.length;
+ this.bindAttribLocation(program, index, attr);
+ }
+ program.attributes[attr].size = existingAttributes[attr].size;
+ }
+
+ commandBuffer.push(14, program.id);
+ };
+ this.getProgramParameter = function(program, name) {
+ switch (name) {
+ case this.ACTIVE_UNIFORMS: return program.uniformVec.length;
+ case this.ACTIVE_ATTRIBUTES: return program.attributeVec.length;
+ case this.LINK_STATUS: {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(15, program.id, name);
+ return true;
+ }
+ default: throw 'bad getProgramParameter ' + revname(name);
+ }
+ };
+ this.getActiveAttrib = function(program, index) {
+ var name = program.attributeVec[index];
+ if (!name) return null;
+ return program.attributes[name];
+ };
+ this.getActiveUniform = function(program, index) {
+ var name = program.uniformVec[index];
+ if (!name) return null;
+ return program.uniforms[name];
+ };
+ this.getUniformLocation = function(program, name) {
+ var fullname = name;
+ var index = -1;
+ var open = name.indexOf('[');
+ if (open >= 0) {
+ var close = name.indexOf(']');
+ index = parseInt(name.substring(open+1, close));
+ name = name.substr(0, open);
+ }
+ if (!(name in program.uniforms)) return null;
+ var id = nextId++;
+ commandBuffer.push(16, program.id, fullname, id);
+ return { what: 'location', uniform: program.uniforms[name], id: id, index: index };
+ };
+ this.getProgramInfoLog = function(shader) {
+ return ''; // optimistic assumption of success; no proxying
+ };
+ this.useProgram = function(program) {
+ commandBuffer.push(17, program ? program.id : 0);
+ bindings.program = program;
+ };
+ this.uniform1i = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(18, location.id, data);
+ };
+ this.uniform1f = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(19, location.id, data);
+ };
+ this.uniform3fv = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(20, location.id, new Float32Array(data));
+ };
+ this.uniform4fv = function(location, data) {
+ if (!location) return;
+ commandBuffer.push(21, location.id, new Float32Array(data));
+ };
+ this.uniformMatrix4fv = function(location, transpose, data) {
+ if (!location) return;
+ commandBuffer.push(22, location.id, transpose, new Float32Array(data));
+ };
+ this.vertexAttrib4fv = function(index, values) {
+ commandBuffer.push(23, index, new Float32Array(values));
+ };
+ this.createBuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(24, id);
+ return new WebGLBuffer(id);
+ };
+ this.deleteBuffer = function(buffer) {
+ if (!buffer) return;
+ commandBuffer.push(25, buffer.id);
+ };
+ this.bindBuffer = function(target, buffer) {
+ commandBuffer.push(26, target, buffer ? buffer.id : 0);
+ switch (target) {
+ case this.ARRAY_BUFFER_BINDING: {
+ bindings.arrayBuffer = buffer;
+ break;
+ }
+ case this.ELEMENT_ARRAY_BUFFER_BINDING: {
+ bindings.elementArrayBuffer = buffer;
+ break;
+ }
+ }
+ };
+ this.bufferData = function(target, something, usage) {
+ if (typeof something !== 'number') something = new something.constructor(something);
+ commandBuffer.push(27, target, something, usage);
+ };
+ this.bufferSubData = function(target, offset, something) {
+ if (typeof something !== 'number') something = new something.constructor(something);
+ commandBuffer.push(28, target, offset, something);
+ };
+ this.viewport = function(x, y, w, h) {
+ commandBuffer.push(29, x, y, w, h);
+ };
+ this.vertexAttribPointer = function(index, size, type, normalized, stride, offset) {
+ commandBuffer.push(30, index, size, type, normalized, stride, offset);
+ };
+ this.enableVertexAttribArray = function(index) {
+ commandBuffer.push(31, index);
+ };
+ this.disableVertexAttribArray = function(index) {
+ commandBuffer.push(32, index);
+ };
+ this.drawArrays = function(mode, first, count) {
+ commandBuffer.push(33, mode, first, count);
+ };
+ this.drawElements = function(mode, count, type, offset) {
+ commandBuffer.push(34, mode, count, type, offset);
+ };
+ this.getError = function() {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(35);
+ return this.NO_ERROR;
+ };
+ this.createTexture = function() {
+ var id = nextId++;
+ commandBuffer.push(36, id);
+ return new WebGLTexture(id);
+ };
+ this.deleteTexture = function(texture) {
+ if (!texture) return;
+ commandBuffer.push(37, texture.id);
+ texture.id = 0;
+ };
+ this.isTexture = function(texture) {
+ return texture && texture.what === 'texture' && texture.id > 0 && texture.binding;
+ };
+ this.bindTexture = function(target, texture) {
+ switch (target) {
+ case that.TEXTURE_2D: {
+ bindings.texture2D = texture;
+ break;
+ }
+ }
+ texture.binding = target;
+ commandBuffer.push(38, target, texture ? texture.id : 0);
+ };
+ this.texParameteri = function(target, pname, param) {
+ commandBuffer.push(39, target, pname, param);
+ };
+ this.texImage2D = function(target, level, internalformat, width, height, border, format, type, pixels) {
+ assert(pixels || pixels === null); // we do not support the overloads that have fewer params
+ commandBuffer.push(40, target, level, internalformat, width, height, border, format, type, pixels ? new pixels.constructor(pixels) : pixels);
+ };
+ this.compressedTexImage2D = function(target, level, internalformat, width, height, border, pixels) {
+ commandBuffer.push(41, target, level, internalformat, width, height, border, new pixels.constructor(pixels));
+ };
+ this.activeTexture = function(texture) {
+ commandBuffer.push(42, texture);
+ };
+ this.getShaderParameter = function(shader, pname) {
+ switch (pname) {
+ case this.SHADER_TYPE: return shader.type;
+ case this.COMPILE_STATUS: {
+ // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow
+ commandBuffer.push(43, shader.id, pname);
+ return true;
+ }
+ default: throw 'unsupported getShaderParameter ' + pname;
+ }
+ };
+ this.clearDepth = function(depth) {
+ commandBuffer.push(44, depth);
+ };
+ this.depthFunc = function(depth) {
+ commandBuffer.push(45, depth);
+ };
+ this.frontFace = function(depth) {
+ commandBuffer.push(46, depth);
+ };
+ this.cullFace = function(depth) {
+ commandBuffer.push(47, depth);
+ };
+ this.readPixels = function(depth) {
+ abort('readPixels is impossible, we are async GL');
+ };
+ this.pixelStorei = function(pname, param) {
+ commandBuffer.push(48, pname, param);
+ };
+ this.depthMask = function(flag) {
+ commandBuffer.push(49, flag);
+ };
+ this.depthRange = function(near, far) {
+ commandBuffer.push(50, near, far);
+ };
+ this.blendFunc = function(sfactor, dfactor) {
+ commandBuffer.push(51, sfactor, dfactor);
+ };
+ this.scissor = function(x, y, width, height) {
+ commandBuffer.push(52, x, y, width, height);
+ };
+ this.colorMask = function(red, green, blue, alpha) {
+ commandBuffer.push(53, red, green, blue, alpha);
+ };
+ this.lineWidth = function(width) {
+ commandBuffer.push(54, width);
+ };
+ this.createFramebuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(55, id);
+ return new WebGLFramebuffer(id);
+ };
+ this.deleteFramebuffer = function(framebuffer) {
+ if (!framebuffer) return;
+ commandBuffer.push(56, framebuffer.id);
+ };
+ this.bindFramebuffer = function(target, framebuffer) {
+ commandBuffer.push(57, target, framebuffer ? framebuffer.id : 0);
+ };
+ this.framebufferTexture2D = function(target, attachment, textarget, texture, level) {
+ commandBuffer.push(58, target, attachment, textarget, texture ? texture.id : 0, level);
+ };
+ this.checkFramebufferStatus = function(target) {
+ return this.FRAMEBUFFER_COMPLETE; // XXX totally wrong
+ };
+ this.createRenderbuffer = function() {
+ var id = nextId++;
+ commandBuffer.push(59, id);
+ return new WebGLRenderbuffer(id);
+ };
+ this.deleteRenderbuffer = function(renderbuffer) {
+ if (!renderbuffer) return;
+ commandBuffer.push(60, renderbuffer.id);
+ };
+ this.bindRenderbuffer = function(target, renderbuffer) {
+ commandBuffer.push(61, target, renderbuffer ? renderbuffer.id : 0);
+ };
+ this.renderbufferStorage = function(target, internalformat, width, height) {
+ commandBuffer.push(62, target, internalformat, width, height);
+ };
+ this.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) {
+ commandBuffer.push(63, target, attachment, renderbuffertarget, renderbuffer ? renderbuffer.id : 0);
+ };
+ //this.debugPrint = function(text) { // useful to interleave debug output properly with client GL commands
+ // commandBuffer.push(64, text);
+ //};
+
+ // Setup
+ var dropped = 0;
+ var average = 0;
+ var last = 0;
+ var meanDiff = 0;
+ var preMainLoop = Module['preMainLoop'];
+ Module['preMainLoop'] = function() {
+ /*
+ var now = Date.now();
+ if (last > 0) {
+ var diff = now - last;
+ meanDiff = 0.95*meanDiff + 0.05*diff;
+ if (clientFrameId % 10 === 0) dump('server fps ' + (1000/meanDiff) + ' (ignoring client throttling)\n');
+ }
+ last = now;
+ */
+ if (preMainLoop) {
+ var ret = preMainLoop();
+ if (ret === false) return ret;
+ }
+ // if too many frames in queue, skip a main loop iter
+ if (Math.abs(frameId - clientFrameId) >= 3) {
+ //dropped++;
+ //if (dropped % 10 === 0) dump('dropped: ' + [dropped, frameId, Math.round(100*dropped/(frameId + dropped)) + '%\n']);
+ return false;
+ }
+ };
+ var postMainLoop = Module['postMainLoop'];
+ Module['postMainLoop'] = function() {
+ if (postMainLoop) postMainLoop();
+ if (commandBuffer.length > 0) {
+ //average = (average + commandBuffer.length)/2;
+ //dump('buffer size: ' + Math.round(average) + '\n');
+ postMessage({ target: 'gl', op: 'render', commandBuffer: commandBuffer });
+ commandBuffer = [];
+ }
+ };
+}
+
+// share prefetched data among all instances
+
+WebGLWorker.prototype.prefetchedParameters = {};
+WebGLWorker.prototype.prefetchedExtensions = {};
+