diff options
-rw-r--r-- | src/library_gl.js | 157 |
1 files changed, 124 insertions, 33 deletions
diff --git a/src/library_gl.js b/src/library_gl.js index f6e0f974..826eb904 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -54,6 +54,40 @@ var LibraryGL = { 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 source; + }, + computeImageSize: function(width, height, sizePerPixel, alignment) { function roundedToNextMultipleOf(x, y) { return Math.floor((x + y - 1) / y) * y @@ -681,36 +715,7 @@ var LibraryGL = { }, 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; - } - // 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 - } - } + var source = GL.getSource(shader, count, string, length); Module.ctx.shaderSource(GL.shaders[shader], source); }, @@ -862,7 +867,7 @@ var LibraryGL = { // GL emulation: provides misc. functionality not present in OpenGL ES 2.0 or WebGL - $GLEmulation__deps: ['glCreateShader', 'glShaderSource', 'glCompileShader', 'glCreateProgram', 'glDeleteShader', 'glDeleteProgram', 'glAttachShader', 'glActiveTexture', 'glGetShaderiv', 'glGetProgramiv', 'glLinkProgram'], + $GLEmulation__deps: ['glCreateShader', 'glShaderSource', 'glCompileShader', 'glCreateProgram', 'glDeleteShader', 'glDeleteProgram', 'glAttachShader', 'glActiveTexture', 'glGetShaderiv', 'glGetProgramiv', 'glLinkProgram', 'glGetProgramInfoLog', 'glGetShaderInfoLog'], $GLEmulation__postset: 'GLEmulation.init();', $GLEmulation: { init: function() { @@ -871,9 +876,12 @@ var LibraryGL = { _glEnable = function(cap) { if (cap == 0x0DE1) return; // GL_TEXTURE_2D if (cap == 0x0B20) return; // GL_LINE_SMOOTH + if (cap == 0x0B60) return; // GL_FOG Module.ctx.enable(cap); }; _glDisable = function(cap) { + if (cap == 0x0DE1) return; // GL_TEXTURE_2D + if (cap == 0x0B20) return; // GL_LINE_SMOOTH if (cap == 0x0B60) return; // GL_FOG Module.ctx.disable(cap); }; @@ -884,6 +892,70 @@ var LibraryGL = { } glGetIntegerv(pname, params); }; + // Do some automatic rewriting to work around GLSL differences. Note that this must be done in + // tandem with the rest of the program, by itself it cannot suffice. + // Note that we need to remember shader types for this rewriting, saving sources makes it easier to debug. + GL.shaderTypes = {}; + GL.shaderSources = {}; + GL.shaderOriginalSources = {}; + var glCreateShader = _glCreateShader; + _glCreateShader = function(shaderType) { + var id = glCreateShader(shaderType); + GL.shaderTypes[id] = shaderType; + return id; + }; + var glShaderSource = _glShaderSource; + _glShaderSource = function(shader, count, string, length) { + var source = GL.getSource(shader, count, string, length); + GL.shaderOriginalSources[shader] = source; + if (GL.shaderTypes[shader] == Module.ctx.VERTEX_SHADER) { + if (source.indexOf('ftransform()') >= 0) { + // Replace ftransform() with explicit project/modelview transforms, and add position and matrix info. + source = 'attribute vec3 a_position; \n\ + uniform mat4 u_modelView; \n\ + uniform mat4 u_projection; \n' + + source.replace(/ftransform\(\)/g, 'u_projection * u_modelView * vec4(a_position, 1.0)') + .replace(/gl_Vertex/g, 'a_position') + .replace(/gl_ModelViewMatrixTranspose\[2\]/g, 'vec3(u_modelView[0][0], u_modelView[1][0], u_modelView[2][0])'); // XXX extremely inefficient + } + if (source.indexOf('gl_TexCoord[0]') >= 0) { + // XXX To handle both regular texture mapping and cube mapping, we use vec3 for tex coordinates. + source = 'attribute vec3 a_texCoord; \n\ + varying vec3 v_texCoord; \n' + + source.replace(/gl_TexCoord\[0\]/g, 'v_texCoord').replace(/gl_MultiTexCoord0/g, 'a_texCoord'); + } + if (source.indexOf('gl_Color') >= 0) { + source = 'attribute vec4 a_color; \n\ + varying vec4 v_color; \n' + + source.replace(/gl_Color/g, 'a_color').replace(/gl_FrontColor/g, 'v_color'); + } + if (source.indexOf('gl_FogFragCoord') >= 0) { + source = 'varying float v_fogCoord; \n' + + source.replace(/gl_FogFragCoord/g, 'v_fogCoord'); + } + } else { // Fragment shader + if (source.indexOf('gl_TexCoord[0]') >= 0) { + source = 'varying vec3 v_texCoord; \n' + source.replace(/gl_TexCoord\[0\]/g, 'v_texCoord'); + } + if (source.indexOf('gl_Color') >= 0) { + source = 'varying vec4 v_color; \n' + source.replace(/gl_Color/g, 'v_color'); + } + source = 'precision mediump float;\n' + source; + } + GL.shaderSources[shader] = source; + Module.ctx.shaderSource(GL.shaders[shader], source); + }; + var glCompileShader = _glCompileShader; + _glCompileShader = function(shader) { + Module.ctx.compileShader(GL.shaders[shader]); + if (!Module.ctx.getShaderParameter(GL.shaders[shader], Module.ctx.COMPILE_STATUS)) { + console.log('Failed to compile shader: ' + Module.ctx.getShaderInfoLog(GL.shaders[shader])); + console.log('Type: ' + GL.shaderTypes[shader]); + console.log('Original source: ' + GL.shaderOriginalSources[shader]); + console.log('Source: ' + GL.shaderSources[shader]); + throw 'Shader compilation halt'; + } + }; }, procReplacements: { @@ -909,13 +981,31 @@ var LibraryGL = { glGetObjectParameterivARB: function(id, type, result) { if (GL.programs[id]) { + if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB + {{{ makeSetValue('result', '0', 'Module.ctx.getProgramInfoLog(GL.programs[id]).length', 'i32') }}}; + return; + } _glGetProgramiv(id, type, result); } else if (GL.shaders[id]) { + if (type == 0x8B84) { // GL_OBJECT_INFO_LOG_LENGTH_ARB + {{{ makeSetValue('result', '0', 'Module.ctx.getShaderInfoLog(GL.shaders[id]).length', 'i32') }}}; + return; + } _glGetShaderiv(id, type, result); } else { console.log('WARNING: getObjectParameterivARB received invalid id: ' + id); } }, + + glGetInfoLogARB: function(id, maxLength, length, infoLog) { + if (GL.programs[id]) { + _glGetProgramInfoLog(id, maxLength, length, infoLog); + } else if (GL.shaders[id]) { + _glGetShaderInfoLog(id, maxLength, length, infoLog); + } else { + console.log('WARNING: getObjectParameterivARB received invalid id: ' + id); + } + } }, getProcAddress: function(name_) { @@ -923,7 +1013,7 @@ var LibraryGL = { var func = GLEmulation.procs[name_]; if (!func) { try { - func = eval('_' + name_); + func = eval('_' + name_); // XXX closure, need Module. and for them to be exported } catch(e) { console.log('WARNING: getProcAddress failed for ' + name_); func = function() { @@ -1070,6 +1160,7 @@ var LibraryGL = { initted: false, init: function() { Module.printErr('WARNING: using emscripten GL immediate mode emulation. This is very limited in what it supports'); + GL.immediate.initted = true; // Buffers for data this.tempData = new Float32Array(this.maxElements); @@ -1291,7 +1382,7 @@ var LibraryGL = { }, glPopMatrix: function() { - GL.immediate.matrix[currentMatrix] = GL.immediate.matrixStack[GL.immediate.currentMatrix].pop(); + GL.immediate.matrix[GL.immediate.currentMatrix] = GL.immediate.matrixStack[GL.immediate.currentMatrix].pop(); }, glLoadIdentity__deps: ['$GL', '$GLImmediateSetup'], |