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