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 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 //CONSTANTS: 28 29 /** 30 * Horizontal center and vertical center. 31 * @constant 32 * @type Number 33 */ 34 cc.ALIGN_CENTER = 0x33; 35 36 /** 37 * Horizontal center and vertical top. 38 * @constant 39 * @type Number 40 */ 41 cc.ALIGN_TOP = 0x13; 42 43 /** 44 * Horizontal right and vertical top. 45 * @constant 46 * @type Number 47 */ 48 cc.ALIGN_TOP_RIGHT = 0x12; 49 50 /** 51 * Horizontal right and vertical center. 52 * @constant 53 * @type Number 54 */ 55 cc.ALIGN_RIGHT = 0x32; 56 57 /** 58 * Horizontal right and vertical bottom. 59 * @constant 60 * @type Number 61 */ 62 cc.ALIGN_BOTTOM_RIGHT = 0x22; 63 64 /** 65 * Horizontal center and vertical bottom. 66 * @constant 67 * @type Number 68 */ 69 cc.ALIGN_BOTTOM = 0x23; 70 71 /** 72 * Horizontal left and vertical bottom. 73 * @constant 74 * @type Number 75 */ 76 cc.ALIGN_BOTTOM_LEFT = 0x21; 77 78 /** 79 * Horizontal left and vertical center. 80 * @constant 81 * @type Number 82 */ 83 cc.ALIGN_LEFT = 0x31; 84 85 /** 86 * Horizontal left and vertical top. 87 * @constant 88 * @type Number 89 */ 90 cc.ALIGN_TOP_LEFT = 0x11; 91 //----------------------Possible texture pixel formats---------------------------- 92 93 94 // By default PVR images are treated as if they don't have the alpha channel premultiplied 95 cc.PVRHaveAlphaPremultiplied_ = false; 96 97 //cc.Texture2DWebGL move to TextureWebGL.js 98 99 cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { 100 101 if(cc._renderType === cc.game.RENDER_TYPE_CANVAS) { 102 103 var proto = { 104 _contentSize: null, 105 _textureLoaded: false, 106 _htmlElementObj: null, 107 url: null, 108 _pattern: null, 109 110 ctor: function () { 111 this._contentSize = cc.size(0, 0); 112 this._textureLoaded = false; 113 this._htmlElementObj = null; 114 this._pattern = ""; 115 }, 116 117 /** 118 * get width in pixels 119 * @return {Number} 120 */ 121 getPixelsWide: function () { 122 return this._contentSize.width; 123 }, 124 125 /** 126 * get height of in pixels 127 * @return {Number} 128 */ 129 getPixelsHigh: function () { 130 return this._contentSize.height; 131 }, 132 133 /** 134 * get content size 135 * @returns {cc.Size} 136 */ 137 getContentSize: function () { 138 var locScaleFactor = cc.contentScaleFactor(); 139 return cc.size(this._contentSize.width / locScaleFactor, this._contentSize.height / locScaleFactor); 140 }, 141 142 _getWidth: function () { 143 return this._contentSize.width / cc.contentScaleFactor(); 144 }, 145 _getHeight: function () { 146 return this._contentSize.height / cc.contentScaleFactor(); 147 }, 148 149 /** 150 * get content size in pixels 151 * @returns {cc.Size} 152 */ 153 getContentSizeInPixels: function () { 154 return this._contentSize; 155 }, 156 157 /** 158 * init with HTML element 159 * @param {HTMLImageElement|HTMLCanvasElement} element 160 */ 161 initWithElement: function (element) { 162 if (!element) 163 return; 164 this._htmlElementObj = element; 165 this._contentSize.width = element.width; 166 this._contentSize.height = element.height; 167 this._textureLoaded = true; 168 }, 169 170 /** 171 * HTMLElement Object getter 172 * @return {HTMLImageElement|HTMLCanvasElement} 173 */ 174 getHtmlElementObj: function () { 175 return this._htmlElementObj; 176 }, 177 178 /** 179 * check whether texture is loaded 180 * @returns {boolean} 181 */ 182 isLoaded: function () { 183 return this._textureLoaded; 184 }, 185 186 /** 187 * handle loaded texture 188 */ 189 handleLoadedTexture: function () { 190 var self = this; 191 if (self._textureLoaded) return; 192 if (!self._htmlElementObj) { 193 var img = cc.loader.getRes(self.url); 194 if (!img) return; 195 self.initWithElement(img); 196 } 197 198 var locElement = self._htmlElementObj; 199 self._contentSize.width = locElement.width; 200 self._contentSize.height = locElement.height; 201 202 //dispatch load event to listener. 203 self.dispatchEvent("load"); 204 }, 205 206 /** 207 * description of cc.Texture2D 208 * @returns {string} 209 */ 210 description: function () { 211 return "<cc.Texture2D | width = " + this._contentSize.width + " height " + this._contentSize.height + ">"; 212 }, 213 214 initWithData: function (data, pixelFormat, pixelsWide, pixelsHigh, contentSize) { 215 //support only in WebGl rendering mode 216 return false; 217 }, 218 219 initWithImage: function (uiImage) { 220 //support only in WebGl rendering mode 221 return false; 222 }, 223 224 initWithString: function (text, fontName, fontSize, dimensions, hAlignment, vAlignment) { 225 //support only in WebGl rendering mode 226 return false; 227 }, 228 229 releaseTexture: function () { 230 cc.loader.release(this.url); 231 }, 232 233 getName: function () { 234 //support only in WebGl rendering mode 235 return null; 236 }, 237 238 getMaxS: function () { 239 //support only in WebGl rendering mode 240 return 1; 241 }, 242 243 setMaxS: function (maxS) { 244 //support only in WebGl rendering mode 245 }, 246 247 getMaxT: function () { 248 return 1; 249 }, 250 251 setMaxT: function (maxT) { 252 //support only in WebGl rendering mode 253 }, 254 255 getPixelFormat: function () { 256 //support only in WebGl rendering mode 257 return null; 258 }, 259 260 getShaderProgram: function () { 261 //support only in WebGl rendering mode 262 return null; 263 }, 264 265 setShaderProgram: function (shaderProgram) { 266 //support only in WebGl rendering mode 267 }, 268 269 hasPremultipliedAlpha: function () { 270 //support only in WebGl rendering mode 271 return false; 272 }, 273 274 hasMipmaps: function () { 275 //support only in WebGl rendering mode 276 return false; 277 }, 278 279 releaseData: function (data) { 280 //support only in WebGl rendering mode 281 data = null; 282 }, 283 284 keepData: function (data, length) { 285 //support only in WebGl rendering mode 286 return data; 287 }, 288 289 drawAtPoint: function (point) { 290 //support only in WebGl rendering mode 291 }, 292 293 drawInRect: function (rect) { 294 //support only in WebGl rendering mode 295 }, 296 297 /** 298 * init with ETC file 299 * @warning does not support on HTML5 300 */ 301 initWithETCFile: function (file) { 302 cc.log(cc._LogInfos.Texture2D_initWithETCFile); 303 return false; 304 }, 305 306 /** 307 * init with PVR file 308 * @warning does not support on HTML5 309 */ 310 initWithPVRFile: function (file) { 311 cc.log(cc._LogInfos.Texture2D_initWithPVRFile); 312 return false; 313 }, 314 315 /** 316 * init with PVRTC data 317 * @warning does not support on HTML5 318 */ 319 initWithPVRTCData: function (data, level, bpp, hasAlpha, length, pixelFormat) { 320 cc.log(cc._LogInfos.Texture2D_initWithPVRTCData); 321 return false; 322 }, 323 324 setTexParameters: function (texParams, magFilter, wrapS, wrapT) { 325 if(magFilter !== undefined) 326 texParams = {minFilter: texParams, magFilter: magFilter, wrapS: wrapS, wrapT: wrapT}; 327 328 if(texParams.wrapS === cc.REPEAT && texParams.wrapT === cc.REPEAT){ 329 this._pattern = "repeat"; 330 return; 331 } 332 333 if(texParams.wrapS === cc.REPEAT ){ 334 this._pattern = "repeat-x"; 335 return; 336 } 337 338 if(texParams.wrapT === cc.REPEAT){ 339 this._pattern = "repeat-y"; 340 return; 341 } 342 343 this._pattern = ""; 344 }, 345 346 setAntiAliasTexParameters: function () { 347 //support only in WebGl rendering mode 348 }, 349 350 setAliasTexParameters: function () { 351 //support only in WebGl rendering mode 352 }, 353 354 generateMipmap: function () { 355 //support only in WebGl rendering mode 356 }, 357 358 stringForFormat: function () { 359 //support only in WebGl rendering mode 360 return ""; 361 }, 362 363 bitsPerPixelForFormat: function (format) { 364 //support only in WebGl rendering mode 365 return -1; 366 }, 367 368 /** 369 * add listener for loaded event 370 * @param {Function} callback 371 * @param {cc.Node} target 372 * @deprecated since 3.1, please use addEventListener instead 373 */ 374 addLoadedEventListener: function (callback, target) { 375 this.addEventListener("load", callback, target); 376 }, 377 378 /** 379 * remove listener from listeners by target 380 * @param {cc.Node} target 381 */ 382 removeLoadedEventListener: function (target) { 383 this.removeEventListener("load", target); 384 }, 385 386 _generateColorTexture: function(){/*overide*/}, 387 _generateTextureCacheForColor: function(){ 388 if (this.channelCache) 389 return this.channelCache; 390 391 var textureCache = [ 392 document.createElement("canvas"), 393 document.createElement("canvas"), 394 document.createElement("canvas"), 395 document.createElement("canvas") 396 ]; 397 //todo texture onload 398 renderToCache(this._htmlElementObj, textureCache); 399 return this.channelCache = textureCache; 400 }, 401 402 //hack for gray effect 403 _grayElementObj: null, 404 _backupElement: null, 405 _isGray: false, 406 _switchToGray: function(toGray){ 407 if(!this._textureLoaded || this._isGray === toGray) 408 return; 409 this._isGray = toGray; 410 if(this._isGray){ 411 this._backupElement = this._htmlElementObj; 412 if(!this._grayElementObj) 413 this._grayElementObj = cc.Texture2D._generateGrayTexture(this._htmlElementObj); 414 this._htmlElementObj = this._grayElementObj; 415 } else { 416 if(this._backupElement !== null) 417 this._htmlElementObj = this._backupElement; 418 } 419 } 420 }; 421 422 var renderToCache = function(image, cache){ 423 var w = image.width; 424 var h = image.height; 425 426 cache[0].width = w; 427 cache[0].height = h; 428 cache[1].width = w; 429 cache[1].height = h; 430 cache[2].width = w; 431 cache[2].height = h; 432 cache[3].width = w; 433 cache[3].height = h; 434 435 var cacheCtx = cache[3].getContext("2d"); 436 cacheCtx.drawImage(image, 0, 0); 437 var pixels = cacheCtx.getImageData(0, 0, w, h).data; 438 439 var ctx; 440 for (var rgbI = 0; rgbI < 4; rgbI++) { 441 ctx = cache[rgbI].getContext("2d"); 442 443 var to = ctx.getImageData(0, 0, w, h); 444 var data = to.data; 445 for (var i = 0; i < pixels.length; i += 4) { 446 data[i ] = (rgbI === 0) ? pixels[i ] : 0; 447 data[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0; 448 data[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0; 449 data[i + 3] = pixels[i + 3]; 450 } 451 ctx.putImageData(to, 0, 0); 452 } 453 image.onload = null; 454 }; 455 456 //change color function 457 if(cc.sys._supportCanvasNewBlendModes){ 458 //multiply mode 459 //Primary afferent, Draw a new texture based on rect 460 proto._generateColorTexture = function(r, g, b, rect, canvas){ 461 var onlyCanvas = false; 462 if(canvas) 463 onlyCanvas = true; 464 else 465 canvas = document.createElement("canvas"); 466 var textureImage = this._htmlElementObj; 467 if(!rect) 468 rect = cc.rect(0, 0, textureImage.width, textureImage.height); 469 470 canvas.width = rect.width; 471 canvas.height = rect.height; 472 473 var context = canvas.getContext("2d"); 474 context.globalCompositeOperation = "source-over"; 475 context.fillStyle = "rgb(" + (r|0) + "," + (g|0) + "," + (b|0) + ")"; 476 context.fillRect(0, 0, rect.width, rect.height); 477 context.globalCompositeOperation = "multiply"; 478 context.drawImage( 479 textureImage, 480 rect.x, rect.y, rect.width, rect.height, 481 0, 0, rect.width, rect.height 482 ); 483 context.globalCompositeOperation = "destination-atop"; 484 context.drawImage( 485 textureImage, 486 rect.x, rect.y, rect.width, rect.height, 487 0, 0, rect.width, rect.height 488 ); 489 if(onlyCanvas) 490 return canvas; 491 var newTexture = new cc.Texture2D(); 492 newTexture.initWithElement(canvas); 493 newTexture.handleLoadedTexture(); 494 return newTexture; 495 }; 496 }else{ 497 //Four color map overlay 498 proto._generateColorTexture = function(r, g, b, rect, canvas){ 499 var onlyCanvas = false; 500 if(canvas) 501 onlyCanvas = true; 502 else 503 canvas = document.createElement("canvas"); 504 505 var textureImage = this._htmlElementObj; 506 if(!rect) 507 rect = cc.rect(0, 0, textureImage.width, textureImage.height); 508 var x, y, w, h; 509 x = rect.x; y = rect.y; w = rect.width; h = rect.height; 510 if(!w || !h) 511 return; 512 513 canvas.width = w; 514 canvas.height = h; 515 516 var context = canvas.getContext("2d"); 517 var tintedImgCache = cc.textureCache.getTextureColors(this); 518 context.globalCompositeOperation = 'lighter'; 519 context.drawImage( 520 tintedImgCache[3], 521 x, y, w, h, 522 0, 0, w, h 523 ); 524 if (r > 0) { 525 context.globalAlpha = r / 255; 526 context.drawImage( 527 tintedImgCache[0], 528 x, y, w, h, 529 0, 0, w, h 530 ); 531 } 532 if (g > 0) { 533 context.globalAlpha = g / 255; 534 context.drawImage( 535 tintedImgCache[1], 536 x, y, w, h, 537 0, 0, w, h 538 ); 539 } 540 if (b > 0) { 541 context.globalAlpha = b / 255; 542 context.drawImage( 543 tintedImgCache[2], 544 x, y, w, h, 545 0, 0, w, h 546 ); 547 } 548 if(onlyCanvas) 549 return canvas; 550 551 var newTexture = new cc.Texture2D(); 552 newTexture.initWithElement(canvas); 553 newTexture.handleLoadedTexture(); 554 return newTexture; 555 }; 556 } 557 558 /** 559 * <p> 560 * This class allows to easily create OpenGL or Canvas 2D textures from images, text or raw data. <br/> 561 * The created cc.Texture2D object will always have power-of-two dimensions. <br/> 562 * Depending on how you create the cc.Texture2D object, the actual image area of the texture might be smaller than the texture dimensions <br/> 563 * i.e. "contentSize" != (pixelsWide, pixelsHigh) and (maxS, maxT) != (1.0, 1.0). <br/> 564 * Be aware that the content of the generated textures will be upside-down! </p> 565 * @name cc.Texture2D 566 * @class 567 * @extends cc.Class 568 * 569 * @property {WebGLTexture} name - <@readonly> WebGLTexture Object 570 * @property {Number} pixelFormat - <@readonly> Pixel format of the texture 571 * @property {Number} pixelsWidth - <@readonly> Width in pixels 572 * @property {Number} pixelsHeight - <@readonly> Height in pixels 573 * @property {Number} width - Content width in points 574 * @property {Number} height - Content height in points 575 * @property {cc.GLProgram} shaderProgram - The shader program used by drawAtPoint and drawInRect 576 * @property {Number} maxS - Texture max S 577 * @property {Number} maxT - Texture max T 578 */ 579 cc.Texture2D = cc.Class.extend(/** @lends cc.Texture2D# */proto); 580 581 cc.Texture2D._generateGrayTexture = function(texture, rect, renderCanvas){ 582 if (texture === null) 583 return null; 584 renderCanvas = renderCanvas || document.createElement("canvas"); 585 rect = rect || cc.rect(0, 0, texture.width, texture.height); 586 renderCanvas.width = rect.width; 587 renderCanvas.height = rect.height; 588 589 var context = renderCanvas.getContext("2d"); 590 context.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); 591 var imgData = context.getImageData(0, 0, rect.width, rect.height); 592 var data = imgData.data; 593 for (var i = 0, len = data.length; i < len; i += 4) { 594 data[i] = data[i + 1] = data[i + 2] = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]; 595 } 596 context.putImageData(imgData, 0, 0); 597 return renderCanvas; 598 }; 599 600 } else if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { 601 cc.assert(cc.isFunction(cc._tmp.WebGLTexture2D), cc._LogInfos.MissingFile, "TexturesWebGL.js"); 602 cc._tmp.WebGLTexture2D(); 603 delete cc._tmp.WebGLTexture2D; 604 } 605 606 cc.EventHelper.prototype.apply(cc.Texture2D.prototype); 607 608 cc.assert(cc.isFunction(cc._tmp.PrototypeTexture2D), cc._LogInfos.MissingFile, "TexturesPropertyDefine.js"); 609 cc._tmp.PrototypeTexture2D(); 610 delete cc._tmp.PrototypeTexture2D; 611 }); 612