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         source = "precision highp float;        \n"
263             + "uniform mat4 CC_PMatrix;         \n"
264             + "uniform mat4 CC_MVMatrix;        \n"
265             + "uniform mat4 CC_MVPMatrix;       \n"
266             + "uniform vec4 CC_Time;            \n"
267             + "uniform vec4 CC_SinTime;         \n"
268             + "uniform vec4 CC_CosTime;         \n"
269             + "uniform vec4 CC_Random01;        \n"
270             + "//CC INCLUDES END                \n" + source;
271 
272         this._glContext.shaderSource(shader, source);
273         this._glContext.compileShader(shader);
274         var status = this._glContext.getShaderParameter(shader, this._glContext.COMPILE_STATUS);
275 
276         if (!status) {
277             cc.log("cocos2d: ERROR: Failed to compile shader:\n" + this._glContext.getShaderSource(shader));
278             if (type == this._glContext.VERTEX_SHADER)
279                 cc.log("cocos2d: \n" + this.vertexShaderLog());
280             else
281                 cc.log("cocos2d: \n" + this.fragmentShaderLog());
282         }
283         return ( status == 1 );
284     },
285 
286     ctor: function (glContext) {
287         this._programObj = null;
288         this._vertShader = null;
289         this._fragShader = null;
290         this._uniforms = [];
291         this._hashForUniforms = [];
292         this._glContext = glContext || cc._renderContext;
293     },
294 
295     destroyProgram: function () {
296         this._vertShader = null;
297         this._fragShader = null;
298         this._uniforms = null;
299         this._hashForUniforms = null;
300 
301         this._glContext.deleteProgram(this._programObj);
302     },
303 
304     /**
305      * Initializes the cc.GLProgram with a vertex and fragment with string
306      * @param {String} vertShaderStr
307      * @param {String} fragShaderStr
308      * @return {Boolean}
309      */
310     initWithVertexShaderByteArray: function (vertShaderStr, fragShaderStr) {
311         var locGL = this._glContext;
312         this._programObj = locGL.createProgram();
313         //cc.CHECK_GL_ERROR_DEBUG();
314 
315         this._vertShader = null;
316         this._fragShader = null;
317 
318         if (vertShaderStr) {
319             this._vertShader = locGL.createShader(locGL.VERTEX_SHADER);
320             if (!this._compileShader(this._vertShader, locGL.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 = locGL.createShader(locGL.FRAGMENT_SHADER);
328             if (!this._compileShader(this._fragShader, locGL.FRAGMENT_SHADER, fragShaderStr)) {
329                 cc.log("cocos2d: ERROR: Failed to compile fragment shader");
330             }
331         }
332 
333         if (this._vertShader)
334             locGL.attachShader(this._programObj, this._vertShader);
335         cc.CHECK_GL_ERROR_DEBUG();
336 
337         if (this._fragShader)
338             locGL.attachShader(this._programObj, this._fragShader);
339         this._hashForUniforms.length = 0;
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 vertexSource = cc.loader.getRes(vShaderFilename);
363         if(!vertexSource) throw "Please load the resource firset : " + vShaderFilename;
364         var fragmentSource = cc.loader.getRes(fShaderFileName);
365         if(!fragmentSource) throw "Please load the resource firset : " + fShaderFileName;
366         return this.initWithVertexShaderByteArray(vertexSource, fragmentSource);
367     },
368 
369     /**
370      * Initializes the CCGLProgram with a vertex and fragment with contents of filenames
371      * @param {String} vShaderFilename
372      * @param {String} fShaderFileName
373      * @return {Boolean}
374      */
375     init: function (vShaderFilename, fShaderFileName) {
376         return this.initWithVertexShaderFilename(vShaderFilename, fShaderFileName);
377     },
378 
379     /**
380      * It will add a new attribute to the shader
381      * @param {String} attributeName
382      * @param {Number} index
383      */
384     addAttribute: function (attributeName, index) {
385         this._glContext.bindAttribLocation(this._programObj, index, attributeName);
386     },
387 
388     /**
389      * links the glProgram
390      * @return {Boolean}
391      */
392     link: function () {
393         if(!this._programObj) {
394             cc.log("cc.GLProgram.link(): Cannot link invalid program");
395             return false;
396         }
397 
398         this._glContext.linkProgram(this._programObj);
399 
400         if (this._vertShader)
401             this._glContext.deleteShader(this._vertShader);
402         if (this._fragShader)
403             this._glContext.deleteShader(this._fragShader);
404 
405         this._vertShader = null;
406         this._fragShader = null;
407 
408         if (cc.game.config[cc.game.CONFIG_KEY.debugMode]) {
409             var status = this._glContext.getProgramParameter(this._programObj, this._glContext.LINK_STATUS);
410             if (!status) {
411                 cc.log("cocos2d: ERROR: Failed to link program: " + this._glContext.getProgramInfoLog(this._programObj));
412                 cc.glDeleteProgram(this._programObj);
413                 this._programObj = null;
414                 return false;
415             }
416         }
417 
418         return true;
419     },
420 
421     /**
422      * it will call glUseProgram()
423      */
424     use: function () {
425         cc.glUseProgram(this._programObj);
426     },
427 
428     /**
429      * It will create 4 uniforms:
430      *  cc.UNIFORM_PMATRIX
431      *  cc.UNIFORM_MVMATRIX
432      *  cc.UNIFORM_MVPMATRIX
433      *  cc.UNIFORM_SAMPLER
434      */
435     updateUniforms: function () {
436         this._uniforms[cc.UNIFORM_PMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_PMATRIX_S);
437         this._uniforms[cc.UNIFORM_MVMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVMATRIX_S);
438         this._uniforms[cc.UNIFORM_MVPMATRIX] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVPMATRIX_S);
439         this._uniforms[cc.UNIFORM_TIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_TIME_S);
440         this._uniforms[cc.UNIFORM_SINTIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SINTIME_S);
441         this._uniforms[cc.UNIFORM_COSTIME] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_COSTIME_S);
442 
443         this._usesTime = (this._uniforms[cc.UNIFORM_TIME] != null || this._uniforms[cc.UNIFORM_SINTIME] != null || this._uniforms[cc.UNIFORM_COSTIME] != null);
444 
445         this._uniforms[cc.UNIFORM_RANDOM01] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_RANDOM01_S);
446         this._uniforms[cc.UNIFORM_SAMPLER] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SAMPLER_S);
447 
448         this.use();
449         // Since sample most probably won't change, set it to 0 now.
450         this.setUniformLocationWith1i(this._uniforms[cc.UNIFORM_SAMPLER], 0);
451     },
452 
453     /**
454      * calls retrieves the named uniform location for this shader program.
455      * @param {String} name
456      * @returns {Number}
457      */
458     getUniformLocationForName:function(name){
459         if(!name)
460             throw "cc.GLProgram.getUniformLocationForName(): uniform name should be non-null";
461         if(!this._programObj)
462             throw "cc.GLProgram.getUniformLocationForName(): Invalid operation. Cannot get uniform location when program is not initialized";
463 
464         return this._glContext.getUniformLocation(this._programObj, name);
465     },
466 
467     getUniformMVPMatrix: function () {
468         return this._uniforms[cc.UNIFORM_MVPMATRIX];
469     },
470 
471     getUniformSampler: function () {
472         return this._uniforms[cc.UNIFORM_SAMPLER];
473     },
474 
475     /**
476      * calls glUniform1i only if the values are different than the previous call for this same shader program.
477      * @param {WebGLUniformLocation} location
478      * @param {Number} i1
479      */
480     setUniformLocationWith1i: function (location, i1) {
481         var updated = this._updateUniformLocation(location, i1);
482         if (updated)
483             this._glContext.uniform1i(location, i1);
484     },
485 
486     /**
487      * calls glUniform2i only if the values are different than the previous call for this same shader program.
488      * @param {WebGLUniformLocation} location
489      * @param {Number} i1
490      * @param {Number} i2
491      */
492     setUniformLocationWith2i:function(location, i1,i2){
493         var intArray= [i1,i2];
494         var updated =  this._updateUniformLocation(location, intArray);
495 
496         if( updated )
497             this._glContext.uniform2i(location, i1, i2);
498     },
499 
500     /**
501      * calls glUniform3i only if the values are different than the previous call for this same shader program.
502      * @param {WebGLUniformLocation} location
503      * @param {Number} i1
504      * @param {Number} i2
505      * @param {Number} i3
506      */
507     setUniformLocationWith3i:function(location, i1, i2, i3){
508         var intArray = [i1,i2,i3];
509         var updated =  this._updateUniformLocation(location, intArray);
510 
511         if( updated )
512             this._glContext.uniform3i(location, i1, i2, i3);
513     },
514 
515     /**
516      * calls glUniform4i only if the values are different than the previous call for this same shader program.
517      * @param {WebGLUniformLocation} location
518      * @param {Number} i1
519      * @param {Number} i2
520      * @param {Number} i3
521      * @param {Number} i4
522      */
523     setUniformLocationWith4i:function(location, i1, i2, i3, i4){
524         var intArray = [i1,i2,i3,i4];
525         var updated =  this._updateUniformLocation(location, intArray);
526 
527         if( updated )
528             this._glContext.uniform4i(location, i1, i2, i3, i4);
529     },
530 
531     /**
532      * calls glUniform2iv only if the values are different than the previous call for this same shader program.
533      * @param {WebGLUniformLocation} location
534      * @param {Int32Array} intArray
535      * @param {Number} numberOfArrays
536      */
537     setUniformLocationWith2iv:function(location, intArray, numberOfArrays){
538         var updated =  this._updateUniformLocation(location, intArray);
539 
540         if( updated )
541             this._glContext.uniform2iv(location, intArray);
542     },
543 
544     /**
545      * calls glUniform3iv only if the values are different than the previous call for this same shader program.
546      * @param {WebGLUniformLocation} location
547      * @param {Int32Array} intArray
548      * @param {Number} numberOfArrays
549      */
550     setUniformLocationWith3iv:function(location, intArray, numberOfArrays){
551         var updated =  this._updateUniformLocation(location, intArray);
552 
553         if( updated )
554             this._glContext.uniform3iv(location, intArray);
555     },
556 
557     /**
558      * calls glUniform4iv only if the values are different than the previous call for this same shader program.
559      * @param {WebGLUniformLocation} location
560      * @param {Int32Array} intArray
561      * @param {Number} numberOfArrays
562      */
563     setUniformLocationWith4iv:function(location, intArray, numberOfArrays){
564         var updated =  this._updateUniformLocation(location, intArray);
565 
566         if( updated )
567             this._glContext.uniform4iv(location, intArray);
568     },
569 
570     /**
571      * calls glUniform1i only if the values are different than the previous call for this same shader program.
572      * @param {WebGLUniformLocation} location
573      * @param {Number} i1
574      */
575     setUniformLocationI32: function (location, i1) {
576         this.setUniformLocationWith1i(arguments[0], arguments[1]);
577     },
578 
579     /**
580      * calls glUniform1f only if the values are different than the previous call for this same shader program.
581      * @param {WebGLUniformLocation} location
582      * @param {Number} f1
583      */
584     setUniformLocationWith1f: function (location, f1) {
585         var updated = this._updateUniformLocation(location, f1);
586         if (updated)
587             this._glContext.uniform1f(location, f1);
588     },
589 
590     /**
591      * calls glUniform2f only if the values are different than the previous call for this same shader program.
592      * @param {WebGLUniformLocation} location
593      * @param {Number} f1
594      * @param {Number} f2
595      */
596     setUniformLocationWith2f: function (location, f1, f2) {
597         var floats = [f1, f2];
598         var updated = this._updateUniformLocation(location, floats);
599         if (updated)
600             this._glContext.uniform2f(location, f1, f2);
601     },
602 
603     /**
604      * calls glUniform3f only if the values are different than the previous call for this same shader program.
605      * @param {WebGLUniformLocation} location
606      * @param {Number} f1
607      * @param {Number} f2
608      * @param {Number} f3
609      */
610     setUniformLocationWith3f: function (location, f1, f2, f3) {
611         var floats = [f1, f2, f3];
612         var updated = this._updateUniformLocation(location, floats);
613         if (updated)
614             this._glContext.uniform3f(location, f1, f2, f3);
615     },
616 
617     /**
618      * calls glUniform4f only if the values are different than the previous call for this same shader program.
619      * @param {WebGLUniformLocation} location
620      * @param {Number} f1
621      * @param {Number} f2
622      * @param {Number} f3
623      * @param {Number} f4
624      */
625     setUniformLocationWith4f: function (location, f1, f2, f3, f4) {
626         var floats = [f1, f2, f3, f4];
627         var updated = this._updateUniformLocation(location, floats);
628         if (updated)
629             this._glContext.uniform4f(location, f1, f2, f3, f4);
630     },
631 
632     /**
633      * calls glUniform2fv only if the values are different than the previous call for this same shader program.
634      * @param {WebGLUniformLocation} location
635      * @param {Float32Array} floatArray
636      * @param {Number} numberOfArrays
637      */
638     setUniformLocationWith2fv: function (location, floatArray, numberOfArrays) {
639         var updated = this._updateUniformLocation(location, floatArray);
640         if (updated)
641             this._glContext.uniform2fv(location, floatArray);
642     },
643 
644     /**
645      * calls glUniform3fv only if the values are different than the previous call for this same shader program.
646      * @param {WebGLUniformLocation} location
647      * @param {Float32Array} floatArray
648      * @param {Number} numberOfArrays
649      */
650     setUniformLocationWith3fv: function (location, floatArray, numberOfArrays) {
651         var updated = this._updateUniformLocation(location, floatArray);
652         if (updated)
653             this._glContext.uniform3fv(location, floatArray);
654     },
655 
656     /**
657      * calls glUniform4fv only if the values are different than the previous call for this same shader program.
658      * @param {WebGLUniformLocation} location
659      * @param {Float32Array} floatArray
660      * @param {Number} numberOfArrays
661      */
662     setUniformLocationWith4fv: function (location, floatArray, numberOfArrays) {
663         var updated = this._updateUniformLocation(location, floatArray);
664         if (updated)
665             this._glContext.uniform4fv(location, floatArray);
666     },
667 
668     /**
669      * calls glUniformMatrix4fv only if the values are different than the previous call for this same shader program.
670      * @param {WebGLUniformLocation} location
671      * @param {Float32Array} matrixArray
672      * @param {Number} numberOfMatrices
673      */
674     setUniformLocationWithMatrix4fv: function (location, matrixArray, numberOfMatrices) {
675         var updated = this._updateUniformLocation(location, matrixArray);
676         if (updated)
677             this._glContext.uniformMatrix4fv(location, false, matrixArray);
678     },
679 
680     setUniformLocationF32: function () {
681         if (arguments.length < 2)
682             return;
683 
684         switch (arguments.length) {
685             case 2:
686                 this.setUniformLocationWith1f(arguments[0], arguments[1]);
687                 break;
688             case 3:
689                 this.setUniformLocationWith2f(arguments[0], arguments[1], arguments[2]);
690                 break;
691             case 4:
692                 this.setUniformLocationWith3f(arguments[0], arguments[1], arguments[2], arguments[3]);
693                 break;
694             case 5:
695                 this.setUniformLocationWith4f(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
696                 break;
697         }
698     },
699 
700     /**
701      * will update the builtin uniforms if they are different than the previous call for this same shader program.
702      */
703     setUniformsForBuiltins: function () {
704         var matrixP = new cc.kmMat4();
705         var matrixMV = new cc.kmMat4();
706         var matrixMVP = new cc.kmMat4();
707 
708         cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP);
709         cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, matrixMV);
710 
711         cc.kmMat4Multiply(matrixMVP, matrixP, matrixMV);
712 
713         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], matrixP.mat, 1);
714         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], matrixMV.mat, 1);
715         this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], matrixMVP.mat, 1);
716 
717         if (this._usesTime) {
718             var director = cc.director;
719             // This doesn't give the most accurate global time value.
720             // Cocos2D doesn't store a high precision time value, so this will have to do.
721             // Getting Mach time per frame per shader using time could be extremely expensive.
722             var time = director.getTotalFrames() * director.getAnimationInterval();
723 
724             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME], time / 10.0, time, time * 2, time * 4);
725             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME], time / 8.0, time / 4.0, time / 2.0, Math.sin(time));
726             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME], time / 8.0, time / 4.0, time / 2.0, Math.cos(time));
727         }
728 
729         if (this._uniforms[cc.UNIFORM_RANDOM01] != -1)
730             this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01], Math.random(), Math.random(), Math.random(), Math.random());
731     },
732 
733     /**
734      * will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program.
735      */
736     setUniformForModelViewProjectionMatrix: function () {
737         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], false,
738             cc.getMat4MultiplyValue(cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top));
739     },
740 
741     setUniformForModelViewProjectionMatrixWithMat4: function (swapMat4) {
742         cc.kmMat4Multiply(swapMat4, cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top);
743         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], false, swapMat4.mat);
744     },
745 
746     setUniformForModelViewAndProjectionMatrixWithMat4: function () {
747         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], false, cc.modelview_matrix_stack.top.mat);
748         this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], false, cc.projection_matrix_stack.top.mat);
749     },
750 
751 
752     /**
753      * returns the vertexShader error log
754      * @return {String}
755      */
756     vertexShaderLog: function () {
757         return this._glContext.getShaderInfoLog(this._vertShader);
758     },
759 
760     /**
761      * returns the vertexShader error log
762      * @return {String}
763      */
764     getVertexShaderLog: function () {
765         return this._glContext.getShaderInfoLog(this._vertShader);
766     },
767 
768     /**
769      * returns the fragmentShader error log
770      * @returns {String}
771      */
772     getFragmentShaderLog: function () {
773         return this._glContext.getShaderInfoLog(this._vertShader);
774     },
775 
776     /**
777      * returns the fragmentShader error log
778      * @return {String}
779      */
780     fragmentShaderLog: function () {
781         return this._glContext.getShaderInfoLog(this._fragShader);
782     },
783 
784     /**
785      * returns the program error log
786      * @return {String}
787      */
788     programLog: function () {
789         return this._glContext.getProgramInfoLog(this._programObj);
790     },
791 
792     /**
793      * returns the program error log
794      * @return {String}
795      */
796     getProgramLog: function () {
797         return this._glContext.getProgramInfoLog(this._programObj);
798     },
799 
800     /**
801      *  reload all shaders, this function is designed for android  <br/>
802      *  when opengl context lost, so don't call it.
803      */
804     reset: function () {
805         this._vertShader = null;
806         this._fragShader = null;
807         this._uniforms.length = 0;
808 
809         // it is already deallocated by android
810         //ccGLDeleteProgram(m_uProgram);
811         this._glContext.deleteProgram(this._programObj);
812         this._programObj = null;
813 
814         // Purge uniform hash
815         for (var i = 0; i < this._hashForUniforms.length; i++) {
816             this._hashForUniforms[i].value = null;
817             this._hashForUniforms[i] = null;
818         }
819 
820         this._hashForUniforms.length = 0;
821     },
822 
823     /**
824      * get WebGLProgram object
825      * @return {WebGLProgram}
826      */
827     getProgram: function () {
828         return this._programObj;
829     },
830 
831     /**
832      * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
833      * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
834      * This is a hack, and should be removed once JSB fixes the retain/release bug
835      */
836     retain: function () {
837     },
838     release: function () {
839     }
840 });
841 
842 /**
843  * Create a cc.GLProgram object
844  * @param {String} vShaderFileName
845  * @param {String} fShaderFileName
846  * @returns {cc.GLProgram}
847  */
848 cc.GLProgram.create = function (vShaderFileName, fShaderFileName) {
849     var program = new cc.GLProgram();
850     if (program.init(vShaderFileName, fShaderFileName))
851         return program;
852     return null;
853 };
854