1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5  Copyright 2011 Jeff Lamarche
  6  Copyright 2012 Goffredo Marocchi
  7 
  8  http://www.cocos2d-x.org
  9 
 10  Permission is hereby granted, free of charge, to any person obtaining a copy
 11  of this software and associated documentation files (the "Software"), to deal
 12  in the Software without restriction, including without limitation the rights
 13  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 14  copies of the Software, and to permit persons to whom the Software is
 15  furnished to do so, subject to the following conditions:
 16 
 17  The above copyright notice and this permission notice shall be included in
 18  all copies or substantial portions of the Software.
 19 
 20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 25  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 26  THE SOFTWARE.
 27  ****************************************************************************/
 28 
 29 /**
 30  * Class that implements a WebGL program
 31  * @class
 32  * @extends cc.Class
 33  */
 34 cc.GLProgram = cc.Class.extend(/** @lends cc.GLProgram# */{
 35     _glContext: null,
 36     _programObj: null,
 37     _vertShader: null,
 38     _fragShader: null,
 39     _uniforms: null,
 40     _hashForUniforms: null,
 41     _usesTime: false,
 42 
 43     // Uniform cache
 44     _updateUniformLocation: function (location) {
 45         if (!location)
 46             return false;
 47 
 48         var updated;
 49         var element = this._hashForUniforms[location];
 50 
 51         if (!element) {
 52             element = [
 53                 arguments[1],
 54                 arguments[2],
 55                 arguments[3],
 56                 arguments[4]
 57             ];
 58             this._hashForUniforms[location] = element;
 59             updated = true;
 60         } else {
 61             updated = false;
 62             var count = arguments.length-1;
 63             for (var i = 0; i < count; ++i) {
 64                 if (arguments[i+1] !== element[i]) {
 65                     element[i] = arguments[i+1];
 66                     updated = true;
 67                 }
 68             }
 69         }
 70 
 71         return updated;
 72     },
 73 
 74     _description: function () {
 75         return "<CCGLProgram = " + this.toString() + " | Program = " + this._programObj.toString() + ", VertexShader = " +
 76             this._vertShader.toString() + ", FragmentShader = " + this._fragShader.toString() + ">";
 77     },
 78 
 79     _compileShader: function (shader, type, source) {
 80         if (!source || !shader)
 81             return false;
 82 
 83         var preStr = cc.GLProgram._isHighpSupported() ? "precision highp float;\n" : "precision mediump float;\n";
 84         source = preStr
 85             + "uniform mat4 CC_PMatrix;         \n"
 86             + "uniform mat4 CC_MVMatrix;        \n"
 87             + "uniform mat4 CC_MVPMatrix;       \n"
 88             + "uniform vec4 CC_Time;            \n"
 89             + "uniform vec4 CC_SinTime;         \n"
 90             + "uniform vec4 CC_CosTime;         \n"
 91             + "uniform vec4 CC_Random01;        \n"
 92             + "uniform sampler2D CC_Texture0;   \n"
 93             + "//CC INCLUDES END                \n" + source;
 94 
 95         this._glContext.shaderSource(shader, source);
 96         this._glContext.compileShader(shader);
 97         var status = this._glContext.getShaderParameter(shader, this._glContext.COMPILE_STATUS);
 98 
 99         if (!status) {
100             cc.log("cocos2d: ERROR: Failed to compile shader:\n" + this._glContext.getShaderSource(shader));
101             if (type === this._glContext.VERTEX_SHADER)
102                 cc.log("cocos2d: \n" + this.vertexShaderLog());
103             else
104                 cc.log("cocos2d: \n" + this.fragmentShaderLog());
105         }
106         return ( status === true );
107     },
108 
109 	/**
110 	 * Create a cc.GLProgram object
111 	 * @param {String} vShaderFileName
112 	 * @param {String} fShaderFileName
113 	 * @returns {cc.GLProgram}
114 	 */
115     ctor: function (vShaderFileName, fShaderFileName, glContext) {
116         this._uniforms = {};
117         this._hashForUniforms = {};
118         this._glContext = glContext || cc._renderContext;
119 
120 		vShaderFileName && fShaderFileName && this.init(vShaderFileName, fShaderFileName);
121     },
122 
123     /**
124      * destroy program
125      */
126     destroyProgram: function () {
127         this._vertShader = null;
128         this._fragShader = null;
129         this._uniforms = null;
130         this._hashForUniforms = null;
131 
132         this._glContext.deleteProgram(this._programObj);
133     },
134 
135     /**
136      * Initializes the cc.GLProgram with a vertex and fragment with string
137      * @param {String} vertShaderStr
138      * @param {String} fragShaderStr
139      * @return {Boolean}
140      */
141     initWithVertexShaderByteArray: function (vertShaderStr, fragShaderStr) {
142         var locGL = this._glContext;
143         this._programObj = locGL.createProgram();
144         //cc.checkGLErrorDebug();
145 
146         this._vertShader = null;
147         this._fragShader = null;
148 
149         if (vertShaderStr) {
150             this._vertShader = locGL.createShader(locGL.VERTEX_SHADER);
151             if (!this._compileShader(this._vertShader, locGL.VERTEX_SHADER, vertShaderStr)) {
152                 cc.log("cocos2d: ERROR: Failed to compile vertex shader");
153             }
154         }
155 
156         // Create and compile fragment shader
157         if (fragShaderStr) {
158             this._fragShader = locGL.createShader(locGL.FRAGMENT_SHADER);
159             if (!this._compileShader(this._fragShader, locGL.FRAGMENT_SHADER, fragShaderStr)) {
160                 cc.log("cocos2d: ERROR: Failed to compile fragment shader");
161             }
162         }
163 
164         if (this._vertShader)
165             locGL.attachShader(this._programObj, this._vertShader);
166         cc.checkGLErrorDebug();
167 
168         if (this._fragShader)
169             locGL.attachShader(this._programObj, this._fragShader);
170 
171         for (var key in this._hashForUniforms) {
172             delete this._hashForUniforms[key];
173         }
174 
175         cc.checkGLErrorDebug();
176         return true;
177     },
178 
179     /**
180      * Initializes the cc.GLProgram with a vertex and fragment with string
181      * @param {String} vertShaderStr
182      * @param {String} fragShaderStr
183      * @return {Boolean}
184      */
185     initWithString: function (vertShaderStr, fragShaderStr) {
186         return this.initWithVertexShaderByteArray(vertShaderStr, fragShaderStr);
187     },
188 
189     /**
190      * Initializes the CCGLProgram with a vertex and fragment with contents of filenames
191      * @param {String} vShaderFilename
192      * @param {String} fShaderFileName
193      * @return {Boolean}
194      */
195     initWithVertexShaderFilename: function (vShaderFilename, fShaderFileName) {
196         var vertexSource = cc.loader.getRes(vShaderFilename);
197         if(!vertexSource) throw new Error("Please load the resource firset : " + vShaderFilename);
198         var fragmentSource = cc.loader.getRes(fShaderFileName);
199         if(!fragmentSource) throw new Error("Please load the resource firset : " + fShaderFileName);
200         return this.initWithVertexShaderByteArray(vertexSource, fragmentSource);
201     },
202 
203     /**
204      * Initializes the CCGLProgram with a vertex and fragment with contents of filenames
205      * @param {String} vShaderFilename
206      * @param {String} fShaderFileName
207      * @return {Boolean}
208      */
209     init: function (vShaderFilename, fShaderFileName) {
210         return this.initWithVertexShaderFilename(vShaderFilename, fShaderFileName);
211     },
212 
213     /**
214      * It will add a new attribute to the shader
215      * @param {String} attributeName
216      * @param {Number} index
217      */
218     addAttribute: function (attributeName, index) {
219         this._glContext.bindAttribLocation(this._programObj, index, attributeName);
220     },
221 
222     /**
223      * links the glProgram
224      * @return {Boolean}
225      */
226     link: function () {
227         if(!this._programObj) {
228             cc.log("cc.GLProgram.link(): Cannot link invalid program");
229             return false;
230         }
231 
232         this._glContext.linkProgram(this._programObj);
233 
234         if (this._vertShader)
235             this._glContext.deleteShader(this._vertShader);
236         if (this._fragShader)
237             this._glContext.deleteShader(this._fragShader);
238 
239         this._vertShader = null;
240         this._fragShader = null;
241 
242         if (cc.game.config[cc.game.CONFIG_KEY.debugMode]) {
243             var status = this._glContext.getProgramParameter(this._programObj, this._glContext.LINK_STATUS);
244             if (!status) {
245                 cc.log("cocos2d: ERROR: Failed to link program: " + this._glContext.getProgramInfoLog(this._programObj));
246                 cc.glDeleteProgram(this._programObj);
247                 this._programObj = null;
248                 return false;
249             }
250         }
251 
252         return true;
253     },
254 
255     /**
256      * it will call glUseProgram()
257      */
258     use: function () {
259         cc.glUseProgram(this._programObj);
260     },
261 
262     /**
263      * It will create 4 uniforms:
264      *  cc.UNIFORM_PMATRIX
265      *  cc.UNIFORM_MVMATRIX
266      *  cc.UNIFORM_MVPMATRIX
267      *  cc.UNIFORM_SAMPLER
268      */
269     updateUniforms: function () {
270         this._uniforms[cc.UNIFORM_PMATRIX_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_PMATRIX_S);
271         this._uniforms[cc.UNIFORM_MVMATRIX_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVMATRIX_S);
272         this._uniforms[cc.UNIFORM_MVPMATRIX_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVPMATRIX_S);
273         this._uniforms[cc.UNIFORM_TIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_TIME_S);
274         this._uniforms[cc.UNIFORM_SINTIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SINTIME_S);
275         this._uniforms[cc.UNIFORM_COSTIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_COSTIME_S);
276 
277         this._usesTime = (this._uniforms[cc.UNIFORM_TIME_S] != null || this._uniforms[cc.UNIFORM_SINTIME_S] != null || this._uniforms[cc.UNIFORM_COSTIME_S] != null);
278 
279         this._uniforms[cc.UNIFORM_RANDOM01_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_RANDOM01_S);
280         this._uniforms[cc.UNIFORM_SAMPLER_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SAMPLER_S);
281 
282         this.use();
283         // Since sample most probably won't change, set it to 0 now.
284         this.setUniformLocationWith1i(this._uniforms[cc.UNIFORM_SAMPLER_S], 0);
285     },
286 
287     _addUniformLocation: function (name) {
288         var location = this._glContext.getUniformLocation(this._programObj, name);
289         this._uniforms[name] = location;
290     },
291 
292     /**
293      * calls retrieves the named uniform location for this shader program.
294      * @param {String} name
295      * @returns {Number}
296      */
297     getUniformLocationForName: function (name) {
298         if (!name)
299             throw new Error("cc.GLProgram.getUniformLocationForName(): uniform name should be non-null");
300         if (!this._programObj)
301             throw new Error("cc.GLProgram.getUniformLocationForName(): Invalid operation. Cannot get uniform location when program is not initialized");
302 
303         var location = this._uniforms[name] || this._glContext.getUniformLocation(this._programObj, name);
304         return location;
305     },
306 
307     /**
308      * get uniform MVP matrix
309      * @returns {WebGLUniformLocation}
310      */
311     getUniformMVPMatrix: function () {
312         return this._uniforms[cc.UNIFORM_MVPMATRIX_S];
313     },
314 
315     /**
316      * get uniform sampler
317      * @returns {WebGLUniformLocation}
318      */
319     getUniformSampler: function () {
320         return this._uniforms[cc.UNIFORM_SAMPLER_S];
321     },
322 
323     /**
324      * calls glUniform1i only if the values are different than the previous call for this same shader program.
325      * @param {WebGLUniformLocation|String} location
326      * @param {Number} i1
327      */
328     setUniformLocationWith1i: function (location, i1) {
329         var gl = this._glContext;
330         if (typeof location === 'string') {
331             var updated = this._updateUniformLocation(location, i1);
332             if (updated) {
333                 var locObj = this.getUniformLocationForName(location);
334                 gl.uniform1i(locObj, i1);
335             }
336         }
337         else {
338             gl.uniform1i(location, i1);
339         }
340     },
341 
342     /**
343      * calls glUniform2i only if the values are different than the previous call for this same shader program.
344      * @param {WebGLUniformLocation|String} location
345      * @param {Number} i1
346      * @param {Number} i2
347      */
348     setUniformLocationWith2i: function (location, i1, i2) {
349         var gl = this._glContext;
350         if (typeof location === 'string') {
351             var updated = this._updateUniformLocation(location, i1, i2);
352             if (updated) {
353                 var locObj = this.getUniformLocationForName(location);
354                 gl.uniform2i(locObj, i1, i2);
355             }
356         }
357         else {
358             gl.uniform2i(location, i1, i2);
359         }
360     },
361 
362     /**
363      * calls glUniform3i only if the values are different than the previous call for this same shader program.
364      * @param {WebGLUniformLocation|String} location
365      * @param {Number} i1
366      * @param {Number} i2
367      * @param {Number} i3
368      */
369     setUniformLocationWith3i: function (location, i1, i2, i3) {
370         var gl = this._glContext;
371         if (typeof location === 'string') {
372             var updated = this._updateUniformLocation(location, i1, i2, i3);
373             if (updated) {
374                 var locObj = this.getUniformLocationForName(location);
375                 gl.uniform3i(locObj, i1, i2, i3);
376             }
377         }
378         else {
379             gl.uniform3i(location, i1, i2, i3);
380         }
381     },
382 
383     /**
384      * calls glUniform4i only if the values are different than the previous call for this same shader program.
385      * @param {WebGLUniformLocation|String} location
386      * @param {Number} i1
387      * @param {Number} i2
388      * @param {Number} i3
389      * @param {Number} i4
390      */
391     setUniformLocationWith4i: function (location, i1, i2, i3, i4) {
392         var gl = this._glContext;
393         if (typeof location === 'string') {
394             var updated = this._updateUniformLocation(location, i1, i2, i3, i4);
395             if (updated) {
396                 var locObj = this.getUniformLocationForName(location);
397                 gl.uniform4i(locObj, i1, i2, i3, i4);
398             }
399         }
400         else {
401             gl.uniform4i(location, i1, i2, i3, i4);
402         }
403     },
404 
405     /**
406      * calls glUniform2iv
407      * @param {WebGLUniformLocation|String} location
408      * @param {Int32Array} intArray
409      * @param {Number} numberOfArrays
410      */
411     setUniformLocationWith2iv: function (location, intArray) {
412         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
413         this._glContext.uniform2iv(locObj, intArray);
414     },
415 
416     /**
417      * calls glUniform3iv
418      * @param {WebGLUniformLocation|String} location
419      * @param {Int32Array} intArray
420      */
421     setUniformLocationWith3iv:function(location, intArray){
422         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
423         this._glContext.uniform3iv(locObj, intArray);
424     },
425 
426     /**
427      * calls glUniform4iv
428      * @param {WebGLUniformLocation|String} location
429      * @param {Int32Array} intArray
430      */
431     setUniformLocationWith4iv:function(location, intArray){
432         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
433         this._glContext.uniform4iv(locObj, intArray);
434     },
435 
436     /**
437      * calls glUniform1i only if the values are different than the previous call for this same shader program.
438      * @param {WebGLUniformLocation|String} location
439      * @param {Number} i1
440      */
441     setUniformLocationI32: function (location, i1) {
442         this.setUniformLocationWith1i(location, i1);
443     },
444 
445     /**
446      * calls glUniform1f only if the values are different than the previous call for this same shader program.
447      * @param {WebGLUniformLocation|String} location
448      * @param {Number} f1
449      */
450     setUniformLocationWith1f: function (location, f1) {
451         var gl = this._glContext;
452         if (typeof location === 'string') {
453             var updated = this._updateUniformLocation(location, f1);
454             if (updated) {
455                 var locObj = this.getUniformLocationForName(location);
456                 gl.uniform1f(locObj, f1);
457             }
458         }
459         else {
460             gl.uniform1f(location, f1);
461         }
462     },
463 
464     /**
465      * calls glUniform2f only if the values are different than the previous call for this same shader program.
466      * @param {WebGLUniformLocation|String} location
467      * @param {Number} f1
468      * @param {Number} f2
469      */
470     setUniformLocationWith2f: function (location, f1, f2) {
471         var gl = this._glContext;
472         if (typeof location === 'string') {
473             var updated = this._updateUniformLocation(location, f1, f2);
474             if (updated) {
475                 var locObj = this.getUniformLocationForName(location);
476                 gl.uniform2f(locObj, f1, f2);
477             }
478         }
479         else {
480             gl.uniform2f(location, f1, f2);
481         }
482     },
483 
484     /**
485      * calls glUniform3f only if the values are different than the previous call for this same shader program.
486      * @param {WebGLUniformLocation|String} location
487      * @param {Number} f1
488      * @param {Number} f2
489      * @param {Number} f3
490      */
491     setUniformLocationWith3f: function (location, f1, f2, f3) {
492         var gl = this._glContext;
493         if (typeof location === 'string') {
494             var updated = this._updateUniformLocation(location, f1, f2, f3);
495             if (updated) {
496                 var locObj = this.getUniformLocationForName(location);
497                 gl.uniform3f(locObj, f1, f2, f3);
498             }
499         }
500         else {
501             gl.uniform3f(location, f1, f2, f3);
502         }
503     },
504 
505     /**
506      * calls glUniform4f only if the values are different than the previous call for this same shader program.
507      * @param {WebGLUniformLocation|String} location
508      * @param {Number} f1
509      * @param {Number} f2
510      * @param {Number} f3
511      * @param {Number} f4
512      */
513     setUniformLocationWith4f: function (location, f1, f2, f3, f4) {
514         var gl = this._glContext;
515         if (typeof location === 'string') {
516             var updated = this._updateUniformLocation(location, f1, f2, f3, f4);
517             if (updated) {
518                 var locObj = this.getUniformLocationForName(location);
519                 gl.uniform4f(locObj, f1, f2, f3, f4);
520             }
521         }
522         else {
523             gl.uniform4f(location, f1, f2, f3, f4);
524         }
525     },
526 
527     /**
528      * calls glUniform2fv
529      * @param {WebGLUniformLocation|String} location
530      * @param {Float32Array} floatArray
531      */
532     setUniformLocationWith2fv: function (location, floatArray) {
533         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
534         this._glContext.uniform2fv(locObj, floatArray);
535     },
536 
537     /**
538      * calls glUniform3fv
539      * @param {WebGLUniformLocation|String} location
540      * @param {Float32Array} floatArray
541      */
542     setUniformLocationWith3fv: function (location, floatArray) {
543         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
544         this._glContext.uniform3fv(locObj, floatArray);
545     },
546 
547     /**
548      * calls glUniform4fv
549      * @param {WebGLUniformLocation|String} location
550      * @param {Float32Array} floatArray
551      */
552     setUniformLocationWith4fv: function (location, floatArray) {
553         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
554         this._glContext.uniform4fv(locObj, floatArray);
555     },
556 
557     /**
558      * calls glUniformMatrix4fv
559      * @param {WebGLUniformLocation|String} location
560      * @param {Float32Array} matrixArray
561      */
562     setUniformLocationWithMatrix4fv: function (location, matrixArray) {
563         var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location;
564         this._glContext.uniformMatrix4fv(locObj, false, matrixArray);
565     },
566 
567     setUniformLocationF32: function () {
568         if (arguments.length < 2)
569             return;
570 
571         switch (arguments.length) {
572             case 2:
573                 this.setUniformLocationWith1f(arguments[0], arguments[1]);
574                 break;
575             case 3:
576                 this.setUniformLocationWith2f(arguments[0], arguments[1], arguments[2]);
577                 break;
578             case 4:
579                 this.setUniformLocationWith3f(arguments[0], arguments[1], arguments[2], arguments[3]);
580                 break;
581             case 5:
582                 this.setUniformLocationWith4f(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
583                 break;
584         }
585     },
586 
587     /**
588      * will update the builtin uniforms if they are different than the previous call for this same shader program.
589      */
590     setUniformsForBuiltins: function () {
591         var matrixP = new cc.math.Matrix4();
592         var matrixMV = new cc.math.Matrix4();
593         var matrixMVP = new cc.math.Matrix4();
594 
595         cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP);
596         cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, matrixMV);
597 
598         cc.kmMat4Multiply(matrixMVP, matrixP, matrixMV);
599 
600         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], matrixP.mat, 1);
601         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], matrixMV.mat, 1);
602         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], matrixMVP.mat, 1);
603 
604         if (this._usesTime) {
605             var director = cc.director;
606             // This doesn't give the most accurate global time value.
607             // Cocos2D doesn't store a high precision time value, so this will have to do.
608             // Getting Mach time per frame per shader using time could be extremely expensive.
609             var time = director.getTotalFrames() * director.getAnimationInterval();
610 
611             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME_S], time / 10.0, time, time * 2, time * 4);
612             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.sin(time));
613             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.cos(time));
614         }
615 
616         if (this._uniforms[cc.UNIFORM_RANDOM01_S] !== -1)
617             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01_S], Math.random(), Math.random(), Math.random(), Math.random());
618     },
619 
620     _setUniformsForBuiltinsForRenderer: function (node) {
621         if(!node || !node._renderCmd)
622             return;
623 
624         var matrixP = new cc.math.Matrix4();
625         //var matrixMV = new cc.kmMat4();
626         var matrixMVP = new cc.math.Matrix4();
627 
628         cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP);
629         //cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, node._stackMatrix);
630 
631         cc.kmMat4Multiply(matrixMVP, matrixP, node._renderCmd._stackMatrix);
632 
633         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], matrixP.mat, 1);
634         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], node._renderCmd._stackMatrix.mat, 1);
635         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], matrixMVP.mat, 1);
636 
637         if (this._usesTime) {
638             var director = cc.director;
639             // This doesn't give the most accurate global time value.
640             // Cocos2D doesn't store a high precision time value, so this will have to do.
641             // Getting Mach time per frame per shader using time could be extremely expensive.
642             var time = director.getTotalFrames() * director.getAnimationInterval();
643 
644             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME_S], time / 10.0, time, time * 2, time * 4);
645             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.sin(time));
646             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.cos(time));
647         }
648 
649         if (this._uniforms[cc.UNIFORM_RANDOM01_S] !== -1)
650             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01_S], Math.random(), Math.random(), Math.random(), Math.random());
651     },
652 
653     /**
654      * will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program.
655      */
656     setUniformForModelViewProjectionMatrix: function () {
657         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], false,
658         cc.getMat4MultiplyValue(cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top));
659     },
660 
661     setUniformForModelViewProjectionMatrixWithMat4: function (swapMat4) {
662         cc.kmMat4Multiply(swapMat4, cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top);
663         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], false, swapMat4.mat);
664     },
665 
666     setUniformForModelViewAndProjectionMatrixWithMat4: function () {
667         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], false, cc.modelview_matrix_stack.top.mat);
668         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat);
669     },
670 
671     _setUniformForMVPMatrixWithMat4: function(modelViewMatrix){
672         if(!modelViewMatrix)
673             throw new Error("modelView matrix is undefined.");
674         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], false, modelViewMatrix.mat);
675         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat);
676     },
677 
678     _updateProjectionUniform: function(){
679         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat);  
680     },
681 
682     /**
683      * returns the vertexShader error log
684      * @return {String}
685      */
686     vertexShaderLog: function () {
687         return this._glContext.getShaderInfoLog(this._vertShader);
688     },
689 
690     /**
691      * returns the vertexShader error log
692      * @return {String}
693      */
694     getVertexShaderLog: function () {
695         return this._glContext.getShaderInfoLog(this._vertShader);
696     },
697 
698     /**
699      * returns the fragmentShader error log
700      * @returns {String}
701      */
702     getFragmentShaderLog: function () {
703         return this._glContext.getShaderInfoLog(this._vertShader);
704     },
705 
706     /**
707      * returns the fragmentShader error log
708      * @return {String}
709      */
710     fragmentShaderLog: function () {
711         return this._glContext.getShaderInfoLog(this._fragShader);
712     },
713 
714     /**
715      * returns the program error log
716      * @return {String}
717      */
718     programLog: function () {
719         return this._glContext.getProgramInfoLog(this._programObj);
720     },
721 
722     /**
723      * returns the program error log
724      * @return {String}
725      */
726     getProgramLog: function () {
727         return this._glContext.getProgramInfoLog(this._programObj);
728     },
729 
730     /**
731      *  reload all shaders, this function is designed for android  <br/>
732      *  when opengl context lost, so don't call it.
733      */
734     reset: function () {
735         this._vertShader = null;
736         this._fragShader = null;
737         this._uniforms.length = 0;
738 
739         // it is already deallocated by android
740         //ccGLDeleteProgram(m_uProgram);
741         this._glContext.deleteProgram(this._programObj);
742         this._programObj = null;
743 
744         // Purge uniform hash
745         for (var key in this._hashForUniforms) {
746             delete this._hashForUniforms[key];
747         }
748     },
749 
750     /**
751      * get WebGLProgram object
752      * @return {WebGLProgram}
753      */
754     getProgram: function () {
755         return this._programObj;
756     },
757 
758     /**
759      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
760      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
761      * This is a hack, and should be removed once JSB fixes the retain/release bug
762      */
763     retain: function () {
764     },
765     release: function () {
766     }
767 });
768 
769 /**
770  * Create a cc.GLProgram object
771  * @deprecated since v3.0, please use new cc.GLProgram(vShaderFileName, fShaderFileName) instead
772  * @param {String} vShaderFileName
773  * @param {String} fShaderFileName
774  * @returns {cc.GLProgram}
775  */
776 cc.GLProgram.create = function (vShaderFileName, fShaderFileName) {
777     return new cc.GLProgram(vShaderFileName, fShaderFileName);
778 };
779 
780 cc.GLProgram._highpSupported = null;
781 
782 cc.GLProgram._isHighpSupported = function(){
783     if(cc.GLProgram._highpSupported == null){
784         var ctx = cc._renderContext;
785         var highp = ctx.getShaderPrecisionFormat(ctx.FRAGMENT_SHADER, ctx.HIGH_FLOAT);
786         cc.GLProgram._highpSupported = highp.precision !== 0;
787     }
788     return cc.GLProgram._highpSupported;
789 };
790 
791 /**
792  * <p>
793  *     Sets the shader program for this node
794  *
795  *     Since v2.0, each rendering node must set its shader program.
796  *     It should be set in initialize phase.
797  * </p>
798  * @function
799  * @param {cc.Node} node
800  * @param {cc.GLProgram} program The shader program which fetches from CCShaderCache.
801  * @example
802  * cc.setGLProgram(node, cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR));
803  */
804 cc.setProgram = function (node, program) {
805     node.shaderProgram = program;
806 
807     var children = node.children;
808     if (!children)
809         return;
810 
811     for (var i = 0; i < children.length; i++)
812         cc.setProgram(children[i], program);
813 };
814