1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga 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 * @constant 28 * @type Number 29 */ 30 cc.TGA_OK = 0; 31 32 /** 33 * @constant 34 * @type Number 35 */ 36 cc.TGA_ERROR_FILE_OPEN = 1; 37 38 /** 39 * @constant 40 * @type Number 41 */ 42 cc.TGA_ERROR_READING_FILE = 2; 43 44 /** 45 * @constant 46 * @type Number 47 */ 48 cc.TGA_ERROR_INDEXED_COLOR = 3; 49 50 /** 51 * @constant 52 * @type Number 53 */ 54 cc.TGA_ERROR_MEMORY = 4; 55 56 /** 57 * @constant 58 * @type Number 59 */ 60 cc.TGA_ERROR_COMPRESSED_FILE = 5; 61 62 function cc.ImageTGA(status, type, pixelDepth, width, height, imageData, flipped) { 63 this.status = status; 64 this.type = type; 65 this.pixelDepth = pixelDepth; 66 /** map width */ 67 this.width = width; 68 /** map height */ 69 this.height = height; 70 /** raw data */ 71 this.imageData = imageData; 72 this.flipped = flipped; 73 } 74 75 /** 76 * <p>cc.TileMapAtlas is a subclass of cc.AtlasNode.</p> 77 * 78 * <p>It knows how to render a map based of tiles.<br/> 79 * The tiles must be in a .PNG format while the map must be a .TGA file. </p> 80 * 81 * <p>For more information regarding the format, please see this post: <br/> 82 * http://www.cocos2d-iphone.org/archives/27 </p> 83 * 84 * <p>All features from cc.AtlasNode are valid in cc.TileMapAtlas</p> 85 * 86 * <p>IMPORTANT: <br/> 87 * This class is deprecated. It is maintained for compatibility reasons only.<br/> 88 * You SHOULD not use this class. <br/> 89 * Instead, use the newer TMX file format: cc.TMXTiledMap </p> 90 * @class 91 * @extends cc.AtlasNode 92 */ 93 cc.TileMapAtlas = cc.AtlasNode.extend(/** @lends cc.TileMapAtlas# */{ 94 _GAInfo:null, 95 indices:null, 96 //numbers of tiles to render 97 _itemsToRender:0, 98 //x,y to altas dictionary 99 _posToAtlasIndex:null, 100 101 /** 102 * @return {cc.ImageTGA} 103 */ 104 getTGAInfo:function () { 105 return this._GAInfo; 106 }, 107 108 /** 109 * @param {cc.ImageTGA} Var 110 */ 111 setTGAInfo:function (Var) { 112 this._GAInfo = Var; 113 }, 114 115 /** 116 * Initializes a cc.TileMap with a tile file (atlas) with a map file and the width and height of each tile in points.<br /> 117 * The file will be loaded using the TextureMgr. 118 * @param {String} tile 119 * @param {String} mapFile 120 * @param {Number} tileWidth 121 * @param {Number} tileHeight 122 * @return {Boolean} 123 * @example 124 * //example 125 * var tmpAtlas = new cc.TileMapAtlas(); 126 * tmpAtlas.initWithTileFile("hello.png", "hello.tga", 16, 16); 127 */ 128 initWithTileFile:function (tile, mapFile, tileWidth, tileHeight) { 129 this._loadTGAfile(mapFile); 130 this._calculateItemsToRender(); 131 if (this.initWithTileFile(tile, tileWidth, tileHeight, this._itemsToRender)) { 132 this._color = cc.white(); 133 this._posToAtlasIndex = new Object(); 134 this._updateAtlasValues(); 135 this.setContentSize(cc.size((this._GAInfo.width * this._itemWidth), 136 (this._GAInfo.height * this._itemHeight))); 137 return true; 138 } 139 return false; 140 }, 141 142 /** 143 * <p>Returns a tile from position x,y.<br /> 144 * For the moment only channel R is used. </p> 145 * @param {cc.Point} position 146 * @return {cc.Sprite} 147 */ 148 tileAt:function (position) { 149 cc.Assert(this._GAInfo != null, "tgaInfo must not be nil"); 150 cc.Assert(position.x < this._GAInfo.width, "Invalid position.x"); 151 cc.Assert(position.y < this._GAInfo.height, "Invalid position.y"); 152 153 var ptr = this._GAInfo.imageData; 154 var value = ptr[position.x + position.y * this._GAInfo.width]; 155 156 return value; 157 }, 158 159 /** 160 * Sets a tile at position x,y. 161 * For the moment only channel R is used 162 * @param {cc.Sprite} tile 163 * @param {cc.Point} position 164 */ 165 setTile:function (tile, position) { 166 cc.Assert(this._GAInfo != null, "tgaInfo must not be nil"); 167 cc.Assert(this._posToAtlasIndex != null, "posToAtlasIndex must not be nil"); 168 cc.Assert(position.x < this._GAInfo.width, "Invalid position.x"); 169 cc.Assert(position.y < this._GAInfo.height, "Invalid position.x"); 170 cc.Assert(tile.r != 0, "R component must be non 0"); 171 172 var ptr = this._GAInfo.imageData; 173 var value = ptr[position.x + position.y * this._GAInfo.width]; 174 if (value.r == 0) { 175 cc.log("cocos2d: Value.r must be non 0."); 176 } else { 177 ptr[position.x + position.y * this._GAInfo.width] = tile; 178 179 var num = this._posToAtlasIndex[position.x + "" + position.y]; 180 this._updateAtlasValueAt(position, tile, num); 181 } 182 }, 183 184 /** 185 * Dealloc the map from memory 186 */ 187 releaseMap:function () { 188 if (this._GAInfo) { 189 cc.tgaDestroy(this._GAInfo); 190 } 191 this._GAInfo = null; 192 }, 193 194 _loadTGAfile:function (file) { 195 cc.Assert(file != null, "file must be non-nil"); 196 197 // //Find the path of the file 198 // NSBundle *mainBndl = [cc.Director sharedDirector].loadingBundle; 199 // cc.String *resourcePath = [mainBndl resourcePath]; 200 // cc.String * path = [resourcePath stringByAppendingPathComponent:file]; 201 202 this._GAInfo = cc.tgaLoad(cc.FileUtils.getInstance().fullPathFromRelativePath(file)); 203 if (this._GAInfo.status != cc.TGA_OK) { 204 cc.Assert(0, "TileMapAtlasLoadTGA : TileMapAtas cannot load TGA file"); 205 } 206 }, 207 208 _calculateItemsToRender:function () { 209 cc.Assert(this._GAInfo != null, "tgaInfo must be non-nil"); 210 211 this._itemsToRender = 0; 212 for (var x = 0; x < this._GAInfo.width; x++) { 213 for (var y = 0; y < this._GAInfo.height; y++) { 214 var ptr = this._GAInfo.imageData; 215 var value = ptr[x + y * this._GAInfo.width]; 216 if (value.r) { 217 ++this._itemsToRender; 218 } 219 } 220 } 221 }, 222 223 _updateAtlasValueAt:function (pos, value, index) { 224 var quad = new cc.V3F_C4B_T2F_Quad(); 225 226 var x = pos.x; 227 var y = pos.y; 228 var row = (value.r % this._itemsPerRow); 229 var col = (value.r / this._itemsPerRow); 230 231 var textureWide = this._textureAtlas.getTexture().getPixelsWide(); 232 var textureHigh = this._textureAtlas.getTexture().getPixelsHigh(); 233 234 var itemWidthInPixels = this._itemWidth * cc.CONTENT_SCALE_FACTOR(); 235 var itemHeightInPixels = this._itemHeight * cc.CONTENT_SCALE_FACTOR(); 236 237 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 238 var left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide); 239 var right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide); 240 var top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh); 241 var bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh); 242 } else { 243 var left = (row * itemWidthInPixels) / textureWide; 244 var right = left + itemWidthInPixels / textureWide; 245 var top = (col * itemHeightInPixels) / textureHigh; 246 var bottom = top + itemHeightInPixels / textureHigh; 247 } 248 249 quad.tl.texCoords.u = left; 250 quad.tl.texCoords.v = top; 251 quad.tr.texCoords.u = right; 252 quad.tr.texCoords.v = top; 253 quad.bl.texCoords.u = left; 254 quad.bl.texCoords.v = bottom; 255 quad.br.texCoords.u = right; 256 quad.br.texCoords.v = bottom; 257 258 quad.bl.vertices.x = (x * this._itemWidth); 259 quad.bl.vertices.y = (y * this._itemHeight); 260 quad.bl.vertices.z = 0.0; 261 quad.br.vertices.x = (x * this._itemWidth + this._itemWidth); 262 quad.br.vertices.y = (y * this._itemHeight); 263 quad.br.vertices.z = 0.0; 264 quad.tl.vertices.x = (x * this._itemWidth); 265 quad.tl.vertices.y = (y * this._itemHeight + this._itemHeight); 266 quad.tl.vertices.z = 0.0; 267 quad.tr.vertices.x = (x * this._itemWidth + this._itemWidth); 268 quad.tr.vertices.y = (y * this._itemHeight + this._itemHeight); 269 quad.tr.vertices.z = 0.0; 270 271 var color = new cc.Color4B(this._color.r, this._color.g, this._color.b, this._opacity); 272 quad.tr.colors = color; 273 quad.tl.colors = color; 274 quad.br.colors = color; 275 quad.bl.colors = color; 276 277 this._textureAtlas.updateQuad(quad, index); 278 }, 279 280 _updateAtlasValues:function () { 281 cc.Assert(this._GAInfo != null, "tgaInfo must be non-nil"); 282 283 var total = 0; 284 285 for (var x = 0; x < this._GAInfo.width; x++) { 286 for (var y = 0; y < this._GAInfo.height; y++) { 287 if (total < this._itemsToRender) { 288 var ptr = this._GAInfo.imageData; 289 var value = ptr[x + y * this._GAInfo.width]; 290 291 if (value.r != 0) { 292 this._updateAtlasValueAt(cc.g(x, y), value, total); 293 this._posToAtlasIndex[x + "" + y] = total; 294 295 total++; 296 } 297 } 298 } 299 } 300 } 301 }); 302 303 /** 304 * <p>Creates a cc.TileMap with a tile file (atlas) with a map file and the width and height of each tile in points.<br /> 305 * The tile file will be loaded using the TextureMgr. </p> 306 * @param {String} tile 307 * @param {String} mapFile 308 * @param {Number} tileWidth 309 * @param {Number} tileHeight 310 * @return {Boolean|Null} 311 * @example 312 * //example 313 * var tmpAtlas = new cc.TileMapAtlas(); 314 * tmpAtlas.initWithTileFile("hello.png", "hello.tga", 16, 16); 315 */ 316 cc.TileMapAtlas.create = function (tile, mapFile, tileWidth, tileHeight) { 317 var ret = new cc.TileMapAtlas(); 318 if (ret.initWithTileFile(tile, mapFile, tileWidth, tileHeight)) { 319 return ret; 320 } 321 return null; 322 }; 323