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 /** 30 * Class that implements a WebGL program 31 * @class 32 * @extends cc.Class 33 */ 34 cc.GLProgram = cc.Class.extend(/** @lends cc.GLProgram# */{ 35 _glContext: null, 36 _programObj: null, 37 _vertShader: null, 38 _fragShader: null, 39 _uniforms: null, 40 _hashForUniforms: null, 41 _usesTime: false, 42 43 // Uniform cache 44 _updateUniformLocation: function (location) { 45 if (!location) 46 return false; 47 48 var updated; 49 var element = this._hashForUniforms[location]; 50 51 if (!element) { 52 element = [ 53 arguments[1], 54 arguments[2], 55 arguments[3], 56 arguments[4] 57 ]; 58 this._hashForUniforms[location] = element; 59 updated = true; 60 } else { 61 updated = false; 62 var count = arguments.length-1; 63 for (var i = 0; i < count; ++i) { 64 if (arguments[i+1] !== element[i]) { 65 element[i] = arguments[i+1]; 66 updated = true; 67 } 68 } 69 } 70 71 return updated; 72 }, 73 74 _description: function () { 75 return "<CCGLProgram = " + this.toString() + " | Program = " + this._programObj.toString() + ", VertexShader = " + 76 this._vertShader.toString() + ", FragmentShader = " + this._fragShader.toString() + ">"; 77 }, 78 79 _compileShader: function (shader, type, source) { 80 if (!source || !shader) 81 return false; 82 83 var preStr = cc.GLProgram._isHighpSupported() ? "precision highp float;\n" : "precision mediump float;\n"; 84 source = preStr 85 + "uniform mat4 CC_PMatrix; \n" 86 + "uniform mat4 CC_MVMatrix; \n" 87 + "uniform mat4 CC_MVPMatrix; \n" 88 + "uniform vec4 CC_Time; \n" 89 + "uniform vec4 CC_SinTime; \n" 90 + "uniform vec4 CC_CosTime; \n" 91 + "uniform vec4 CC_Random01; \n" 92 + "uniform sampler2D CC_Texture0; \n" 93 + "//CC INCLUDES END \n" + source; 94 95 this._glContext.shaderSource(shader, source); 96 this._glContext.compileShader(shader); 97 var status = this._glContext.getShaderParameter(shader, this._glContext.COMPILE_STATUS); 98 99 if (!status) { 100 cc.log("cocos2d: ERROR: Failed to compile shader:\n" + this._glContext.getShaderSource(shader)); 101 if (type === this._glContext.VERTEX_SHADER) 102 cc.log("cocos2d: \n" + this.vertexShaderLog()); 103 else 104 cc.log("cocos2d: \n" + this.fragmentShaderLog()); 105 } 106 return ( status === true ); 107 }, 108 109 /** 110 * Create a cc.GLProgram object 111 * @param {String} vShaderFileName 112 * @param {String} fShaderFileName 113 * @returns {cc.GLProgram} 114 */ 115 ctor: function (vShaderFileName, fShaderFileName, glContext) { 116 this._uniforms = {}; 117 this._hashForUniforms = {}; 118 this._glContext = glContext || cc._renderContext; 119 120 vShaderFileName && fShaderFileName && this.init(vShaderFileName, fShaderFileName); 121 }, 122 123 /** 124 * destroy program 125 */ 126 destroyProgram: function () { 127 this._vertShader = null; 128 this._fragShader = null; 129 this._uniforms = null; 130 this._hashForUniforms = null; 131 132 this._glContext.deleteProgram(this._programObj); 133 }, 134 135 /** 136 * Initializes the cc.GLProgram with a vertex and fragment with string 137 * @param {String} vertShaderStr 138 * @param {String} fragShaderStr 139 * @return {Boolean} 140 */ 141 initWithVertexShaderByteArray: function (vertShaderStr, fragShaderStr) { 142 var locGL = this._glContext; 143 this._programObj = locGL.createProgram(); 144 //cc.checkGLErrorDebug(); 145 146 this._vertShader = null; 147 this._fragShader = null; 148 149 if (vertShaderStr) { 150 this._vertShader = locGL.createShader(locGL.VERTEX_SHADER); 151 if (!this._compileShader(this._vertShader, locGL.VERTEX_SHADER, vertShaderStr)) { 152 cc.log("cocos2d: ERROR: Failed to compile vertex shader"); 153 } 154 } 155 156 // Create and compile fragment shader 157 if (fragShaderStr) { 158 this._fragShader = locGL.createShader(locGL.FRAGMENT_SHADER); 159 if (!this._compileShader(this._fragShader, locGL.FRAGMENT_SHADER, fragShaderStr)) { 160 cc.log("cocos2d: ERROR: Failed to compile fragment shader"); 161 } 162 } 163 164 if (this._vertShader) 165 locGL.attachShader(this._programObj, this._vertShader); 166 cc.checkGLErrorDebug(); 167 168 if (this._fragShader) 169 locGL.attachShader(this._programObj, this._fragShader); 170 171 for (var key in this._hashForUniforms) { 172 delete this._hashForUniforms[key]; 173 } 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 new Error("Please load the resource firset : " + vShaderFilename); 198 var fragmentSource = cc.loader.getRes(fShaderFileName); 199 if(!fragmentSource) throw new Error("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_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_PMATRIX_S); 271 this._uniforms[cc.UNIFORM_MVMATRIX_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVMATRIX_S); 272 this._uniforms[cc.UNIFORM_MVPMATRIX_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_MVPMATRIX_S); 273 this._uniforms[cc.UNIFORM_TIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_TIME_S); 274 this._uniforms[cc.UNIFORM_SINTIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_SINTIME_S); 275 this._uniforms[cc.UNIFORM_COSTIME_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_COSTIME_S); 276 277 this._usesTime = (this._uniforms[cc.UNIFORM_TIME_S] != null || this._uniforms[cc.UNIFORM_SINTIME_S] != null || this._uniforms[cc.UNIFORM_COSTIME_S] != null); 278 279 this._uniforms[cc.UNIFORM_RANDOM01_S] = this._glContext.getUniformLocation(this._programObj, cc.UNIFORM_RANDOM01_S); 280 this._uniforms[cc.UNIFORM_SAMPLER_S] = 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_S], 0); 285 }, 286 287 _addUniformLocation: function (name) { 288 var location = this._glContext.getUniformLocation(this._programObj, name); 289 this._uniforms[name] = location; 290 }, 291 292 /** 293 * calls retrieves the named uniform location for this shader program. 294 * @param {String} name 295 * @returns {Number} 296 */ 297 getUniformLocationForName: function (name) { 298 if (!name) 299 throw new Error("cc.GLProgram.getUniformLocationForName(): uniform name should be non-null"); 300 if (!this._programObj) 301 throw new Error("cc.GLProgram.getUniformLocationForName(): Invalid operation. Cannot get uniform location when program is not initialized"); 302 303 var location = this._uniforms[name] || this._glContext.getUniformLocation(this._programObj, name); 304 return location; 305 }, 306 307 /** 308 * get uniform MVP matrix 309 * @returns {WebGLUniformLocation} 310 */ 311 getUniformMVPMatrix: function () { 312 return this._uniforms[cc.UNIFORM_MVPMATRIX_S]; 313 }, 314 315 /** 316 * get uniform sampler 317 * @returns {WebGLUniformLocation} 318 */ 319 getUniformSampler: function () { 320 return this._uniforms[cc.UNIFORM_SAMPLER_S]; 321 }, 322 323 /** 324 * calls glUniform1i only if the values are different than the previous call for this same shader program. 325 * @param {WebGLUniformLocation|String} location 326 * @param {Number} i1 327 */ 328 setUniformLocationWith1i: function (location, i1) { 329 var gl = this._glContext; 330 if (typeof location === 'string') { 331 var updated = this._updateUniformLocation(location, i1); 332 if (updated) { 333 var locObj = this.getUniformLocationForName(location); 334 gl.uniform1i(locObj, i1); 335 } 336 } 337 else { 338 gl.uniform1i(location, i1); 339 } 340 }, 341 342 /** 343 * calls glUniform2i only if the values are different than the previous call for this same shader program. 344 * @param {WebGLUniformLocation|String} location 345 * @param {Number} i1 346 * @param {Number} i2 347 */ 348 setUniformLocationWith2i: function (location, i1, i2) { 349 var gl = this._glContext; 350 if (typeof location === 'string') { 351 var updated = this._updateUniformLocation(location, i1, i2); 352 if (updated) { 353 var locObj = this.getUniformLocationForName(location); 354 gl.uniform2i(locObj, i1, i2); 355 } 356 } 357 else { 358 gl.uniform2i(location, i1, i2); 359 } 360 }, 361 362 /** 363 * calls glUniform3i only if the values are different than the previous call for this same shader program. 364 * @param {WebGLUniformLocation|String} location 365 * @param {Number} i1 366 * @param {Number} i2 367 * @param {Number} i3 368 */ 369 setUniformLocationWith3i: function (location, i1, i2, i3) { 370 var gl = this._glContext; 371 if (typeof location === 'string') { 372 var updated = this._updateUniformLocation(location, i1, i2, i3); 373 if (updated) { 374 var locObj = this.getUniformLocationForName(location); 375 gl.uniform3i(locObj, i1, i2, i3); 376 } 377 } 378 else { 379 gl.uniform3i(location, i1, i2, i3); 380 } 381 }, 382 383 /** 384 * calls glUniform4i only if the values are different than the previous call for this same shader program. 385 * @param {WebGLUniformLocation|String} location 386 * @param {Number} i1 387 * @param {Number} i2 388 * @param {Number} i3 389 * @param {Number} i4 390 */ 391 setUniformLocationWith4i: function (location, i1, i2, i3, i4) { 392 var gl = this._glContext; 393 if (typeof location === 'string') { 394 var updated = this._updateUniformLocation(location, i1, i2, i3, i4); 395 if (updated) { 396 var locObj = this.getUniformLocationForName(location); 397 gl.uniform4i(locObj, i1, i2, i3, i4); 398 } 399 } 400 else { 401 gl.uniform4i(location, i1, i2, i3, i4); 402 } 403 }, 404 405 /** 406 * calls glUniform2iv 407 * @param {WebGLUniformLocation|String} location 408 * @param {Int32Array} intArray 409 * @param {Number} numberOfArrays 410 */ 411 setUniformLocationWith2iv: function (location, intArray) { 412 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 413 this._glContext.uniform2iv(locObj, intArray); 414 }, 415 416 /** 417 * calls glUniform3iv 418 * @param {WebGLUniformLocation|String} location 419 * @param {Int32Array} intArray 420 */ 421 setUniformLocationWith3iv:function(location, intArray){ 422 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 423 this._glContext.uniform3iv(locObj, intArray); 424 }, 425 426 /** 427 * calls glUniform4iv 428 * @param {WebGLUniformLocation|String} location 429 * @param {Int32Array} intArray 430 */ 431 setUniformLocationWith4iv:function(location, intArray){ 432 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 433 this._glContext.uniform4iv(locObj, intArray); 434 }, 435 436 /** 437 * calls glUniform1i only if the values are different than the previous call for this same shader program. 438 * @param {WebGLUniformLocation|String} location 439 * @param {Number} i1 440 */ 441 setUniformLocationI32: function (location, i1) { 442 this.setUniformLocationWith1i(location, i1); 443 }, 444 445 /** 446 * calls glUniform1f only if the values are different than the previous call for this same shader program. 447 * @param {WebGLUniformLocation|String} location 448 * @param {Number} f1 449 */ 450 setUniformLocationWith1f: function (location, f1) { 451 var gl = this._glContext; 452 if (typeof location === 'string') { 453 var updated = this._updateUniformLocation(location, f1); 454 if (updated) { 455 var locObj = this.getUniformLocationForName(location); 456 gl.uniform1f(locObj, f1); 457 } 458 } 459 else { 460 gl.uniform1f(location, f1); 461 } 462 }, 463 464 /** 465 * calls glUniform2f only if the values are different than the previous call for this same shader program. 466 * @param {WebGLUniformLocation|String} location 467 * @param {Number} f1 468 * @param {Number} f2 469 */ 470 setUniformLocationWith2f: function (location, f1, f2) { 471 var gl = this._glContext; 472 if (typeof location === 'string') { 473 var updated = this._updateUniformLocation(location, f1, f2); 474 if (updated) { 475 var locObj = this.getUniformLocationForName(location); 476 gl.uniform2f(locObj, f1, f2); 477 } 478 } 479 else { 480 gl.uniform2f(location, f1, f2); 481 } 482 }, 483 484 /** 485 * calls glUniform3f only if the values are different than the previous call for this same shader program. 486 * @param {WebGLUniformLocation|String} location 487 * @param {Number} f1 488 * @param {Number} f2 489 * @param {Number} f3 490 */ 491 setUniformLocationWith3f: function (location, f1, f2, f3) { 492 var gl = this._glContext; 493 if (typeof location === 'string') { 494 var updated = this._updateUniformLocation(location, f1, f2, f3); 495 if (updated) { 496 var locObj = this.getUniformLocationForName(location); 497 gl.uniform3f(locObj, f1, f2, f3); 498 } 499 } 500 else { 501 gl.uniform3f(location, f1, f2, f3); 502 } 503 }, 504 505 /** 506 * calls glUniform4f only if the values are different than the previous call for this same shader program. 507 * @param {WebGLUniformLocation|String} location 508 * @param {Number} f1 509 * @param {Number} f2 510 * @param {Number} f3 511 * @param {Number} f4 512 */ 513 setUniformLocationWith4f: function (location, f1, f2, f3, f4) { 514 var gl = this._glContext; 515 if (typeof location === 'string') { 516 var updated = this._updateUniformLocation(location, f1, f2, f3, f4); 517 if (updated) { 518 var locObj = this.getUniformLocationForName(location); 519 gl.uniform4f(locObj, f1, f2, f3, f4); 520 } 521 } 522 else { 523 gl.uniform4f(location, f1, f2, f3, f4); 524 } 525 }, 526 527 /** 528 * calls glUniform2fv 529 * @param {WebGLUniformLocation|String} location 530 * @param {Float32Array} floatArray 531 */ 532 setUniformLocationWith2fv: function (location, floatArray) { 533 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 534 this._glContext.uniform2fv(locObj, floatArray); 535 }, 536 537 /** 538 * calls glUniform3fv 539 * @param {WebGLUniformLocation|String} location 540 * @param {Float32Array} floatArray 541 */ 542 setUniformLocationWith3fv: function (location, floatArray) { 543 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 544 this._glContext.uniform3fv(locObj, floatArray); 545 }, 546 547 /** 548 * calls glUniform4fv 549 * @param {WebGLUniformLocation|String} location 550 * @param {Float32Array} floatArray 551 */ 552 setUniformLocationWith4fv: function (location, floatArray) { 553 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 554 this._glContext.uniform4fv(locObj, floatArray); 555 }, 556 557 /** 558 * calls glUniformMatrix4fv 559 * @param {WebGLUniformLocation|String} location 560 * @param {Float32Array} matrixArray 561 */ 562 setUniformLocationWithMatrix4fv: function (location, matrixArray) { 563 var locObj = typeof location === 'string' ? this.getUniformLocationForName(location) : location; 564 this._glContext.uniformMatrix4fv(locObj, false, matrixArray); 565 }, 566 567 setUniformLocationF32: function () { 568 if (arguments.length < 2) 569 return; 570 571 switch (arguments.length) { 572 case 2: 573 this.setUniformLocationWith1f(arguments[0], arguments[1]); 574 break; 575 case 3: 576 this.setUniformLocationWith2f(arguments[0], arguments[1], arguments[2]); 577 break; 578 case 4: 579 this.setUniformLocationWith3f(arguments[0], arguments[1], arguments[2], arguments[3]); 580 break; 581 case 5: 582 this.setUniformLocationWith4f(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); 583 break; 584 } 585 }, 586 587 /** 588 * will update the builtin uniforms if they are different than the previous call for this same shader program. 589 */ 590 setUniformsForBuiltins: function () { 591 var matrixP = new cc.math.Matrix4(); 592 var matrixMV = new cc.math.Matrix4(); 593 var matrixMVP = new cc.math.Matrix4(); 594 595 cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP); 596 cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, matrixMV); 597 598 cc.kmMat4Multiply(matrixMVP, matrixP, matrixMV); 599 600 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], matrixP.mat, 1); 601 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], matrixMV.mat, 1); 602 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], matrixMVP.mat, 1); 603 604 if (this._usesTime) { 605 var director = cc.director; 606 // This doesn't give the most accurate global time value. 607 // Cocos2D doesn't store a high precision time value, so this will have to do. 608 // Getting Mach time per frame per shader using time could be extremely expensive. 609 var time = director.getTotalFrames() * director.getAnimationInterval(); 610 611 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME_S], time / 10.0, time, time * 2, time * 4); 612 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.sin(time)); 613 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.cos(time)); 614 } 615 616 if (this._uniforms[cc.UNIFORM_RANDOM01_S] !== -1) 617 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01_S], Math.random(), Math.random(), Math.random(), Math.random()); 618 }, 619 620 _setUniformsForBuiltinsForRenderer: function (node) { 621 if(!node || !node._renderCmd) 622 return; 623 624 var matrixP = new cc.math.Matrix4(); 625 //var matrixMV = new cc.kmMat4(); 626 var matrixMVP = new cc.math.Matrix4(); 627 628 cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP); 629 //cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, node._stackMatrix); 630 631 cc.kmMat4Multiply(matrixMVP, matrixP, node._renderCmd._stackMatrix); 632 633 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], matrixP.mat, 1); 634 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], node._renderCmd._stackMatrix.mat, 1); 635 this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], matrixMVP.mat, 1); 636 637 if (this._usesTime) { 638 var director = cc.director; 639 // This doesn't give the most accurate global time value. 640 // Cocos2D doesn't store a high precision time value, so this will have to do. 641 // Getting Mach time per frame per shader using time could be extremely expensive. 642 var time = director.getTotalFrames() * director.getAnimationInterval(); 643 644 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME_S], time / 10.0, time, time * 2, time * 4); 645 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.sin(time)); 646 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME_S], time / 8.0, time / 4.0, time / 2.0, Math.cos(time)); 647 } 648 649 if (this._uniforms[cc.UNIFORM_RANDOM01_S] !== -1) 650 this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01_S], Math.random(), Math.random(), Math.random(), Math.random()); 651 }, 652 653 /** 654 * will update the MVP matrix on the MVP uniform if it is different than the previous call for this same shader program. 655 */ 656 setUniformForModelViewProjectionMatrix: function () { 657 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], false, 658 cc.getMat4MultiplyValue(cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top)); 659 }, 660 661 setUniformForModelViewProjectionMatrixWithMat4: function (swapMat4) { 662 cc.kmMat4Multiply(swapMat4, cc.projection_matrix_stack.top, cc.modelview_matrix_stack.top); 663 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX_S], false, swapMat4.mat); 664 }, 665 666 setUniformForModelViewAndProjectionMatrixWithMat4: function () { 667 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], false, cc.modelview_matrix_stack.top.mat); 668 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat); 669 }, 670 671 _setUniformForMVPMatrixWithMat4: function(modelViewMatrix){ 672 if(!modelViewMatrix) 673 throw new Error("modelView matrix is undefined."); 674 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX_S], false, modelViewMatrix.mat); 675 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat); 676 }, 677 678 _updateProjectionUniform: function(){ 679 this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX_S], false, cc.projection_matrix_stack.top.mat); 680 }, 681 682 /** 683 * returns the vertexShader error log 684 * @return {String} 685 */ 686 vertexShaderLog: function () { 687 return this._glContext.getShaderInfoLog(this._vertShader); 688 }, 689 690 /** 691 * returns the vertexShader error log 692 * @return {String} 693 */ 694 getVertexShaderLog: function () { 695 return this._glContext.getShaderInfoLog(this._vertShader); 696 }, 697 698 /** 699 * returns the fragmentShader error log 700 * @returns {String} 701 */ 702 getFragmentShaderLog: function () { 703 return this._glContext.getShaderInfoLog(this._vertShader); 704 }, 705 706 /** 707 * returns the fragmentShader error log 708 * @return {String} 709 */ 710 fragmentShaderLog: function () { 711 return this._glContext.getShaderInfoLog(this._fragShader); 712 }, 713 714 /** 715 * returns the program error log 716 * @return {String} 717 */ 718 programLog: function () { 719 return this._glContext.getProgramInfoLog(this._programObj); 720 }, 721 722 /** 723 * returns the program error log 724 * @return {String} 725 */ 726 getProgramLog: function () { 727 return this._glContext.getProgramInfoLog(this._programObj); 728 }, 729 730 /** 731 * reload all shaders, this function is designed for android <br/> 732 * when opengl context lost, so don't call it. 733 */ 734 reset: function () { 735 this._vertShader = null; 736 this._fragShader = null; 737 this._uniforms.length = 0; 738 739 // it is already deallocated by android 740 //ccGLDeleteProgram(m_uProgram); 741 this._glContext.deleteProgram(this._programObj); 742 this._programObj = null; 743 744 // Purge uniform hash 745 for (var key in this._hashForUniforms) { 746 delete this._hashForUniforms[key]; 747 } 748 }, 749 750 /** 751 * get WebGLProgram object 752 * @return {WebGLProgram} 753 */ 754 getProgram: function () { 755 return this._programObj; 756 }, 757 758 /** 759 * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, 760 * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. 761 * This is a hack, and should be removed once JSB fixes the retain/release bug 762 */ 763 retain: function () { 764 }, 765 release: function () { 766 } 767 }); 768 769 /** 770 * Create a cc.GLProgram object 771 * @deprecated since v3.0, please use new cc.GLProgram(vShaderFileName, fShaderFileName) instead 772 * @param {String} vShaderFileName 773 * @param {String} fShaderFileName 774 * @returns {cc.GLProgram} 775 */ 776 cc.GLProgram.create = function (vShaderFileName, fShaderFileName) { 777 return new cc.GLProgram(vShaderFileName, fShaderFileName); 778 }; 779 780 cc.GLProgram._highpSupported = null; 781 782 cc.GLProgram._isHighpSupported = function(){ 783 if(cc.GLProgram._highpSupported == null){ 784 var ctx = cc._renderContext; 785 var highp = ctx.getShaderPrecisionFormat(ctx.FRAGMENT_SHADER, ctx.HIGH_FLOAT); 786 cc.GLProgram._highpSupported = highp.precision !== 0; 787 } 788 return cc.GLProgram._highpSupported; 789 }; 790 791 /** 792 * <p> 793 * Sets the shader program for this node 794 * 795 * Since v2.0, each rendering node must set its shader program. 796 * It should be set in initialize phase. 797 * </p> 798 * @function 799 * @param {cc.Node} node 800 * @param {cc.GLProgram} program The shader program which fetches from CCShaderCache. 801 * @example 802 * cc.setGLProgram(node, cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); 803 */ 804 cc.setProgram = function (node, program) { 805 node.shaderProgram = program; 806 807 var children = node.children; 808 if (!children) 809 return; 810 811 for (var i = 0; i < children.length; i++) 812 cc.setProgram(children[i], program); 813 }; 814