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