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