aboutsummaryrefslogtreecommitdiff
path: root/src/library_gl.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library_gl.js')
-rw-r--r--src/library_gl.js1662
1 files changed, 1342 insertions, 320 deletions
diff --git a/src/library_gl.js b/src/library_gl.js
index 1d5168fb..052226cf 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -1,49 +1,120 @@
-//"use strict";
-
-// XXX FIXME Hardcoded '4' in many places, here and in library_SDL, for RGBA
+/*
+ * GL support. See https://github.com/kripken/emscripten/wiki/OpenGL-support
+ * for current status.
+ */
var LibraryGL = {
$GL: {
- hashtable: function(name) {
- if (!this._hashtables) {
- this._hashtables = {};
+ counter: 1,
+ buffers: {},
+ programs: {},
+ framebuffers: {},
+ renderbuffers: {},
+ textures: {},
+ uniforms: {},
+ shaders: {},
+
+ packAlignment: 4, // default alignment is 4 bytes
+ unpackAlignment: 4, // default alignment is 4 bytes
+
+ // Linear lookup in one of the tables (buffers, programs, etc.). TODO: consider using a weakmap to make this faster, if it matters
+ scan: function(table, object) {
+ for (var item in table) {
+ if (table[item] == object) return item;
}
- 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];
- },
- 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];
+ return 0;
+ },
+
+ // Find a token in a shader source string
+ findToken: function(source, token) {
+ function isIdentChar(ch) {
+ if (ch >= 48 && ch <= 57) // 0-9
+ return true;
+ if (ch >= 65 && ch <= 90) // A-Z
+ return true;
+ if (ch >= 97 && ch <= 122) // a-z
+ return true;
+ return false;
+ }
+ var i = -1;
+ do {
+ i = source.indexOf(token, i + 1);
+ if (i < 0) {
+ break;
+ }
+ if (i > 0 && isIdentChar(source[i - 1])) {
+ continue;
+ }
+ i += token.length;
+ if (i < source.length - 1 && isIdentChar(source[i + 1])) {
+ continue;
+ }
+ return true;
+ } while (true);
+ return false;
+ },
+
+ getSource: 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;
+ }
+ // Let's see if we need to enable the standard derivatives extension
+ type = Module.ctx.getShaderParameter(GL.shaders[shader], 0x8B4F /* GL_SHADER_TYPE */);
+ if (type == 0x8B30 /* GL_FRAGMENT_SHADER */) {
+ if (GL.findToken(source, "dFdx") ||
+ GL.findToken(source, "dFdy") ||
+ GL.findToken(source, "fwidth")) {
+ source = "#extension GL_OES_standard_derivatives : enable\n" + source;
+ var extension = Module.ctx.getExtension("OES_standard_derivatives");
+#if GL_DEBUG
+ if (!extension) {
+ Module.printErr("Shader attempts to use the standard derivatives extension which is not available.");
+ }
+#endif
+ }
}
- return this._hashtables[name];
+ return source;
},
+
+ computeImageSize: function(width, height, sizePerPixel, alignment) {
+ function roundedToNextMultipleOf(x, y) {
+ return Math.floor((x + y - 1) / y) * y
+ }
+ var plainRowSize = width * sizePerPixel;
+ var alignedRowSize = roundedToNextMultipleOf(plainRowSize, alignment);
+ return (height <= 0) ? 0 :
+ ((height - 1) * alignedRowSize + plainRowSize);
+ }
+ },
+
+ glPixelStorei: function(pname, param) {
+ if (pname == 0x0D05 /* GL_PACK_ALIGNMENT */) {
+ GL.packAlignment = param;
+ } else if (pname == 0x0cf5 /* GL_UNPACK_ALIGNMENT */) {
+ GL.unpackAlignment = param;
+ }
+ Module.ctx.pixelStorei(pname, param);
},
glGetString: function(name_) {
switch(name_) {
- case Module.ctx.VENDOR:
- case Module.ctx.RENDERER:
- case Module.ctx.VERSION:
+ case 0x1F00 /* GL_VENDOR */:
+ case 0x1F01 /* GL_RENDERER */:
+ case 0x1F02 /* GL_VERSION */:
return allocate(intArrayFromString(Module.ctx.getParameter(name_)), 'i8', ALLOC_NORMAL);
- case 0x1F03: // Extensions
+ case 0x1F03 /* GL_EXTENSIONS */:
return allocate(intArrayFromString(Module.ctx.getSupportedExtensions().join(' ')), 'i8', ALLOC_NORMAL);
default:
throw 'Failure: Invalid glGetString value: ' + name_;
@@ -51,289 +122,674 @@ var LibraryGL = {
},
glGetIntegerv: function(name_, p) {
- {{{ makeSetValue('p', '0', 'Module.ctx.getParameter(name_)', 'i32') }}};
+ 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.scan(GL.buffers, result)', 'i32') }}};
+ } else if (result instanceof WebGLProgram) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.programs, result)', 'i32') }}};
+ } else if (result instanceof WebGLFramebuffer) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.framebuffers, result)', 'i32') }}};
+ } else if (result instanceof WebGLRenderbuffer) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.renderbuffers, result)', 'i32') }}};
+ } else if (result instanceof WebGLTexture) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.textures, 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: 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.scan(GL.buffers, result)', 'float') }}};
+ } else if (result instanceof WebGLProgram) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.programs, result)', 'float') }}};
+ } else if (result instanceof WebGLFramebuffer) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.framebuffers, result)', 'float') }}};
+ } else if (result instanceof WebGLRenderbuffer) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.renderbuffers, result)', 'float') }}};
+ } else if (result instanceof WebGLTexture) {
+ {{{ makeSetValue('p', '0', 'GL.scan(GL.textures, 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: 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', 'id', 'i32') }}};
+ var id = GL.counter++;
+ GL.textures[id] = Module.ctx.createTexture();
+ {{{ makeSetValue('textures', 'i*4', 'id', 'i32') }}};
}
},
glDeleteTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
- var id = {{{ makeGetValue('textures', 'i', 'i32') }}};
- Module.ctx.deleteTexture(GL.hashtable("texture").get(id));
- GL.hashtable("texture").remove(id);
+ var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}};
+ Module.ctx.deleteTexture(GL.textures[id]);
+ GL.textures[id] = null;
+ }
+ },
+
+ glCompressedTexImage2D: function(target, level, internalformat, width, height, border, imageSize, data) {
+ if (data) {
+ data = {{{ makeHEAPView('U8', 'data', '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 = {{{ makeHEAPView('U8', 'data', '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) {
- pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize
+ 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';
+ }
+ 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;
+ break;
+ default:
+ throw 'Invalid type (' + type + ') passed to glTexImage2D';
+ }
+ var bytes = GL.computeImageSize(width, height, sizePerPixel, GL.unpackAlignment);
+ pixels = {{{ makeHEAPView('U8', 'pixels', 'pixels+bytes') }}};
+ } 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) {
- pixels = new Uint8Array(Array_copy(pixels, pixels + width*height*4)); // TODO: optimize
+ 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';
+ }
+ 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;
+ break;
+ default:
+ throw 'Invalid type (' + type + ') passed to glTexSubImage2D';
+ }
+ var bytes = GL.computeImageSize(width, height, sizePerPixel, GL.unpackAlignment);
+ pixels = {{{ makeHEAPView('U8', 'pixels', 'pixels+bytes') }}};
+ } else {
+ pixels = null;
}
Module.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
},
+ glReadPixels: function(x, y, width, height, format, type, pixels) {
+ Module.ctx.readPixels(x, y, width, height, format, type, HEAPU8.subarray(pixels));
+ },
+
glBindTexture: function(target, texture) {
- Module.ctx.bindTexture(target, GL.hashtable("texture").get(texture));
+ Module.ctx.bindTexture(target, GL.textures[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: function(texture) {
+ var fb = GL.textures[texture];
+ if (typeof(fb) == 'undefined') {
+ return 0;
+ }
+ 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', 'id', 'i32') }}};
+ var id = GL.counter++;
+ GL.buffers[id] = Module.ctx.createBuffer();
+ {{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}};
}
},
glDeleteBuffers: function(n, buffers) {
for (var i = 0; i < n; i++) {
- var id = {{{ makeGetValue('buffers', 'i', 'i32') }}};
- Module.ctx.deleteBuffer(GL.hashtable("buffer").get(id));
- GL.hashtable("buffer").remove(id);
+ var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
+ Module.ctx.deleteBuffer(GL.buffers[id]);
+ GL.buffers[id] = null;
}
},
+ glGetBufferParameteriv: function(target, value, data) {
+ {{{ makeSetValue('data', '0', 'Module.ctx.getBufferParameter(target, value)', 'i32') }}};
+ },
+
glBufferData: function(target, size, data, usage) {
- var floatArray = new Float32Array(TypedArray_copy(data, size));
- Module.ctx.bufferData(target, floatArray, usage);
+ Module.ctx.bufferData(target, HEAPU8.subarray(data, data+size), usage);
+ },
+
+ glBufferSubData: function(target, offset, size, data) {
+ var floatArray = {{{ makeHEAPView('F32', 'data', 'data+size') }}};
+ Module.ctx.bufferSubData(target, offset, floatArray);
+ },
+
+ glIsBuffer: function(buffer) {
+ var fb = GL.buffers[buffer];
+ if (typeof(fb) == 'undefined') {
+ return 0;
+ }
+ return Module.ctx.isBuffer(fb);
+ },
+
+ glGenRenderbuffers: function(n, renderbuffers) {
+ for (var i = 0; i < n; i++) {
+ var id = GL.counter++;
+ GL.renderbuffers[id] = Module.ctx.createRenderbuffer();
+ {{{ makeSetValue('renderbuffers', 'i*4', 'id', 'i32') }}};
+ }
+ },
+
+ glDeleteRenderbuffers: function(n, renderbuffers) {
+ for (var i = 0; i < n; i++) {
+ var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}};
+ Module.ctx.deleteRenderbuffer(GL.renderbuffers[id]);
+ GL.renderbuffers[id];
+ }
+ },
+
+ glBindRenderbuffer: function(target, renderbuffer) {
+ Module.ctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]);
+ },
+
+ glGetRenderbufferParameteriv: function(target, pname, params) {
+ {{{ makeSetValue('params', '0', 'Module.ctx.getRenderbufferParameter(target, pname)', 'i32') }}};
+ },
+
+ glIsRenderbuffer: function(renderbuffer) {
+ var fb = GL.renderbuffers[renderbuffer];
+ if (typeof(fb) == 'undefined') {
+ return 0;
+ }
+ return Module.ctx.isRenderbuffer(fb);
+ },
+
+ glGetUniformfv: function(program, location, params) {
+ var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
+ if (typeof data == 'number') {
+ {{{ makeSetValue('params', '0', 'data', 'float') }}};
+ } else {
+ for (var i = 0; i < data.length; i++) {
+ {{{ makeSetValue('params', 'i', 'data[i]', 'float') }}};
+ }
+ }
+ },
+
+ glGetUniformiv: function(program, location, params) {
+ var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
+ if (typeof data == 'number' || typeof data == 'boolean') {
+ {{{ makeSetValue('params', '0', 'data', 'i32') }}};
+ } else {
+ for (var i = 0; i < data.length; i++) {
+ {{{ makeSetValue('params', 'i', 'data[i]', 'i32') }}};
+ }
+ }
},
- glBindAttribLocation_deps: ['$GL'],
glGetUniformLocation: function(program, name) {
name = Pointer_stringify(name);
- return GL.hashtable("uniform").add(
- Module.ctx.getUniformLocation(GL.hashtable("program").get(program), name));
+ var loc = Module.ctx.getUniformLocation(GL.programs[program], name);
+ if (!loc) return -1;
+ var id = GL.counter++;
+ GL.uniforms[id] = loc;
+ return id;
+ },
+
+ glGetVertexAttribfv: function(index, pname, params) {
+ var data = Module.ctx.getVertexAttrib(index, pname);
+ if (typeof data == 'number') {
+ {{{ makeSetValue('params', '0', 'data', 'float') }}};
+ } else {
+ for (var i = 0; i < data.length; i++) {
+ {{{ makeSetValue('params', 'i', 'data[i]', 'float') }}};
+ }
+ }
+ },
+
+ glGetVertexAttribiv: function(index, pname, params) {
+ var data = Module.ctx.getVertexAttrib(index, pname);
+ if (typeof data == 'number' || typeof data == 'boolean') {
+ {{{ makeSetValue('params', '0', 'data', 'i32') }}};
+ } else {
+ for (var i = 0; i < data.length; i++) {
+ {{{ makeSetValue('params', 'i', 'data[i]', 'i32') }}};
+ }
+ }
+ },
+
+ glGetVertexAttribPointerv: function(index, pname, pointer) {
+ {{{ makeSetValue('pointer', '0', 'Module.ctx.getVertexAttribOffset(index, pname)', 'i32') }}};
+ },
+
+ glGetActiveUniform: function(program, index, bufSize, length, size, type, name) {
+ program = GL.programs[program];
+ var info = Module.ctx.getActiveUniform(program, index);
+
+ var infoname = info.name.slice(0, bufsize - 1);
+ writeStringToMemory(infoname, name);
+
+ if (length) {
+ {{{ makeSetValue('length', '0', 'infoname.length', 'i32') }}};
+ }
+ if (size) {
+ {{{ makeSetValue('size', '0', 'info.size', 'i32') }}};
+ }
+ if (type) {
+ {{{ makeSetValue('type', '0', 'info.type', 'i32') }}};
+ }
},
- glUniform1f: function(Location, v0) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform1f(Location, v0);
+ glUniform1f: function(location, v0) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform1f(location, v0);
},
- glUniform2f: function(Location, v0, v1) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform2f(Location, v0, v1);
+ glUniform2f: function(location, v0, v1) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform2f(location, v0, v1);
},
- glUniform3f: function(Location, v0, v1, v2) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform3f(Location, v0, v1, v2);
+ glUniform3f: function(location, v0, v1, v2) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform3f(location, v0, v1, v2);
},
- glUniform4f: function(Location, v0, v1, v2, v3) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform4f(Location, v0, v1, v2, v3);
+ glUniform4f: function(location, v0, v1, v2, v3) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform4f(location, v0, v1, v2, v3);
},
- glUniform1i: function(Location, v0) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform1i(Location, v0);
+ glUniform1i: function(location, v0) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform1i(location, v0);
},
- glUniform2i: function(Location, v0, v1) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform2i(Location, v0, v1);
+ glUniform2i: function(location, v0, v1) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform2i(location, v0, v1);
},
- glUniform3i: function(Location, v0, v1, v2) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform3i(Location, v0, v1, v2);
+ glUniform3i: function(location, v0, v1, v2) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform3i(location, v0, v1, v2);
},
- glUniform4i: function(Location, v0, v1, v2, v3) {
- Location = GL.hashtable("uniform").get(Location);
- Module.ctx.uniform4i(Location, v0, v1, v2, v3);
+ glUniform4i: function(location, v0, v1, v2, v3) {
+ location = GL.uniforms[location];
+ Module.ctx.uniform4i(location, v0, v1, v2, v3);
},
- 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);
+ glUniform1iv: function(location, count, value) {
+ location = GL.uniforms[location];
+ value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform1iv(location, value);
},
- glUniform2fv: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform2iv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 2;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform2fv(Location, value);
+ value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform2iv(location, value);
},
- glUniform3fv: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform3iv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 3;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform3fv(Location, value);
+ value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform3iv(location, value);
},
- glUniform4fv: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform4iv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 4;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform4fv(Location, value);
+ value = {{{ makeHEAPView('32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform4iv(location, value);
},
- glUniform1fi: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
- value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform1fi(Location, value);
+ glUniform1fv: function(location, count, value) {
+ location = GL.uniforms[location];
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform1fv(location, value);
},
- glUniform2fi: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform2fv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 2;
- value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform2fi(Location, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform2fv(location, value);
},
- glUniform3fi: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform3fv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 3;
- value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform3fi(Location, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform3fv(location, value);
},
- glUniform4fi: function(Location, count, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniform4fv: function(location, count, value) {
+ location = GL.uniforms[location];
count *= 4;
- value = new Uint32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniform4fi(Location, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniform4fv(location, value);
},
- glUniformMatrix2fv: function(Location, count, transpose, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniformMatrix2fv: function(location, count, transpose, value) {
+ location = GL.uniforms[location];
count *= 4;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniformMatrix2fv(Location, transpose, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniformMatrix2fv(location, transpose, value);
},
- glUniformMatrix3fv: function(Location, count, transpose, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniformMatrix3fv: function(location, count, transpose, value) {
+ location = GL.uniforms[location];
count *= 9;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniformMatrix3fv(Location, transpose, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniformMatrix3fv(location, transpose, value);
},
- glUniformMatrix4fv: function(Location, count, transpose, value) {
- Location = GL.hashtable("uniform").get(Location);
+ glUniformMatrix4fv: function(location, count, transpose, value) {
+ location = GL.uniforms[location];
count *= 16;
- value = new Float32Array(TypedArray_copy(value, count*4)); // TODO: optimize
- Module.ctx.uniformMatrix4fv(Location, transpose, value);
+ value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}};
+ Module.ctx.uniformMatrix4fv(location, transpose, value);
},
glBindBuffer: function(target, buffer) {
- Module.ctx.bindBuffer(target, GL.hashtable("buffer").get(buffer));
+ Module.ctx.bindBuffer(target, GL.buffers[buffer]);
},
glVertexAttrib1fv: function(index, v) {
- v = new Float32Array(TypedArray_copy(v, 1*4)); // TODO: optimize
+ v = {{{ makeHEAPView('F32', 'v', 'v+1*4') }}};
Module.ctx.vertexAttrib1fv(index, v);
},
glVertexAttrib2fv: function(index, v) {
- v = new Float32Array(TypedArray_copy(v, 2*4)); // TODO: optimize
+ v = {{{ makeHEAPView('F32', 'v', 'v+2*4') }}};
Module.ctx.vertexAttrib2fv(index, v);
},
glVertexAttrib3fv: function(index, v) {
- v = new Float32Array(TypedArray_copy(v, 3*4)); // TODO: optimize
+ v = {{{ makeHEAPView('F32', 'v', 'v+3*4') }}};
Module.ctx.vertexAttrib3fv(index, v);
},
glVertexAttrib4fv: function(index, v) {
- v = new Float32Array(TypedArray_copy(v, 4*4)); // TODO: optimize
+ v = {{{ makeHEAPView('F32', 'v', 'v+4*4') }}};
Module.ctx.vertexAttrib4fv(index, v);
},
glGetAttribLocation: function(program, name) {
- program = GL.hashtable("program").get(program);
+ program = GL.programs[program];
name = Pointer_stringify(name);
- Module.ctx.getAttribLocation(program, name);
+ return Module.ctx.getAttribLocation(program, name);
+ },
+
+ glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) {
+ program = GL.programs[program];
+ var info = Module.ctx.getActiveAttrib(program, index);
+
+ var infoname = info.name.slice(0, bufsize - 1);
+ writeStringToMemory(infoname, name);
+
+ if (length) {
+ {{{ makeSetValue('length', '0', 'infoname.length', 'i32') }}};
+ }
+ if (size) {
+ {{{ makeSetValue('size', '0', 'info.size', 'i32') }}};
+ }
+ if (type) {
+ {{{ makeSetValue('type', '0', 'info.type', 'i32') }}};
+ }
},
- glCreateShader_deps: ['$GL'],
glCreateShader: function(shaderType) {
- var shader = Module.ctx.createShader(shaderType);
- return GL.hashtable("shader").add(shader);
+ var id = GL.counter++;
+ GL.shaders[id] = Module.ctx.createShader(shaderType);
+ return id;
+ },
+
+ glDeleteShader: function(shader) {
+ Module.ctx.deleteShader(GL.shaders[shader]);
+ GL.shaders[shader] = null;
+ },
+
+ glDetachShader: function(program, shader) {
+ Module.ctx.detachShader(GL.programs[program],
+ GL.shaders[shader]);
+ },
+
+ glGetAttachedShaders: function(program, maxCount, count, shaders) {
+ var result = Module.ctx.getAttachedShaders(GL.programs[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.shaders[result[i]]', 'i32') }}};
+ }
},
- glShaderSource_deps: ['$GL'],
glShaderSource: function(shader, count, string, length) {
- var source = "";
- for (var i = 0; i < count; ++i) {
- var frag = string[i];
- if (length) {
- var len = {{{ makeGetValue('length', 'i', 'i32') }}};
- if (len < 0) {
- frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}});
- } else {
- frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}}, len);
- }
- } else {
- frag = Pointer_stringify({{{ makeGetValue('string', 'i', 'i32') }}});
- }
- if (source.length) {
- source += "\n";
- }
- source += frag;
+ var source = GL.getSource(shader, count, string, length);
+ Module.ctx.shaderSource(GL.shaders[shader], source);
+ },
+
+ glGetShaderSource: function(shader, bufsize, length, source) {
+ var result = Module.ctx.getShaderSource(GL.shaders[shader]);
+ result.slice(0, bufsize - 1);
+ writeStringToMemory(result, source);
+ if (length) {
+ {{{ makeSetValue('length', '0', 'result.length', 'i32') }}};
}
- Module.ctx.shaderSource(GL.hashtable("shader").get(shader), source);
},
- glCompileShader_deps: ['$GL'],
glCompileShader: function(shader) {
- Module.ctx.compileShader(GL.hashtable("shader").get(shader));
+ Module.ctx.compileShader(GL.shaders[shader]);
},
- glGetShaderInfoLog_deps: ['$GL'],
glGetShaderInfoLog: function(shader, maxLength, length, infoLog) {
- var log = Module.ctx.getShaderInfoLog(GL.hashtable("shader").get(shader));
- log.slice(0, maxLength - 1);
+ var log = Module.ctx.getShaderInfoLog(GL.shaders[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', 'i', 'log.length', 'i32') }}}
+ {{{ 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') }}};
+
+ glGetShaderiv : function(shader, pname, p) {
+ {{{ makeSetValue('p', '0', 'Module.ctx.getShaderParameter(GL.shaders[shader], pname)', 'i32') }}};
+ },
+
+ glGetProgramiv : function(program, pname, p) {
+ {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}};
},
- glGetProgramiv_deps: ['$GL'],
- glGetProgramiv : function(program, pname, p) {
- {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.hashtable("program").get(program),pname)', 'i32') }}};
+ glIsShader: function(shader) {
+ var fb = GL.shaders[shader];
+ if (typeof(fb) == 'undefined') {
+ return 0;
+ }
+ return Module.ctx.isShader(fb);
},
- glCreateProgram_deps: ['$GL'],
glCreateProgram: function() {
- return GL.hashtable("program").add(Module.ctx.createProgram());
+ var id = GL.counter++;
+ GL.programs[id] = Module.ctx.createProgram();
+ return id;
+ },
+
+ glDeleteProgram: function(program) {
+ Module.ctx.deleteProgram(GL.programs[program]);
+ GL.programs[program] = null;
},
- glAttachShader_deps: ['$GL'],
glAttachShader: function(program, shader) {
- Module.ctx.attachShader(GL.hashtable("program").get(program),
- GL.hashtable("shader").get(shader));
+ Module.ctx.attachShader(GL.programs[program],
+ GL.shaders[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));
+ Module.ctx.linkProgram(GL.programs[program]);
},
- glGetProgramInfoLog_deps: ['$GL'],
glGetProgramInfoLog: function(program, maxLength, length, infoLog) {
- var log = Module.ctx.getProgramInfoLog(GL.hashtable("program").get(program));
+ var log = Module.ctx.getProgramInfoLog(GL.programs[program]);
// Work around a bug in Chromium which causes getProgramInfoLog to return null
if (!log) {
log = "";
@@ -341,224 +797,790 @@ var LibraryGL = {
log = log.substr(0, maxLength - 1);
writeStringToMemory(log, infoLog);
if (length) {
- {{{ makeSetValue('length', 'i', 'log.length', 'i32') }}}
+ {{{ makeSetValue('length', '0', 'log.length', 'i32') }}}
}
},
- glUseProgram_deps: ['$Gl'],
glUseProgram: function(program) {
- Module.ctx.useProgram(GL.hashtable("program").get(program));
+ Module.ctx.useProgram(GL.programs[program]);
+ },
+
+ glValidateProgram: function(program) {
+ Module.ctx.validateProgram(GL.programs[program]);
+ },
+
+ glIsProgram: function(program) {
+ var fb = GL.programs[program];
+ if (typeof(fb) == 'undefined') {
+ return 0;
+ }
+ 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);
+ Module.ctx.bindAttribLocation(GL.programs[program], index, name);
},
- glBindFramebuffer_deps: ['$GL'],
glBindFramebuffer: function(target, framebuffer) {
- Module.ctx.bindFramebuffer(target, GL.hashtable("framebuffer").get(