// 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 = 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': { that.prefetchedParameters = msg.parameters; that.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; } 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('getExtension', 1, name); return true; // TODO: return an object here }; this.getSupportedExtensions = function() { return this.prefetchedExtensions; }; this.enable = function(cap) { commandBuffer.push('enable', 1, cap); }; this.disable = function(cap) { commandBuffer.push('disable', 1, cap); }; this.clear = function(mask) { commandBuffer.push('clear', 1, mask); }; this.clearColor = function(r, g, b, a) { commandBuffer.push('clearColor', 4, r, g, b, a); }; this.createShader = function(type) { var id = nextId++; commandBuffer.push('createShader', -2, type, id); return { id: id, what: 'shader', type: type }; }; this.shaderSource = function(shader, source) { shader.source = source; commandBuffer.push('shaderSource', 2, shader.id, source); }; this.compileShader = function(shader) { commandBuffer.push('compileShader', 1, shader.id); }; this.getShaderInfoLog = function(shader) { return ''; // optimistic assumption of success; no proxying }; this.createProgram = function() { var id = nextId++; commandBuffer.push('createProgram', -1, id); return new WebGLProgram(id); }; this.attachShader = function(program, shader) { program.shaders.push(shader); commandBuffer.push('attachShader', 2, program.id, shader.id); }; this.bindAttribLocation = function(program, index, name) { program.attributes[name] = index; program.attributeVec[index] = name; commandBuffer.push('bindAttribLocation', 3, program.id, index, name); }; this.getAttribLocation = function(program, name) { // manually bound attribs are cached locally if (name in program.attributes) return program.attributes[name]; // if not manually bound, bind it to the next index so we update the client var index = program.attributeVec.length; this.bindAttribLocation(program, index, name); return index; }; this.linkProgram = function(program) { commandBuffer.push('linkProgram', 1, program.id); // parse shader sources program.uniforms = {}; program.uniformVec = []; program.shaders.forEach(function(shader) { var newUniforms = shader.source.match(/uniform\s+\w+\s+[\w,\s\[\]]+;/g); if (!newUniforms) return; newUniforms.forEach(function(uniform) { var m = /uniform\s+\w+\s+([\w,\s\[\]]+);/.exec(uniform); assert(m); m[1].split(',').map(function(name) { return name.replace(/\s/g, '') }).filter(function(name) { return !!name }).forEach(function(name) { var size = 1; var open = name.indexOf('['); if (open >= 0) { var close = name.indexOf(']'); size = parseInt(name.substring(open+1, close)); name = name.substr(0, open); } if (!program.uniforms[name]) { program.uniforms[name] = { what: 'uniform', name: name, size: size }; program.uniformVec.push(name); } }); }); }); }; this.getProgramParameter = function(program, name) { switch (name) { case this.ACTIVE_UNIFORMS: return program.uniformVec.length; case this.LINK_STATUS: { // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow commandBuffer.push('getProgramParameter', program.id, name); return true; } default: throw 'bad getProgramParameter ' + revname(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 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); } var id = nextId++; commandBuffer.push('getUniformLocation', -3, program.id, name, 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('useProgram', 1, program.id); }; this.uniform1i = function(location, data) { commandBuffer.push('uniform1i', 2, location.id, data); }; this.uniform1f = function(location, data) { commandBuffer.push('uniform1f', 2, location.id, data); }; this.uniform4fv = function(location, data) { commandBuffer.push('uniform4fv', 2, location.id, new Float32Array(data)); }; this.uniformMatrix4fv = function(location, transpose, data) { commandBuffer.push('uniformMatrix4fv', 3, location.id, transpose, new Float32Array(data)); }; this.createBuffer = function() { var id = nextId++; commandBuffer.push('createBuffer', -1, id); return new WebGLBuffer(id); }; this.bindBuffer = function(target, buffer) { commandBuffer.push('bindBuffer', 2, target, buffer ? buffer.id : 0); }; this.bufferData = function(target, something, usage) { if (typeof something !== 'number') something = new Uint8Array(something); commandBuffer.push('bufferData', 3, target, something, usage); }; this.viewport = function(x, y, w, h) { commandBuffer.push('viewport', 4, x, y, w, h); }; this.vertexAttribPointer = function(index, size, type, normalized, stride, offset) { commandBuffer.push('vertexAttribPointer', 6, index, size, type, normalized, stride, offset); }; this.enableVertexAttribArray = function(index) { commandBuffer.push('enableVertexAttribArray', 1, index); }; this.disableVertexAttribArray = function(index) { commandBuffer.push('disableVertexAttribArray', 1, index); }; this.drawArrays = function(mode, first, count) { commandBuffer.push('drawArrays', 3, mode, first, count); }; this.getError = function() { // optimisticaly return success; client will abort on an actual error. we assume an error-free async workflow commandBuffer.push('getError', 0); return this.NO_ERROR; }; this.createTexture = function() { var id = nextId++; commandBuffer.push('createTexture', -1, id); return new WebGLTexture(id); }; this.bindTexture = function(target, texture) { switch (target) { case that.TEXTURE_2D: { bindings.texture2D = texture; break; } } commandBuffer.push('bindTexture', 2, target, texture ? texture.id : 0); }; this.texParameteri = function(target, pname, param) { commandBuffer.push('texParameteri', 3, target, pname, param); }; this.texImage2D = function(target, level, internalformat, width, height, border, format, type, pixels) { assert(pixels); // we do not support the overloads that have fewer params commandBuffer.push('texImage2D', 9, target, level, internalformat, width, height, border, format, type, new pixels.constructor(pixels)); }; this.activeTexture = function(texture) { commandBuffer.push('activeTexture', 1, 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('getShaderParameter', shader.id, pname); return true; } default: throw 'unsupported getShaderParameter ' + pname; } }; // Setup var dropped = 0; var postMainLoop = Module['postMainLoop']; Module['postMainLoop'] = function() { if (postMainLoop) postMainLoop(); // frame complete, send the command buffer if (Math.abs(frameId - clientFrameId) <= 3) { // only send if not throttling postMessage({ target: 'gl', op: 'render', commandBuffer: commandBuffer }); } else { //dropped++; //if (dropped % 1000 === 0) dump('dropped: ' + [dropped, frameId, Math.round(100*dropped/frameId) + '%\n']); } commandBuffer = []; }; }