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