1 /*************************************** 2 * Copyright 2011, 2012 GlobWeb contributors. 3 * 4 * This file is part of GlobWeb. 5 * 6 * GlobWeb is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * GlobWeb is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GlobWeb. If not, see <http://www.gnu.org/licenses/>. 18 ***************************************/ 19 20 define(function() { 21 22 /**************************************************************************************************************/ 23 24 /** @constructor 25 Program constructor 26 */ 27 var Program = function(renderContext) 28 { 29 this.renderContext = renderContext; 30 this.glProgram = null; 31 this.attributes = {}; 32 this.uniforms = {}; 33 this.numActiveAttribArray = 0; 34 } 35 36 /**************************************************************************************************************/ 37 38 /** 39 Creates a shader of the given type from the given source string 40 */ 41 Program.prototype.createShader = function(type, source) 42 { 43 var gl = this.renderContext.gl; 44 var shader = gl.createShader(type); 45 gl.shaderSource(shader, source); 46 gl.compileShader(shader); 47 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) 48 { 49 console.log("Shader compilation error: " + gl.getShaderInfoLog(shader)); 50 console.log(source); 51 gl.deleteShader(shader); 52 return null; 53 } 54 55 return shader; 56 } 57 58 /**************************************************************************************************************/ 59 60 /** 61 Create the program from source shaders 62 */ 63 Program.prototype.createFromSource = function(vertexSource, fragmentSource) 64 { 65 var gl = this.renderContext.gl; 66 67 // Create the gl shaders from the source 68 var vertexShader = this.createShader(gl.VERTEX_SHADER, vertexSource); 69 var fragmentShader = this.createShader(gl.FRAGMENT_SHADER, fragmentSource); 70 if (vertexShader == null || fragmentShader == null) 71 { 72 return false; 73 } 74 75 // Create the program and attach the shaderss 76 this.glProgram = gl.createProgram(); 77 gl.attachShader(this.glProgram, vertexShader); 78 gl.attachShader(this.glProgram, fragmentShader); 79 80 // Link and test the program is ok 81 gl.linkProgram(this.glProgram); 82 if (!gl.getProgramParameter(this.glProgram, gl.LINK_STATUS)) 83 { 84 console.log("Program link error: " + gl.getProgramInfoLog(this.glProgram)); 85 gl.deleteShader(vertexShader); 86 gl.deleteShader(fragmentShader); 87 gl.deleteProgram(this.glProgram); 88 this.glProgram = null; 89 return false; 90 } 91 92 // Get vertex attributes used in the program, stored them in an attributes object 93 var attributeCount = gl.getProgramParameter(this.glProgram, gl.ACTIVE_ATTRIBUTES); 94 this.numActiveAttribArray = 0; 95 for (var i = 0; i < attributeCount; ++i) 96 { 97 var attribute = gl.getActiveAttrib(this.glProgram, i); 98 var loc = gl.getAttribLocation(this.glProgram,attribute.name); 99 this.attributes[attribute.name] = loc; 100 101 if ( loc + 1 > this.numActiveAttribArray ) 102 { 103 this.numActiveAttribArray = loc + 1; 104 } 105 } 106 107 // Get uniforms used in the program, stored them in an uniforms object 108 var uniformCount = gl.getProgramParameter(this.glProgram, gl.ACTIVE_UNIFORMS); 109 for (var i = 0; i < uniformCount; ++i) 110 { 111 var uniform = gl.getActiveUniform(this.glProgram, i); 112 this.uniforms[uniform.name] = gl.getUniformLocation(this.glProgram,uniform.name); 113 } 114 115 return true; 116 } 117 118 /**************************************************************************************************************/ 119 120 /* 121 Load from file (must be located on the server) 122 */ 123 Program.prototype.loadFromFile = function(vertexFile, fragmentFile) 124 { 125 var xhr = new XMLHttpRequest; 126 xhr.open("get", this.renderContext.shadersPath + vertexFile, false); 127 xhr.send(null); 128 var vertexSource = xhr.responseText; 129 xhr.open("get", this.renderContext.shadersPath + fragmentFile, false); 130 xhr.send(null); 131 var fragmentSource = xhr.responseText; 132 133 return this.createFromSource(vertexSource, fragmentSource); 134 } 135 136 /**************************************************************************************************************/ 137 138 /* 139 Apply the programs 140 */ 141 Program.prototype.apply = function() 142 { 143 var rc = this.renderContext; 144 var gl = rc.gl; 145 146 // Bind program 147 gl.useProgram(this.glProgram); 148 149 for ( var i = rc.numActiveAttribArray; 150 i < this.numActiveAttribArray; i++ ) 151 { 152 gl.enableVertexAttribArray(i); 153 } 154 for ( var i = this.numActiveAttribArray; 155 i < rc.numActiveAttribArray; i++ ) 156 { 157 gl.disableVertexAttribArray(i); 158 } 159 rc.numActiveAttribArray = this.numActiveAttribArray; 160 } 161 162 /**************************************************************************************************************/ 163 164 /* 165 Load shader using Http request 166 */ 167 // Program.prototype.loadShader = function (shader, type, callback) 168 // { 169 // function onreadystatechange() { 170 // var xhr = this; 171 // if (xhr.readyState == 4) { 172 // shader = gl.createShader(type); 173 // gl.shaderSource(shader, xhr.responseText); 174 // gl.compileShader(shader); 175 // if (! gl.getShaderParameter(shader, gl.COMPILE_STATUS)) 176 // throw gl.getShaderInfoLog(shader) 177 // ; 178 // !--length && typeof callback == "function" && callback(shader); 179 // } 180 // } 181 182 // var asynchronous = !!callback; 183 // xhr = new XMLHttpRequest; 184 // xhr.open("get", shader, asynchronous); 185 // if (asynchronous) 186 // { 187 // xhr.onreadystatechange = onreadystatechange; 188 // } 189 // xhr.send(null); 190 // onreadystatechange.call(xhr); 191 192 // return shader; 193 // } 194 195 /**************************************************************************************************************/ 196 197 198 /* 199 Get the shader using defined in HTML 200 */ 201 // Program.prototype.getShader = function(id) 202 // { 203 // var shaderScript = document.getElementById(id); 204 // if (!shaderScript) { 205 // return null; 206 // } 207 208 // var str = ""; 209 // var k = shaderScript.firstChild; 210 // while (k) { 211 // if (k.nodeType == 3) { 212 // str += k.textContent; 213 // } 214 // k = k.nextSibling; 215 // } 216 217 // var shader; 218 // if (shaderScript.type == "x-shader/x-fragment") { 219 // shader = RenderContext.gl.createShader(RenderContext.gl.FRAGMENT_SHADER); 220 // } else if (shaderScript.type == "x-shader/x-vertex") { 221 // shader = RenderContext.gl.createShader(RenderContext.gl.VERTEX_SHADER); 222 // } else { 223 // return null; 224 // } 225 226 // RenderContext.gl.shaderSource(shader, str); 227 // RenderContext.gl.compileShader(shader); 228 229 // if (!RenderContext.gl.getShaderParameter(shader, RenderContext.gl.COMPILE_STATUS)) { 230 // alert(RenderContext.gl.getShaderInfoLog(shader)); 231 // return null; 232 // } 233 234 // return shader; 235 // } 236 237 /**************************************************************************************************************/ 238 239 return Program; 240 241 }); 242