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 cc.HashUniformEntry = function (value, location, hh) {
 30     this.value = value;
 31     this.location = location;
 32     this.hh = hh || {};
 33 };
 34 
 35 /**
 36  * Class that implements a WebGL program
 37  * @class
 38  * @extends cc.Class
 39  */
 40 cc.GLProgram = cc.Class.extend(/** @lends cc.GLProgram# */{
 41     _glContext: null,
 42     _programObj: null,
 43     _vertShader: null,
 44     _fragShader: null,
 45     _uniforms: null,
 46     _hashForUniforms: null,
 47     _usesTime: false,
 48 
 49     // Uniform cache
 50     _updateUniformLocation: function (location, data, bytes) {
 51         if (location == null)
 52             return false;
 53 
 54         var updated = true;
 55         var element = null;
 56         for (var i = 0; i < this._hashForUniforms.length; i++)
 57             if (this._hashForUniforms[i].location == location)
 58                 element = this._hashForUniforms[i];
 59 
 60         if (!element) {
 61             element = new cc.HashUniformEntry();
 62             // key
 63             element.location = location;
 64             // value
 65             element.value = data;
 66             this._hashForUniforms.push(element);
 67         } else {
 68             if (element.value == data)
 69                 updated = false;
 70             else
 71                 element.value = data;
 72         }
 73 
 74         return updated;
 75     },
 76 
 77     _description: function () {
 78         return "<CCGLProgram = " + this.toString() + " | Program = " + this._programObj.toString() + ", VertexShader = " +
 79             this._vertShader.toString() + ", FragmentShader = " + this._fragShader.toString() + ">";
 80     },
 81 
 82     _compileShader: function (shader, type, source) {
 83         if (!source || !shader)
 84             return false;
 85 
 86         //var preStr = (type == this._glContext.VERTEX_SHADER) ? "precision highp float;\n" : "precision mediump float;\n";
 87         source = "precision highp float;        \n"
 88             + "uniform mat4 CC_PMatrix;         \n"
 89             + "uniform mat4 CC_MVMatrix;        \n"
 90             + "uniform mat4 CC_MVPMatrix;       \n"
 91             + "uniform vec4 CC_Time;            \n"
 92             + "uniform vec4 CC_SinTime;         \n"
 93             + "uniform vec4 CC_CosTime;         \n"
 94             + "uniform vec4 CC_Random01;        \n"
 95             + "//CC INCLUDES END                \n" + source;
 96 
 97         this._glContext.shaderSource(shader, source);
 98         this._glContext.compileShader(shader);
 99         var status = this._glContext.getShaderParameter(shader, this._glContext.COMPILE_STATUS);
100 
101         if (!status) {
102             cc.log("cocos2d: ERROR: Failed to compile shader:\n" + this._glContext.getShaderSource(shader));
103             if (type == this._glContext.VERTEX_SHADER)
104                 cc.log("cocos2d: \n" + this.vertexShaderLog());
105             else
106                 cc.log("cocos2d: \n" + this.fragmentShaderLog());
107         }
108         return ( status == 1 );
109     },
110 
111 	/**
112 	 * Create a cc.GLProgram object
113 	 * @param {String} vShaderFileName
114 	 * @param {String} fShaderFileName
115 	 * @returns {cc.GLProgram}
116 	 */
117     ctor: function (vShaderFileName, fShaderFileName, glContext) {
118         this._uniforms = [];
119         this._hashForUniforms = [];
120         this._glContext = glContext || cc._renderContext;
121 
122 		vShaderFileName && fShaderFileName && this.init(vShaderFileName, fShaderFileName);
123     },
124 
125     /**
126      * destroy program
127      */
128     destroyProgram: function () {
129         this._vertShader = null;
130         this._fragShader = null;
131         this._uniforms = null;
132         this._hashForUniforms = null;
133 
134         this._glContext.deleteProgram(this._programObj);
135     },
136 
137     /**
138      * Initializes the cc.GLProgram with a vertex and fragment with string
139      * @param {String} vertShaderStr
140      * @param {String} fragShaderStr
141      * @return {Boolean}
142      */
143     initWithVertexShaderByteArray: function (vertShaderStr, fragShaderStr) {
144         var locGL = this._glContext;
145         this._programObj = locGL.createProgram();
146         //cc.checkGLErrorDebug();
147 
148         this._vertShader = null;
149         this._fragShader = null;
150 
151         if (vertShaderStr) {
152             this._vertShader = locGL.createShader(locGL.VERTEX_SHADER);
153             if (!this._compileShader(this._vertShader, locGL.VERTEX_SHADER, vertShaderStr)) {
154                 cc.log("cocos2d: ERROR: Failed to compile vertex shader");
155             }
156         }
157 
158         // Create and compile fragment shader
159         if (fragShaderStr) {
160             this._fragShader = locGL.createShader(locGL.FRAGMENT_SHADER);
161             if (!this._compileShader(this._fragShader, locGL.FRAGMENT_SHADER, fragShaderStr)) {
162                 cc.log("cocos2d: ERROR: Failed to compile fragment shader");
163             }
164         }
165 
166         if (this._vertShader)
167             locGL.attachShader(this._programObj, this._vertShader);
168         cc.checkGLErrorDebug();
169 
170         if (this._fragShader)
171             locGL.attachShader(this._programObj, this._fragShader);
172         this._hashForUniforms.length = 0;
173 
174         cc.checkGLErrorDebug();
175         return true;
176     },
177 
178     /**
179      * Initializes the cc.GLProgram with a vertex and fragment with string
180      * @param {String} vertShaderStr
181      * @param {String} fragShaderStr
182      * @return {Boolean}
183      */
184     initWithString: function (vertShaderStr, fragShaderStr) {
185         return this.initWithVertexShaderByteArray(vertShaderStr, fragShaderStr);
186     },
187 
188     /**
189      * Initializes the CCGLProgram with a vertex and fragment with contents of filenames
190      * @param {String} vShaderFilename
191      * @param {String} fShaderFileName
192      * @return {Boolean}
193      */
194     initWithVertexShaderFilename: function (vShaderFilename, fShaderFileName) {
195         var vertexSource = cc.loader.getRes(vShaderFilename);
196         if(!vertexSource) throw "Please load the resource firset : " + vShaderFilename;
197         var fragmentSource = cc.loader.getRes(fShaderFileName);
198         if(!fragmentSource) throw "Please load the resource firset : " + fShaderFileName;
199         return this.initWithVertexShaderByteArray(vertexSource, fragmentSource);
200     },
201 
202     /**
203      * Initializes the CCGLProgram with a vertex and fragment with contents of filenames
204      * @param {String} vShaderFilename
205      * @param {String} fShaderFileName
206      * @return {Boolean}
207      */
208     init: function (vShaderFilename, fShaderFileName) {
209         return this.initWithVertexShaderFilename(vShaderFilename, fShaderFileName);
210     },
211 
212     /**
213      * It will add a new attribute to the shader
214      * @param {String} attributeName
215      * @param {Number} index
216      */
217     addAttribute: function (attributeName, index) {
218         this._glContext.bindAttribLocation(this._programObj, index, attributeName);
219     },
220 
221     /**
222      * links the glProgram
223      * @return {Boolean}
224      */
225     link: function () {
226         if(!this._programObj) {
227             cc.log("cc.GLProgram.link(): Cannot link invalid program");
228             return false;
229         }
230 
231         this._glContext.linkProgram(this._programObj);
232 
233         if (this._vertShader)
234             this._glContext.deleteShader(this._vertShader);
235         if (this._fragShader)
236             this._glContext.deleteShader(this._fragShader);
237 
238         this._vertShader = null;
239         this._fragShader = null;
240 
241         if (cc.game.config[cc.game.CONFIG_KEY.debugMode]) {
242             var status = this._glContext.getProgramParameter(this._programObj, this._glContext.LINK_STATUS);
243             if (!status) {
244                 cc.log("cocos2d: ERROR: Failed to link program: " + this._glContext.getProgramInfoLog(this._programObj));
245                 cc.glDeleteProgram(this._programObj);
246                 this._programObj = null;
247                 return false;
248             }
249         }
250 
251         return true;
252     },
253 
254     /**
255      * it will call glUseProgram()
256      */
257     use: function () {
258         cc.glUseProgram(this._programObj);
259     },
260 
261     /**
262      * It will create 4 uniforms:
263      *  cc.UNIFORM_PMATRIX
264      *  cc.UNIFORM_MVMATRIX
265      *  cc.UNIFORM_MVPMATRIX
266      *  cc.UNIFORM_SAMPLER
267      */
268     updateUniforms: function () {
269         this._uniforms[cc.UNIFORM_PMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_PMATRIX_S);
270         this._uniforms[cc.UNIFORM_MVMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVMATRIX_S);
271         this._uniforms[cc.UNIFORM_MVPMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVPMATRIX_S);
272         this._uniforms[cc.UNIFORM_TIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_TIME_S);
273         this._uniforms[cc.UNIFORM_SINTIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SINTIME_S);
274         this._uniforms[cc.UNIFORM_COSTIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_COSTIME_S);
275 
276         this._usesTime = (this._uniforms[cc.UNIFORM_TIME] != null || this._uniforms[cc.UNIFORM_SINTIME] != null || this._uniforms[cc.UNIFORM_COSTIME] != null);
277 
278         this._uniforms[cc.UNIFORM_RANDOM01] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_RANDOM01_S);
279         this._uniforms[cc.UNIFORM_SAMPLER] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SAMPLER_S);
280 
281         this.use();
282         // Since sample most probably won't change, set it to 0 now.
283         this.setUniformLocationWith1i(this._uniforms[cc.UNIFORM_SAMPLER], 0);
284     },
285 
286     /**
287      * calls retrieves the named uniform location for this shader program.
288      * @param {String} name
289      * @returns {Number}
290      */
291     getUniformLocationForName:function(name){
292         if(!name)
293             throw "cc.GLProgram.getUniformLocationForName(): uniform name should be non-null";
294         if(!this._programObj)
295             throw "cc.GLProgram.getUniformLocationForName(): Invalid operation. Cannot get uniform location when program is not initialized";
296 
297         return this._glContext.getUniformLocation(this._programObj, name);
298     },
299 
300     /**
301      * get uniform MVP matrix
302      * @returns {WebGLUniformLocation}
303      */
304     getUniformMVPMatrix: function () {
305         return this._uniforms[cc.UNIFORM_MVPMATRIX];
306     },
307 
308     /**
309      * get uniform sampler
310      * @returns {WebGLUniformLocation}
311      */
312     getUniformSampler: function () {
313         return this._uniforms[cc.UNIFORM_SAMPLER];
314     },
315 
316     /**
317      * calls glUniform1i only if the values are different than the previous call for this same shader program.
318      * @param {WebGLUniformLocation} location
319      * @param {Number} i1
320      */
321     setUniformLocationWith1i: function (location, i1) {
322         var updated = this._updateUniformLocation(location, i1);
323         if (updated)
324             this._glContext.uniform1i(location, i1);
325     },
326 
327     /**
328      * calls glUniform2i only if the values are different than the previous call for this same shader program.
329      * @param {WebGLUniformLocation} location
330      * @param {Number} i1
331      * @param {Number} i2
332      */
333     setUniformLocationWith2i:function(location, i1,i2){
334         var intArray= [i1,i2];
335         var updated =  this._updateUniformLocation(location, intArray);
336 
337         if( updated )
338             this._glContext.uniform2i(location, i1, i2);
339     },
340 
341     /**
342      * calls glUniform3i only if the values are different than the previous call for this same shader program.
343      * @param {WebGLUniformLocation} location
344      * @param {Number} i1
345      * @param {Number} i2
346      * @param {Number} i3
347      */
348     setUniformLocationWith3i:function(location, i1, i2, i3){
349         var intArray = [i1,i2,i3];
350         var updated =  this._updateUniformLocation(location, intArray);
351 
352         if( updated )
353             this._glContext.uniform3i(location, i1, i2, i3);
354     },
355 
356     /**
357      * calls glUniform4i only if the values are different than the previous call for this same shader program.
358      * @param {WebGLUniformLocation} location
359      * @param {Number} i1
360      * @param {Number} i2
361      * @param {Number} i3
362      * @param {Number} i4
363      */
364     setUniformLocationWith4i:function(location, i1, i2, i3, i4){
365         var intArray = [i1,i2,i3,i4];
366         var updated =  this._updateUniformLocation(location, intArray);
367 
368         if( updated )
369             this._glContext.uniform4i(location, i1, i2, i3, i4);
370     },
371 
372     /**
373      * calls glUniform2iv only if the values are different than the previous call for this same shader program.
374      * @param {WebGLUniformLocation} location
375      * @param {Int32Array} intArray
376      * @param {Number} numberOfArrays
377      */
378     setUniformLocationWith2iv:function(location, intArray, numberOfArrays){
379         var updated =  this._updateUniformLocation(location, intArray);
380 
381         if( updated )
382             this._glContext.uniform2iv(location, intArray);
383     },
384 
385     /**
386      * calls glUniform3iv only if the values are different than the previous call for this same shader program.
387      * @param {WebGLUniformLocation} location
388      * @param {Int32Array} intArray
389      * @param {Number} numberOfArrays
390      */
391     setUniformLocationWith3iv:function(location, intArray, numberOfArrays){
392         var updated =  this._updateUniformLocation(location, intArray);
393 
394         if( updated )
395             this._glContext.uniform3iv(location, intArray);
396     },
397 
398     /**
399      * calls glUniform4iv only if the values are different than the previous call for this same shader program.
400      * @param {WebGLUniformLocation} location
401      * @param {Int32Array} intArray
402      * @param {Number} numberOfArrays
403      */
404     setUniformLocationWith4iv:function(location, intArray, numberOfArrays){
405         var updated =  this._updateUniformLocation(location, intArray);
406 
407         if( updated )
408             this._glContext.uniform4iv(location, intArray);
409     },
410 
411     /**
412      * calls glUniform1i only if the values are different than the previous call for this same shader program.
413      * @param {WebGLUniformLocation} location
414      * @param {Number} i1
415      */
416     setUniformLocationI32: function (location, i1) {
417         this.setUniformLocationWith1i(arguments[0], arguments[1]);
418     },
419 
420     /**
421      * calls glUniform1f only if the values are different than the previous call for this same shader program.
422      * @param {WebGLUniformLocation} location
423      * @param {Number} f1
424      */
425     setUniformLocationWith1f: function (location, f1) {
426         var updated = this._updateUniformLocation(location, f1);
427         if (updated)
428             this._glContext.uniform1f(location, f1);
429     },
430 
431     /**
432      * calls glUniform2f only if the values are different than the previous call for this same shader program.
433      * @param {WebGLUniformLocation} location
434      * @param {Number} f1
435      * @param {Number} f2
436      */
437     setUniformLocationWith2f: function (location, f1, f2) {
438         var floats = [f1, f2];
439         var updated = this._updateUniformLocation(location, floats);
440         if (updated)
441             this._glContext.uniform2f(location, f1, f2);
442     },
443 
444     /**
445      * calls glUniform3f only if the values are different than the previous call for this same shader program.
446      * @param {WebGLUniformLocation} location
447      * @param {Number} f1
448      * @param {Number} f2
449      * @param {Number} f3
450      */
451     setUniformLocationWith3f: function (location, f1, f2, f3) {
452         var floats = [f1, f2, f3];
453         var updated = this._updateUniformLocation(location, floats);
454         if (updated)
455             this._glContext.uniform3f(location, f1, f2, f3);
456     },
457 
458     /**
459      * calls glUniform4f only if the values are different than the previous call for this same shader program.
460      * @param {WebGLUniformLocation} location
461      * @param {Number} f1
462      * @param {Number} f2
463      * @param {Number} f3
464      * @param {Number} f4
465      */
466     setUniformLocationWith4f: function (location, f1, f2, f3, f4) {
467         var floats = [f1, f2, f3, f4];
468         var updated = this._updateUniformLocation(location, floats);
469         if (updated)
470             this._glContext.uniform4f(location, f1, f2, f3, f4);
471     },
472 
473     /**
474      * calls glUniform2fv only if the values are different than the previous call for this same shader program.
475      * @param {WebGLUniformLocation} location
476      * @param {Float32Array} floatArray
477      * @param {Number} numberOfArrays
478      */
479     setUniformLocationWith2fv: function (location, floatArray, numberOfArrays) {
480         var updated = this._updateUniformLocation(location, floatArray);
481         if (updated)
482             this._glContext.uniform2fv(location, floatArray);
483     },
484 
485     /**
486      * calls glUniform3fv only if the values are different than the previous call for this same shader program.
487      * @param {WebGLUniformLocation} location
488      * @param {Float32Array} floatArray
489      * @param {Number} numberOfArrays
490      */
491     setUniformLocationWith3fv: function (location, floatArray, numberOfArrays) {
492         var updated = this._updateUniformLocation(location, floatArray);
493         if (updated)
494             this._glContext.uniform3fv(location, floatArray);
495     },
496 
497     /**
498      * calls glUniform4fv only if the values are different than the previous call for this same shader program.
499      * @param {WebGLUniformLocation} location
500      * @param {Float32Array} floatArray
501      * @param {Number} numberOfArrays
502      */
503     setUniformLocationWith4fv: function (location, floatArray, numberOfArrays) {
504         var updated = this._updateUniformLocation(location, floatArray);
505         if (updated)
506             this._glContext.uniform4fv(location, floatArray);
507     },
508 
509     /**
510      * calls glUniformMatrix4fv only if the values are different than the previous call for this same shader program.
511      * @param {WebGLUniformLocation} location
512      * @param {Float32Array} matrixArray
513      * @param {Number} numberOfMatrices
514      */
515     setUniformLocationWithMatrix4fv: function (location, matrixArray, numberOfMatrices) {
516         var updated = this._updateUniformLocation(location, matrixArray);
517         if (updated)
518             this._glContext.uniformMatrix4fv(location, false, matrixArray);
519     },
520 
521     setUniformLocationF32: function () {
522         if (arguments.length < 2)
523             return;
524 
525         switch (arguments.length) {
526             case 2:
527                 this.setUniformLocationWith1f(arguments[0], arguments[1]);
528                 break;
529             case 3:
530                 this.setUniformLocationWith2f(arguments[0], arguments[1], arguments[2]);
531                 break;
532             case 4:
533                 this.setUniformLocationWith3f(arguments[0], arguments[1], arguments[2], arguments[3]);
534                 break;
535             case 5:
536                 this.setUniformLocationWith4f(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
537                 break;
538         }
539     },
540 
541     /**
542      * will update the builtin uniforms if they are different than the previous call for this same shader program.
543      */
544     setUniformsForBuiltins: function () {
545         var matrixP = new cc.kmMat4();
546         var matrixMV = new cc.kmMat4();
547         var matrixMVP = new cc.kmMat4();
548 
549         cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP);
550         cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, matrixMV);
551 
552         cc.kmMat4Multiply(matrixMVP, matrixP, matrixMV);
553 
554         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], matrixP.mat, 1);
555         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], matrixMV.mat, 1);
556         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], matrixMVP.mat, 1);
557 
558         if (this._usesTime) {
559             var director = cc.director;
560             // This doesn't give the most accurate global time value.
561             // Cocos2D doesn't store a high precision time value, so this will have to do.
562             // Getting Mach time per frame per shader using time could be extremely expensive.
563             var time = director.getTotalFrames() * director.getAnimationInterval();
564 
565             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME], time / 10.0, time, time * 2, time * 4);
566             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME], time / 8.0, time / 4.0, time / 2.0, Math.sin(time));
567             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME], time / 8.0, time / 4.0, time / 2.0, Math.cos(time));
568         }
569 
570         if (this._uniforms[cc.UNIFORM_RANDOM01] != -1)
571             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01], Math.random(), Math.random(), Math.random(), Math.random());
572     },
573 
574     /**
575      * will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program.
576      */
577     setUniformForModelViewProjectionMatrix: function () {
578         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], false,
579             cc.getMat4MultiplyValue(cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top));
580     },
581 
582     setUniformForModelViewProjectionMatrixWithMat4: function (swapMat4) {
583         cc.kmMat4Multiply(swapMat4, cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top);
584         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], false, swapMat4.mat);
585     },
586 
587     setUniformForModelViewAndProjectionMatrixWithMat4: function () {
588         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], false, cc.modelview_matrix_stack.top.mat);
589         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], false, cc.projection_matrix_stack.top.mat);
590     },
591 
592 
593     /**
594      * returns the vertexShader error log
595      * @return {String}
596      */
597     vertexShaderLog: function () {
598         return this._glContext.getShaderInfoLog(this._vertShader);
599     },
600 
601     /**
602      * returns the vertexShader error log
603      * @return {String}
604      */
605     getVertexShaderLog: function () {
606         return this._glContext.getShaderInfoLog(this._vertShader);
607     },
608 
609     /**
610      * returns the fragmentShader error log
611      * @returns {String}
612      */
613     getFragmentShaderLog: function () {
614         return this._glContext.getShaderInfoLog(this._vertShader);
615     },
616 
617     /**
618      * returns the fragmentShader error log
619      * @return {String}
620      */
621     fragmentShaderLog: function () {
622         return this._glContext.getShaderInfoLog(this._fragShader);
623     },
624 
625     /**
626      * returns the program error log
627      * @return {String}
628      */
629     programLog: function () {
630         return this._glContext.getProgramInfoLog(this._programObj);
631     },
632 
633     /**
634      * returns the program error log
635      * @return {String}
636      */
637     getProgramLog: function () {
638         return this._glContext.getProgramInfoLog(this._programObj);
639     },
640 
641     /**
642      *  reload all shaders, this function is designed for android  <br/>
643      *  when opengl context lost, so don't call it.
644      */
645     reset: function () {
646         this._vertShader = null;
647         this._fragShader = null;
648         this._uniforms.length = 0;
649 
650         // it is already deallocated by android
651         //ccGLDeleteProgram(m_uProgram);
652         this._glContext.deleteProgram(this._programObj);
653         this._programObj = null;
654 
655         // Purge uniform hash
656         for (var i = 0; i < this._hashForUniforms.length; i++) {
657             this._hashForUniforms[i].value = null;
658             this._hashForUniforms[i] = null;
659         }
660 
661         this._hashForUniforms.length = 0;
662     },
663 
664     /**
665      * get WebGLProgram object
666      * @return {WebGLProgram}
667      */
668     getProgram: function () {
669         return this._programObj;
670     },
671 
672     /**
673      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
674      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
675      * This is a hack, and should be removed once JSB fixes the retain/release bug
676      */
677     retain: function () {
678     },
679     release: function () {
680     }
681 });
682 
683 /**
684  * Create a cc.GLProgram object
685  * @deprecated since v3.0, please use new cc.GLProgram(vShaderFileName, fShaderFileName) instead
686  * @param {String} vShaderFileName
687  * @param {String} fShaderFileName
688  * @returns {cc.GLProgram}
689  */
690 cc.GLProgram.create = function (vShaderFileName, fShaderFileName) {
691     return new cc.GLProgram(vShaderFileName, fShaderFileName);
692 };
693