//"use strict"; // FIXME: // * single-underscore deps need double underscore (and, just auto-add them all) var LibraryGL = { $GL: { hashtable: function(name) { if (!this._hashtables) { this._hashtables = {}; } if (!(name in this._hashtables)) { this._hashtables[name] = { table: {}, counter: 1, add: function(obj) { var id = this.counter++; this.table[id] = obj; return id; }, get: function(id) { if( id == 0 ) return null; #if ASSERTIONS assert(id < this.counter, "Invalid id " + id + " for the hashtable " + name); #endif return this.table[id]; }, id: function(obj) { for (var i = 1; i < this.counter; ++i) { if (obj == this.table[i]) { return i; } } return 0; }, remove: function(id) { if( id == 0 ) return; #if ASSERTIONS assert(id < this.counter, "Invalid id " + id + " for the hashtable " + name); #endif delete this.table[id]; }, lookup: function(v) { for (var i = 1; i < this.counter; i++) if (this.table[i] == v) return i; return 0; }, }; } return this._hashtables[name]; }, }, glGetString: function(name_) { switch(name_) { case 0x1F00 /* GL_VENDOR */: case 0x1F01 /* GL_RENDERER */: case 0x1F02 /* GL_VERSION */: return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL); case 0x1F03 /* GL_EXTENSIONS */: return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ')), 'i8', ALLOC_NORMAL); default: throw 'Failure: Invalid glGetString value: ' + name_; } }, glGetIntegerv__deps: ['$GL'], glGetIntegerv: function(name_, p) { var result = Module.ctx.getParameter(name_); switch (typeof(result)) { case "number": {{{ makeSetValue('p', '0', 'result', 'i32') }}}; break; case "boolean": {{{ makeSetValue('p', '0', 'result ? 1 : 0', 'i8') }}}; break; case "string": throw 'Native code calling glGetIntegerv(' + name_ + ') on a name which returns a string!'; case "object": if (result === null) { {{{ makeSetValue('p', '0', '0', 'i32') }}}; } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || result instanceof Array) { for (var i = 0; i < result.length; ++i) { {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}}; } } else if (result instanceof WebGLBuffer) { {{{ makeSetValue('p', '0', 'GL.hashtable("buffer").id(result)', 'i32') }}}; } else if (result instanceof WebGLProgram) { {{{ makeSetValue('p', '0', 'GL.hashtable("program").id(result)', 'i32') }}}; } else if (result instanceof WebGLFramebuffer) { {{{ makeSetValue('p', '0', 'GL.hashtable("framebuffer").id(result)', 'i32') }}}; } else if (result instanceof WebGLRenderbuffer) { {{{ makeSetValue('p', '0', 'gl.hashtable("renderbuffer").id(result)', 'i32') }}}; } else if (result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', 'gl.hashtable("texture").id(result)', 'i32') }}}; } else { throw 'Unknown object returned from WebGL getParameter'; } break; case "undefined": throw 'Native code calling glGetIntegerv(' + name_ + ') and it returns undefined'; default: throw 'Why did we hit the default case?'; } }, glGetFloatv__deps: ['$GL'], glGetFloatv: function(name_, p) { var result = Module.ctx.getParameter(name_); switch (typeof(result)) { case "number": {{{ makeSetValue('p', '0', 'result', 'float') }}}; break; case "boolean": {{{ makeSetValue('p', '0', 'result ? 1.0 : 0.0', 'float') }}}; break; case "string": {{{ makeSetValue('p', '0', '0', 'float') }}}; case "object": if (result === null) { throw 'Native code calling glGetFloatv(' + name_ + ') and it returns null'; } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || result instanceof Array) { for (var i = 0; i < result.length; ++i) { {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}}; } } else if (result instanceof WebGLBuffer) { {{{ makeSetValue('p', '0', 'GL.hashtable("buffer").id(result)', 'float') }}}; } else if (result instanceof WebGLProgram) { {{{ makeSetValue('p', '0', 'GL.hashtable("program").id(result)', 'float') }}}; } else if (result instanceof WebGLFramebuffer) { {{{ makeSetValue('p', '0', 'GL.hashtable("framebuffer").id(result)', 'float') }}}; } else if (result instanceof WebGLRenderbuffer) { {{{ makeSetValue('p', '0', 'gl.hashtable("renderbuffer").id(result)', 'float') }}}; } else if (result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', 'gl.hashtable("texture").id(result)', 'float') }}}; } else { throw 'Unknown object returned from WebGL getParameter'; } break; case "undefined": throw 'Native code calling glGetFloatv(' + name_ + ') and it returns undefined'; default: throw 'Why did we hit the default case?'; } }, glGetBooleanv__deps: ['$GL'], glGetBooleanv: function(name_, p) { var result = Module.ctx.getParameter(name_); switch (typeof(result)) { case "number": {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}}; break; case "boolean": {{{ makeSetValue('p', '0', 'result != 0', 'i8') }}}; break; case "string": throw 'Native code calling glGetBooleanv(' + name_ + ') on a name which returns a string!'; case "object": if (result === null) { {{{ makeSetValue('p', '0', '0', 'i8') }}}; } else if (result instanceof Float32Array || result instanceof Uint32Array || result instanceof Int32Array || result instanceof Array) { for (var i = 0; i < result.length; ++i) { {{{ makeSetValue('p', 'i', 'result[i] != 0', 'i8') }}}; } } else if (result instanceof WebGLBuffer || result instanceof WebGLProgram || result instanceof WebGLFramebuffer || result instanceof WebGLRenderbuffer || result instanceof WebGLTexture) { {{{ makeSetValue('p', '0', '1', 'i8') }}}; // non-zero ID is always 1! } else { throw 'Unknown object returned from WebGL getParameter'; } break; case "undefined": throw 'Unknown object returned from WebGL getParameter'; default: throw 'Why did we hit the default case?'; } }, glGenTextures__deps: ['$GL'], glGenTextures: function(n, textures) { for (var i = 0; i < n; i++) { var id = GL.hashtable("texture").add(Module.ctx.createTexture()); {{{ makeSetValue('textures', 'i*4', 'id', 'i32') }}}; } }, glDeleteTextures__deps: ['$GL'], glDeleteTextures: function(n, textures) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}}; Module.ctx.deleteTexture(GL.hashtable("texture").get(id)); GL.hashtable("texture").remove(id); } }, glCompressedTexImage2D: function(target, level, internalformat, width, height, border, imageSize, data) { if (data) { data = new Uint8Array(Array_copy(data, imageSize)); } else { data = null; } Module.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, data); }, glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { if (data) { data = new Uint8Array(Array_copy(data, imageSize)); } else { data = null; } Module.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, data); }, glTexImage2D: function(target, level, internalformat, width, height, border, format, type, pixels) { if (pixels) { var sizePerPixel; switch (type) { case 0x1401 /* GL_UNSIGNED_BYTE */: switch (format) { case 0x1906 /* GL_ALPHA */: case 0x1909 /* GL_LUMINANCE */: sizePerPixel = 1; break; case 0x1907 /* GL_RGB */: sizePerPixel = 3; break; case 0x1908 /* GL_RGBA */: sizePerPixel = 4; break; case 0x190A /* GL_LUMINANCE_ALPHA */: sizePerPixel = 2; break; default: throw 'Invalid format (' + format + ') passed to glTexImage2D'; } pixels = new Uint8Array(Array_copy(pixels, width*height*sizePerPixel)); break; case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */: case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */: case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: sizePerPixel = 2; pixels = new Uint16Array(new ArrayBuffer(Array_copy(pixels, width*height*sizePerPixel*2))); break; default: throw 'Invalid type (' + type + ') passed to glTexImage2D'; } } else { pixels = null; } Module.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, pixels); }, glTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, type, pixels) { if (pixels) { var sizePerPixel; switch (type) { case 0x1401 /* GL_UNSIGNED_BYTE */: switch (format) { case 0x1906 /* GL_ALPHA */: case 0x1909 /* GL_LUMINANCE */: sizePerPixel = 1; break; case 0x1907 /* GL_RGB */: sizePerPixel = 3; break; case 0x1908 /* GL_RGBA */: sizePerPixel = 4; break; case 0x190A /* GL_LUMINANCE_ALPHA */: sizePerPixel = 2; break; default: throw 'Invalid format (' + format + ') passed to glTexSubImage2D'; } pixels = new Uint8Array(Array_copy(pixels, (width-xoffset+1)*(height-yoffset+1)*sizePerPixel)); break; case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */: case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */: case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */: sizePerPixel = 2; pixels = new Uint16Array(new ArrayBuffer(Array_copy(pixels, (width-xoffset+1)*(height-yoffset+1)*sizePerPixel*2))); break; default: throw 'Invalid type (' + type + ') passed to glTexSubImage2D'; } } else { pixels = null; } Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); }, glBindTexture: function(target, texture) { Module.ctx.bindTexture(target, GL.hashtable("texture").get(texture)); }, glGetTexParameterfv: function(target, pname, params) { {{{ makeSetValue('params', '0', 'Module.getTexParameter(target, pname)', 'float') }}}; }, glGetTexParameteriv: function(target, pname, params) { {{{ makeSetValue('params', '0', 'Module.getTexParameter(target, pname)', 'i32') }}}; }, glIsTexture__deps: ['$GL'], glIsTexture: function(texture) { var fb = GL.hashtable("texture").get(texture); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isTexture(fb); }, glGenBuffers__deps: ['$GL'], glGenBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = GL.hashtable("buffer").add(Module.ctx.createBuffer()); {{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}}; } }, glDeleteBuffers__deps: ['$GL'], glDeleteBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; Module.ctx.deleteBuffer(GL.hashtable("buffer").get(id)); GL.hashtable("buffer").remove(id); } }, glBufferData: function(target, size, data, usage) { Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage); }, glBufferSubData: function(target, offset, size, data) { var floatArray = new Float32Array(TypedArray_copy(data, size, offset)); Module.ctx.bufferSubData(target, offset, floatArray); }, glIsBuffer__deps: ['$GL'], glIsBuffer: function(buffer) { var fb = GL.hashtable("buffer").get(buffer); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isBuffer(fb); }, glGenRenderbuffers__deps: ['$GL'], glGenRenderbuffers: function(n, renderbuffers) { for (var i = 0; i < n; i++) { var id = GL.hashtable("renderbuffer").add(Module.ctx.createRenderbuffer()); {{{ makeSetValue('renderbuffers', 'i*4', 'id', 'i32') }}}; } }, glDeleteRenderbuffers__deps: ['$GL'], glDeleteRenderbuffers: function(n, renderbuffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}}; Module.ctx.deleteRenderbuffer(GL.hashtable("renderbuffer").get(id)); GL.hashtable("renderbuffer").remove(id); } }, glBindRenderbuffer__deps: ['$GL'], glBindRenderbuffer: function(target, renderbuffer) { Module.ctx.bindRenderbuffer(target, GL.hashtable("renderbuffer").get(renderbuffer)); }, glGetRenderbufferParameteriv: function(target, pname, params) { {{{ makeSetValue('params', '0', 'Module.ctx.getRenderbufferParameter(target, pname)', 'i32') }}}; }, glIsRenderbuffer__deps: ['$GL'], glIsRenderbuffer: function(renderbuffer) { var fb = GL.hashtable("renderbuffer").get(renderbuffer); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isRenderbuffer(fb); }, glGetUniformLocation__deps: ['$GL'], glGetUniformLocation: function(program, name) { name = Pointer_stringify(name); var loc = Module.ctx.getUniformLocation(GL.hashtable("program").get(program), name); if (!loc) return -1; return GL.hashtable("uniform").add(loc); }, glUniform1f__deps: ['$GL'], glUniform1f: function(Location, v0) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform1f(Location, v0); }, glUniform2f__deps: ['$GL'], glUniform2f: function(Location, v0, v1) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform2f(Location, v0, v1); }, glUniform3f__deps: ['$GL'], glUniform3f: function(Location, v0, v1, v2) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform3f(Location, v0, v1, v2); }, glUniform4f__deps: ['$GL'], glUniform4f: function(Location, v0, v1, v2, v3) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform4f(Location, v0, v1, v2, v3); }, glUniform1i__deps: ['$GL'], glUniform1i: function(Location, v0) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform1i(Location, v0); }, glUniform2i__deps: ['$GL'], glUniform2i: function(Location, v0, v1) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform2i(Location, v0, v1); }, glUniform3i__deps: ['$GL'], glUniform3i: function(Location, v0, v1, v2) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform3i(Location, v0, v1, v2); }, glUniform4i__deps: ['$GL'], glUniform4i: function(Location, v0, v1, v2, v3) { Location = GL.hashtable("uniform").get(Location); Module.ctx.uniform4i(Location, v0, v1, v2, v3); }, glUniform1fv__deps: ['$GL'], glUniform1fv: function(Location, count, value) { Location = GL.hashtable("uniform").get(Location); value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniform1fv(Location, value); }, glUniform2fv__deps: ['$GL'], glUniform2fv: function(Location, count, value) { Location = GL.hashtable("uniform").get(Location); count *= 2; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniform2fv(Location, value); }, glUniform3fv__deps: ['$GL'], glUniform3fv: function(Location, count, value) { Location = GL.hashtable("uniform").get(Location); count *= 3; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniform3fv(Location, value); }, glUniform4fv__deps: ['$GL'], glUniform4fv: function(Location, count, value) { Location = GL.hashtable("uniform").get(Location); count *= 4; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniform4fv(Location, value); }, glUniformMatrix2fv__deps: ['$GL'], glUniformMatrix2fv: function(Location, count, transpose, value) { Location = GL.hashtable("uniform").get(Location); count *= 4; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniformMatrix2fv(Location, transpose, value); }, glUniformMatrix3fv__deps: ['$GL'], glUniformMatrix3fv: function(Location, count, transpose, value) { Location = GL.hashtable("uniform").get(Location); count *= 9; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniformMatrix3fv(Location, transpose, value); }, glUniformMatrix4fv__deps: ['$GL'], glUniformMatrix4fv: function(Location, count, transpose, value) { Location = GL.hashtable("uniform").get(Location); count *= 16; value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize Module.ctx.uniformMatrix4fv(Location, transpose, value); }, glBindBuffer__deps: ['$GL'], glBindBuffer: function(target, buffer) { Module.ctx.bindBuffer(target, GL.hashtable("buffer").get(buffer)); }, glVertexAttrib1fv: function(index, v) { v = new Float32Array(TypedArray_copy(v, 1*4)); // TODO: optimize Module.ctx.vertexAttrib1fv(index, v); }, glVertexAttrib2fv: function(index, v) { v = new Float32Array(TypedArray_copy(v, 2*4)); // TODO: optimize Module.ctx.vertexAttrib2fv(index, v); }, glVertexAttrib3fv: function(index, v) { v = new Float32Array(TypedArray_copy(v, 3*4)); // TODO: optimize Module.ctx.vertexAttrib3fv(index, v); }, glVertexAttrib4fv: function(index, v) { v = new Float32Array(TypedArray_copy(v, 4*4)); // TODO: optimize Module.ctx.vertexAttrib4fv(index, v); }, glGetAttribLocation__deps: ['$GL'], glGetAttribLocation: function(program, name) { program = GL.hashtable("program").get(program); name = Pointer_stringify(name); return Module.ctx.getAttribLocation(program, name); }, glCreateShader__deps: ['$GL'], glCreateShader: function(shaderType) { var shader = Module.ctx.createShader(shaderType); return GL.hashtable("shader").add(shader); }, glDeleteShader__deps: ['$GL'], glDeleteShader: function(shader) { Module.ctx.deleteShader(GL.hashtable("shader").get(shader)); }, glDetachShader__deps: ['$GL'], glDetachShader: function(program, shader) { Module.ctx.detachShader(GL.hashtable("program").get(program), GL.hashtable("shader").get(shader)); }, glGetAttachedShaders__deps: ['$GL'], glGetAttachedShaders: function(program, maxCount, count, shaders) { var result = Module.ctx.getAttachedShaders(GL.hashtable("program").get(program)); var len = result.length; if (len > maxCount) { len = maxCount; } {{{ makeSetValue('count', '0', 'len', 'i32') }}}; for (var i = 0; i < len; ++i) { {{{ makeSetValue('shaders', 'i*4', 'GL.hashtable("shader").get(result[i])', 'i32') }}}; } }, glShaderSource__deps: ['$GL'], glShaderSource: function(shader, count, string, length) { var source = ""; for (var i = 0; i < count; ++i) { var frag; if (length) { var len = {{{ makeGetValue('length', 'i*4', 'i32') }}}; if (len < 0) { frag = Pointer_stringify({{{ makeGetValue('string', 'i*4', 'i32') }}}); } else { frag = Pointer_stringify({{{ makeGetValue('string', 'i*4', 'i32') }}}, len); } } else { frag = Pointer_stringify({{{ makeGetValue('string', 'i*4', 'i32') }}}); } source += frag; } Module.ctx.shaderSource(GL.hashtable("shader").get(shader), source); }, glGetShaderSource__deps: ['$GL'], glGetShaderSource: function(shader, bufsize, length, source) { var result = Module.ctx.getShaderSource(GL.hashtable("shader").get(shader)); result.slice(0, bufsize - 1); writeStringToMemory(result, source); if (length) { {{{ makeSetValue('length', '0', 'result.length', 'i32') }}}; } }, glCompileShader__deps: ['$GL'], glCompileShader: function(shader) { Module.ctx.compileShader(GL.hashtable("shader").get(shader)); }, glGetShaderInfoLog__deps: ['$GL'], glGetShaderInfoLog: function(shader, maxLength, length, infoLog) { var log = Module.ctx.getShaderInfoLog(GL.hashtable("shader").get(shader)); // Work around a bug in Chromium which causes getShaderInfoLog to return null if (!log) { log = ""; } log = log.substr(0, maxLength - 1); writeStringToMemory(log, infoLog); if (length) { {{{ makeSetValue('length', '0', 'log.length', 'i32') }}} } }, glGetShaderiv__deps: ['$GL'], glGetShaderiv : function(shader, pname, p) { {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.hashtable("shader").get(shader), pname)', 'i32') }}}; }, glGetProgramiv__deps: ['$GL'], glGetProgramiv : function(program, pname, p) { {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.hashtable("program").get(program), pname)', 'i32') }}}; }, glIsShader__deps: ['$GL'], glIsShader: function(shader) { var fb = GL.hashtable("shader").get(shader); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isShader(fb); }, glCreateProgram__deps: ['$GL'], glCreateProgram: function() { return GL.hashtable("program").add(Module.ctx.createProgram()); }, glDeleteProgram__deps: ['$GL'], glDeleteProgram: function(program) { Module.ctx.deleteProgram(GL.hashtable("program").get(program)); }, glAttachShader__deps: ['$GL'], glAttachShader: function(program, shader) { Module.ctx.attachShader(GL.hashtable("program").get(program), GL.hashtable("shader").get(shader)); }, glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) { var result = Module.ctx.getShaderPrecisionFormat(shaderType, precisionType); {{{ makeSetValue('range', '0', 'result.rangeMin', 'i32') }}}; {{{ makeSetValue('range', '4', 'result.rangeMax', 'i32') }}}; {{{ makeSetValue('precision', '0', 'result.precision', 'i32') }}}; }, glLinkProgram__deps: ['$GL'], glLinkProgram: function(program) { Module.ctx.linkProgram(GL.hashtable("program").get(program)); }, glGetProgramInfoLog__deps: ['$GL'], glGetProgramInfoLog: function(program, maxLength, length, infoLog) { var log = Module.ctx.getProgramInfoLog(GL.hashtable("program").get(program)); // Work around a bug in Chromium which causes getProgramInfoLog to return null if (!log) { log = ""; } log = log.substr(0, maxLength - 1); writeStringToMemory(log, infoLog); if (length) { {{{ makeSetValue('length', '0', 'log.length', 'i32') }}} } }, glUseProgram__deps: ['$Gl'], glUseProgram: function(program) { Module.ctx.useProgram(GL.hashtable("program").get(program)); }, glValidateProgram__deps: ['$Gl'], glValidateProgram: function(program) { Module.ctx.validateProgram(GL.hashtable("program").get(program)); }, glIsProgram__deps: ['$GL'], glIsProgram: function(program) { var fb = GL.hashtable("program").get(program); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isProgram(fb); }, glBindAttribLocation__deps: ['$GL'], glBindAttribLocation: function(program, index, name) { name = Pointer_stringify(name); Module.ctx.bindAttribLocation(GL.hashtable("program").get(program), index, name); }, glBindFramebuffer__deps: ['$GL'], glBindFramebuffer: function(target, framebuffer) { Module.ctx.bindFramebuffer(target, GL.hashtable("framebuffer").get(framebuffer)); }, glGenFramebuffers__deps: ['$GL'], glGenFramebuffers: function(n, ids) { for (var i = 0; i < n; ++i) { var fb = GL.hashtable("framebuffer").add(Module.ctx.createFramebuffer()); {{{ makeSetValue('ids', 'i*4', 'fb', 'i32') }}}; } }, glDeleteFramebuffers__deps: ['$GL'], glDeleteFramebuffers: function(n, framebuffers) { for (var i = 0; i < n; ++i) { var fb = GL.hashtable("framebuffer").get({{{ makeGetValue('framebuffers', 'i*4', 'i32' ) }}}); Module.ctx.deleteFramebuffer(fb); } }, glFramebufferRenderbuffer__deps: ['$GL'], glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) { Module.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget, GL.hashtable("renderbuffer").get(renderbuffer)); }, glFramebufferTexture2D__deps: ['$GL'], glFramebufferTexture2D: function(target, attachment, textarget, texture, level) { Module.ctx.framebufferTexture2D(target, attachment, textarget, GL.hashtable("texture").get(texture), level); }, glGetFramebufferAttachmentParameteriv__deps: ['$GL'], glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) { var result = Module.ctx.getFramebufferAttachmentParameter(target, attachment, pname); {{{ makeSetValue('params', '0', 'params', 'i32') }}}; }, glIsFramebuffer__deps: ['$GL'], glIsFramebuffer: function(framebuffer) { var fb = GL.hashtable("framebuffer").get(framebuffer); if (typeof(fb) == 'undefined') { return false; } return Module.ctx.isFramebuffer(fb); }, }; // Simple pass-through functions [[0, 'shadeModel fogi fogfv getError finish flush'], [1, 'clearDepth depthFunc enable disable frontFace cullFace clear enableVertexAttribArray disableVertexAttribArray lineWidth clearStencil depthMask stencilMask stencilMaskSeparate checkFramebufferStatus generateMipmap activeTexture'], [2, 'pixelStorei'], [3, 'texParameteri texParameterf drawArrays vertexAttrib2f'], [4, 'viewport clearColor scissor vertexAttrib3f colorMask drawElements renderbufferStorage'], [5, 'vertexAttrib4f'], [6, 'vertexAttribPointer'], [8, 'copyTexImage2D copyTexSubImage2D']].forEach(function(data) { var num = data[0]; var names = data[1]; var args = range(num).map(function(i) { return 'x' + i }).join(', '); var stub = '(function(' + args + ') { ' + (num > 0 ? 'Module.ctx.NAME(' + args + ')' : '') + ' })'; names.split(' ').forEach(function(name_) { var cName = 'gl' + name_[0].toUpperCase() + name_.substr(1); assert(!(cName in LibraryGL), "Cannot reimplement the existing function " + cName); LibraryGL[cName] = eval(stub.replace('NAME', name_)); }); }); var LibraryGLUT = { $GLUT: { initTime: null, displayFunc: null, keyboardFunc: null, keyboardUpFunc: null, specialFunc: null, specialUpFunc: null, reshapeFunc: null, motionFunc: null, passiveMotionFunc: null, mouseFunc: null, lastX: 0, lastY: 0, buttons: 0, modifiers: 0, saveModifiers__deps: ['$GLUT'], saveModifiers: function(event) { GLUT.modifiers = 0; if (event['shiftKey']) GLUT.modifiers += 1; /* GLUT_ACTIVE_SHIFT */ if (event['ctrlKey']) GLUT.modifiers += 2; /* GLUT_ACTIVE_CTRL */ if (event['altKey']) GLUT.modifiers += 4; /* GLUT_ACTIVE_ALT */ }, onMousemove__deps: ['$GLUT'], onMousemove: function(event) { GLUT.lastX = event['clientX']; GLUT.lastY = event['clientY']; if (GLUT.buttons == 0 && GLUT.passiveMotionFunc) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.passiveMotionFunc](GLUT.lastX, GLUT.lastY); } else if (GLUT.buttons != 0 && GLUT.motionFunc) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.motionFunc](GLUT.lastX, GLUT.lastY); } }, getSpecialKey: function(keycode) { var key = null; switch (keycode) { case 0x70 /*DOM_VK_F1*/: key = 1 /* GLUT_KEY_F1 */; break; case 0x71 /*DOM_VK_F2*/: key = 2 /* GLUT_KEY_F2 */; break; case 0x72 /*DOM_VK_F3*/: key = 3 /* GLUT_KEY_F3 */; break; case 0x73 /*DOM_VK_F4*/: key = 4 /* GLUT_KEY_F4 */; break; case 0x74 /*DOM_VK_F5*/: key = 5 /* GLUT_KEY_F5 */; break; case 0x75 /*DOM_VK_F6*/: key = 6 /* GLUT_KEY_F6 */; break; case 0x76 /*DOM_VK_F7*/: key = 7 /* GLUT_KEY_F7 */; break; case 0x77 /*DOM_VK_F8*/: key = 8 /* GLUT_KEY_F8 */; break; case 0x78 /*DOM_VK_F9*/: key = 9 /* GLUT_KEY_F9 */; break; case 0x79 /*DOM_VK_F10*/: key = 10 /* GLUT_KEY_F10 */; break; case 0x7a /*DOM_VK_F11*/: key = 11 /* GLUT_KEY_F11 */; break; case 0x7b /*DOM_VK_F12*/: key = 12 /* GLUT_KEY_F12 */; break; case 0x25 /*DOM_VK_LEFT*/: key = 100 /* GLUT_KEY_LEFT */; break; case 0x26 /*DOM_VK_UP*/: key = 101 /* GLUT_KEY_UP */; break; case 0x27 /*DOM_VK_RIGHT*/: key = 102 /* GLUT_KEY_RIGHT */; break; case 0x28 /*DOM_VK_DOWN*/: key = 103 /* GLUT_KEY_DOWN */; break; case 0x21 /*DOM_VK_PAGE_UP*/: key = 104 /* GLUT_KEY_PAGE_UP */; break; case 0x22 /*DOM_VK_PAGE_DOWN*/: key = 105 /* GLUT_KEY_PAGE_DOWN */; break; case 0x24 /*DOM_VK_HOME*/: key = 106 /* GLUT_KEY_HOME */; break; case 0x23 /*DOM_VK_END*/: key = 107 /* GLUT_KEY_END */; break; case 0x2d /*DOM_VK_INSERT*/: key = 108 /* GLUT_KEY_INSERT */; break; }; return key; }, getASCIIKey: function(keycode) { // TODO apply modifiers, etc return keycode; }, onKeydown__deps: ['$GLUT'], onKeydown: function(event) { if (GLUT.specialFunc || GLUT.keyboardFunc) { var key = GLUT.getSpecialKey(event['keyCode']); if (key !== null) { if( GLUT.specialFunc ) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.specialFunc](key, GLUT.lastX, GLUT.lastY); } } else { key = GLUT.getASCIIKey(event['keyCode']); if( key !== null && GLUT.keyboardFunc ) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.keyboardFunc](event['keyCode'], GLUT.lastX, GLUT.lastY); } } } }, onKeyup__deps: ['$GLUT'], onKeyup: function(event) { if (GLUT.specialUpFunc || GLUT.keyboardUpFunc) { var key = GLUT.getSpecialKey(event['keyCode']); if (key !== null) { if(GLUT.specialUpFunc) { event.preventDefault (); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.specialUpFunc](key, GLUT.lastX, GLUT.lastY); } } else { key = GLUT.getASCIIKey(event['keyCode']); if( key !== null && GLUT.keyboardUpFunc ) { event.preventDefault (); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.keyboardUpFunc](event['keyCode'], GLUT.lastX, GLUT.lastY); } } } }, onMouseButtonDown__deps: ['$GLUT'], onMouseButtonDown: function(event){ GLUT.lastX = event['clientX']; GLUT.lastY = event['clientY']; GLUT.buttons |= (1 << event['button']); if(GLUT.mouseFunc){ event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 0/*GLUT_DOWN*/, GLUT.lastX, GLUT.lastY); } }, onMouseButtonUp__deps: ['$GLUT'], onMouseButtonUp: function(event){ GLUT.lastX = event['clientX']; GLUT.lastY = event['clientY']; GLUT.buttons &= ~(1 << event['button']); if(GLUT.mouseFunc) { event.preventDefault(); GLUT.saveModifiers(event); FUNCTION_TABLE[GLUT.mouseFunc](event['button'], 1/*GLUT_UP*/, GLUT.lastX, GLUT.lastY); } }, }, glutGetModifiers__deps: ['$GLUT'], glutGetModifiers: function() { return GLUT.modifiers; }, glutInit__deps: ['$GLUT'], glutInit: function(argcp, argv) { // Ignore arguments GLUT.initTime = Date.now(); window.addEventListener("keydown", GLUT.onKeydown, true); window.addEventListener("keyup", GLUT.onKeyup, true); window.addEventListener("mousemove", GLUT.onMousemove, true); window.addEventListener("mousedown", GLUT.onMouseButtonDown, true); window.addEventListener("mouseup", GLUT.onMouseButtonUp, true); }, glutInitWindowSize: function(width, height) { Module['canvas'].width = width; Module['canvas'].height = height; }, glutGet__deps: ['$GLUT'], glutGet: function(type) { switch (type) { case 700: /* GLUT_ELAPSED_TIME */ var now = Date.now(); return now - GLUT.initTime; default: throw "glutGet(" + type + ") not implemented yet"; } }, glutIdleFunc: function(func) { window.setTimeout(FUNCTION_TABLE[func], 0); }, glutTimerFunc: function(msec, func, value) { window.setTimeout(function() { FUNCTION_TABLE[func](value); }, msec); }, glutDisplayFunc__deps: ['$GLUT'], glutDisplayFunc: function(func) { GLUT.displayFunc = func; }, glutKeyboardFunc__deps: ['$GLUT'], glutKeyboardFunc: function(func) { GLUT.keyboardFunc = func; }, glutKeyboardUpFunc__deps: ['$GLUT'], glutKeyboardUpFunc: function(func) { GLUT.keyboardUpFunc = func; }, glutSpecialFunc__deps: ['$GLUT'], glutSpecialFunc: function(func) { GLUT.specialFunc = func; }, glutSpecialUpFunc__deps: ['$GLUT'], glutSpecialUpFunc: function(func) { GLUT.specialUpFunc = func; }, glutReshapeFunc__deps: ['$GLUT'], glutReshapeFunc: function(func) { GLUT.reshapeFunc = func; }, glutMotionFunc__deps: ['$GLUT'], glutMotionFunc: function(func) { GLUT.motionFunc = func; }, glutPassiveMotionFunc__deps: ['$GLUT'], glutPassiveMotionFunc: function(func) { GLUT.passiveMotionFunc = func; }, glutMouseFunc__deps: ['$GLUT'], glutMouseFunc: function(func) { GLUT.mouseFunc = func; }, glutCreateWindow: function(name) { #if USE_TYPED_ARRAYS try { var ctx = Module.canvas.getContext('experimental-webgl'); if (!ctx) throw 'Could not create canvas :('; #if GL_DEBUG var wrapper = {}; wrapper.objectMap = new WeakMap(); wrapper.objectCounter = 1; for (var prop in ctx) { (function(prop) { switch (typeof ctx[prop]) { case 'function': { wrapper[prop] = function() { var printArgs = Array.prototype.slice.call(arguments).map(function(arg) { if (wrapper.objectMap[arg]) return '<' + arg + '|' + wrapper.objectMap[arg] + '>'; if (arg.subarray) return '{' + arg + '|' + arg.length /*+ '|' + Array.prototype.slice.call(arg).toString().replace(/,/g, ', ')*/ + '}'; return arg; }); Module.printErr('[gl_f:' + prop + ':' + printArgs + ']'); var ret = ctx[prop].apply(ctx, arguments); var printRet = ret; if (typeof ret == 'object') { wrapper.objectMap[ret] = wrapper.objectCounter++; printRet = '<' + ret + '|' + wrapper.objectMap[ret] + '>'; } Module.printErr('[ gl:' + prop + ':return:' + printRet + ']'); return ret; } break; } case 'number': case 'string': { wrapper.__defineGetter__(prop, function() { //Module.printErr('[gl_g:' + prop + ':' + ctx[prop] + ']'); return ctx[prop]; }); wrapper.__defineSetter__(prop, function(value) { Module.printErr('[gl_s:' + prop + ':' + value + ']'); ctx[prop] = value; }); break; } } })(prop); } Module.ctx = wrapper; #else Module.ctx = ctx; #endif // Set the background of the canvas to black, because glut gives us a // window which has a black background by default. Module.canvas.style.backgroundColor = "black"; } catch (e) { Module.print('(canvas not available)'); } #else Module.print('(USE_TYPED_ARRAYS needs to be enabled for WebGL)'); #endif }, glutInitDisplayMode: function(mode) {}, glutSwapBuffers: function() {}, glutPostRedisplay__deps: ['$GLUT'], glutPostRedisplay: function() { if (GLUT.displayFunc) { var RAF = window['setTimeout']; if (window['requestAnimationFrame']) { RAF = window['requestAnimationFrame']; } else if (window['mozRequestAnimationFrame']) { RAF = window['mozRequestAnimationFrame']; } else if (window['webkitRequestAnimationFrame']) { RAF = window['webkitRequestAnimationFrame']; } else if (window['msRequestAnimationFrame']) { RAF = window['msRequestAnimationFrame']; } RAF.apply(window, [FUNCTION_TABLE[GLUT.displayFunc]]); } }, glutMainLoop__deps: ['$GLUT', 'exit', 'glutPostRedisplay'], glutMainLoop: function() { if (GLUT.reshapeFunc) { FUNCTION_TABLE[GLUT.reshapeFunc](Module['canvas'].width, Module['canvas'].height); } _glutPostRedisplay(); _exit(0); // GLUT mainloop should never return }, }; var LibraryXlib = { XOpenDisplay: function() { return 1; // We support 1 display, the canvas }, XCreateWindow: function(display, parent, x, y, width, height, border_width, depth, class_, visual, valuemask, attributes) { // All we can do is set the width and height Module['canvas'].width = width; Module['canvas'].height = height; return 2; }, XChangeWindowAttributes: function(){}, XSetWMHints: function(){}, XMapWindow: function(){}, XStoreName: function(){}, XInternAtom: function(display, name_, hmm) { return 0 }, XSendEvent: function(){}, XPending: function(display) { return 0 }, }; var LibraryEGL = { eglGetDisplay: function(x_display) { return 3 }, eglInitialize: function(display, majorVersion, minorVersion) { return 1 }, eglGetConfigs: function(display, hmm1, hmm2, numConfigs) { return 1 }, eglChooseConfig: function(display, attribList, config, hmm, numConfigs) { return 1 }, eglCreateWindowSurface: function(display, config, hWnd, hmm) { return 4 }, eglCreateContext__deps: ['glutCreateWindow', '$GL'], eglCreateContext: function(display, config, hmm, contextAttribs) { _glutCreateWindow(); return 1; }, eglMakeCurrent: function(display, surface, surface, context) { return 1 }, eglSwapBuffers: function() {}, }; mergeInto(LibraryManager.library, LibraryGL); mergeInto(LibraryManager.library, LibraryGLUT); mergeInto(LibraryManager.library, LibraryXlib); mergeInto(LibraryManager.library, LibraryEGL);