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