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 /** 28 * using image file to print text label on the screen, might be a bit slower than cc.Label, similar to cc.LabelBMFont 29 * @class 30 * @extends cc.AtlasNode 31 */ 32 cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ 33 // string to render 34 _string:null, 35 // the first char in the charmap 36 _mapStartChar:null, 37 38 /** 39 * <p> 40 * initializes the cc.LabelAtlas with a string, a char map file(the atlas), <br/> 41 * the width and height of each element and the starting char of the atlas <br/> 42 * It accepts two groups of parameters: <br/> 43 * a) string, fntFile <br/> 44 * b) label, textureFilename, width, height, startChar <br/> 45 * </p> 46 * @param {String} strText 47 * @param {String|cc.Texture2D} charMapFile charMapFile or fntFile or texture file 48 * @param {Number} [itemWidth=0] 49 * @param {Number} [itemHeight=0] 50 * @param {Number} [startCharMap=""] 51 * @return {Boolean} returns true on success 52 */ 53 initWithString:function (strText, charMapFile, itemWidth, itemHeight, startCharMap) { 54 var label = strText + "", textureFilename, width, height, startChar; 55 if (arguments.length === 2) { 56 var fileUtils = cc.FileUtils.getInstance(); 57 var pathStr = fileUtils.fullPathForFilename(charMapFile); 58 var relPathStr = pathStr.substr(0, pathStr.lastIndexOf('/')) + '/'; 59 60 var dict = fileUtils.dictionaryWithContentsOfFileThreadSafe(pathStr); 61 if(parseInt(dict["version"], 10) !== 1) { 62 cc.log("cc.LabelAtlas.initWithString(): Unsupported version. Upgrade cocos2d version"); 63 return false; 64 } 65 66 textureFilename = relPathStr + dict["textureFilename"]; 67 var locScaleFactor = cc.CONTENT_SCALE_FACTOR(); 68 width = parseInt(dict["itemWidth"], 10) / locScaleFactor; 69 height = parseInt(dict["itemHeight"], 10) / locScaleFactor; 70 startChar = String.fromCharCode(parseInt(dict["firstChar"], 10)); 71 } else { 72 textureFilename = charMapFile; 73 width = itemWidth || 0; 74 height = itemHeight || 0; 75 startChar = startCharMap || " "; 76 } 77 78 var texture = null; 79 if(textureFilename instanceof cc.Texture2D) 80 texture = textureFilename; 81 else 82 texture = cc.TextureCache.getInstance().addImage(textureFilename); 83 84 if (this.initWithTexture(texture, width, height, label.length)) { 85 this._mapStartChar = startChar; 86 this.setString(label); 87 return true; 88 } 89 return false; 90 }, 91 92 /** 93 * @param {cc.Color3B} color3 94 */ 95 setColor:function (color3) { 96 cc.AtlasNode.prototype.setColor.call(this, color3); 97 this.updateAtlasValues(); 98 }, 99 /** 100 * return the text of this label 101 * @return {String} 102 */ 103 getString:function () { 104 return this._string; 105 }, 106 107 /** 108 * draw the label 109 */ 110 draw:function (ctx) { 111 cc.AtlasNode.prototype.draw.call(this,ctx); 112 if (cc.LABELATLAS_DEBUG_DRAW) { 113 var s = this.getContentSize(); 114 var vertices = [cc.p(0, 0), cc.p(s.width, 0), 115 cc.p(s.width, s.height), cc.p(0, s.height)]; 116 cc.drawingUtil.drawPoly(vertices, 4, true); 117 } 118 }, 119 120 /** 121 * Atlas generation 122 */ 123 updateAtlasValues: null, 124 125 _updateAtlasValuesForCanvas: function () { 126 var locString = this._string; 127 var n = locString.length; 128 var texture = this.getTexture(); 129 var locItemWidth = this._itemWidth, locItemHeight = this._itemHeight; 130 var locScaleFactor = cc.CONTENT_SCALE_FACTOR(); 131 for (var i = 0; i < n; i++) { 132 var a = locString.charCodeAt(i) - this._mapStartChar.charCodeAt(0); 133 var row = parseInt(a % this._itemsPerRow, 10) * locScaleFactor; 134 var col = parseInt(a / this._itemsPerRow, 10) * locScaleFactor; 135 136 var rect = cc.rect(row * locItemWidth, col * locItemHeight, locItemWidth, locItemHeight); 137 var c = locString.charCodeAt(i); 138 var fontChar = this.getChildByTag(i); 139 if (!fontChar) { 140 fontChar = new cc.Sprite(); 141 if (c == 32) { 142 fontChar.init(); 143 fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.SizeZero()); 144 } else 145 fontChar.initWithTexture(texture, rect); 146 147 this.addChild(fontChar, 0, i); 148 } else { 149 if (c == 32) { 150 fontChar.init(); 151 fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.SizeZero()); 152 } else { 153 // reusing fonts 154 fontChar.initWithTexture(texture, rect); 155 // restore to default in case they were modified 156 fontChar.setVisible(true); 157 fontChar.setOpacity(this._displayedOpacity); 158 } 159 } 160 fontChar.setPosition(i * locItemWidth + locItemWidth / 2, locItemHeight / 2); 161 } 162 }, 163 164 _updateAtlasValuesForWebGL: function () { 165 var locString = this._string; 166 var n = locString.length; 167 var locTextureAtlas = this._textureAtlas; 168 169 var texture = locTextureAtlas.getTexture(); 170 var textureWide = texture.getPixelsWide(); 171 var textureHigh = texture.getPixelsHigh(); 172 var itemWidthInPixels = this._itemWidth; 173 var itemHeightInPixels = this._itemHeight; 174 if (!this._ignoreContentScaleFactor) { 175 itemWidthInPixels = this._itemWidth * cc.CONTENT_SCALE_FACTOR(); 176 itemHeightInPixels = this._itemHeight * cc.CONTENT_SCALE_FACTOR(); 177 } 178 if(n > locTextureAtlas.getCapacity()) 179 cc.log("cc.LabelAtlas._updateAtlasValues(): Invalid String length"); 180 var quads = locTextureAtlas.getQuads(); 181 var locDisplayedColor = this._displayedColor; 182 var curColor = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: this._displayedOpacity}; 183 var locItemWidth = this._itemWidth; 184 for (var i = 0; i < n; i++) { 185 var a = locString.charCodeAt(i) - this._mapStartChar.charCodeAt(0); 186 var row = a % this._itemsPerRow; 187 var col = 0 | (a / this._itemsPerRow); 188 189 var left, right, top, bottom; 190 if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { 191 // Issue #938. Don't use texStepX & texStepY 192 left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide); 193 right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide); 194 top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh); 195 bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh); 196 } else { 197 left = row * itemWidthInPixels / textureWide; 198 right = left + itemWidthInPixels / textureWide; 199 top = col * itemHeightInPixels / textureHigh; 200 bottom = top + itemHeightInPixels / textureHigh; 201 } 202 var quad = quads[i]; 203 var locQuadTL = quad.tl, locQuadTR = quad.tr, locQuadBL = quad.bl, locQuadBR = quad.br; 204 locQuadTL.texCoords.u = left; 205 locQuadTL.texCoords.v = top; 206 locQuadTR.texCoords.u = right; 207 locQuadTR.texCoords.v = top; 208 locQuadBL.texCoords.u = left; 209 locQuadBL.texCoords.v = bottom; 210 locQuadBR.texCoords.u = right; 211 locQuadBR.texCoords.v = bottom; 212 213 locQuadBL.vertices.x = (i * locItemWidth); 214 locQuadBL.vertices.y = 0; 215 locQuadBL.vertices.z = 0.0; 216 locQuadBR.vertices.x = (i * locItemWidth + locItemWidth); 217 locQuadBR.vertices.y = 0; 218 locQuadBR.vertices.z = 0.0; 219 locQuadTL.vertices.x = i * locItemWidth; 220 locQuadTL.vertices.y = this._itemHeight; 221 locQuadTL.vertices.z = 0.0; 222 locQuadTR.vertices.x = i * locItemWidth + locItemWidth; 223 locQuadTR.vertices.y = this._itemHeight; 224 locQuadTR.vertices.z = 0.0; 225 locQuadTL.colors = curColor; 226 locQuadTR.colors = curColor; 227 locQuadBL.colors = curColor; 228 locQuadBR.colors = curColor; 229 } 230 if (n > 0) { 231 locTextureAtlas.setDirty(true); 232 var totalQuads = locTextureAtlas.getTotalQuads(); 233 if (n > totalQuads) 234 locTextureAtlas.increaseTotalQuadsWith(n - totalQuads); 235 } 236 }, 237 238 /** 239 * set the display string 240 * @param {String} label 241 */ 242 setString: null, 243 244 _setStringForCanvas: function (label) { 245 label = String(label); 246 var len = label.length; 247 this._string = label; 248 this.setContentSize(cc.size(len * this._itemWidth, this._itemHeight)); 249 if (this._children) { 250 var locChildren = this._children; 251 len = locChildren.length; 252 for (var i = 0; i < len; i++) { 253 var node = locChildren[i]; 254 if (node) 255 node.setVisible(false); 256 } 257 } 258 259 this.updateAtlasValues(); 260 this._quadsToDraw = len; 261 }, 262 263 _setStringForWebGL: function (label) { 264 label = String(label); 265 var len = label.length; 266 if (len > this._textureAtlas.getTotalQuads()) 267 this._textureAtlas.resizeCapacity(len); 268 269 this._string = label; 270 this.setContentSize(cc.size(len * this._itemWidth, this._itemHeight)); 271 272 this.updateAtlasValues(); 273 this._quadsToDraw = len; 274 }, 275 276 setOpacity: null, 277 278 _setOpacityForCanvas: function (opacity) { 279 if (this._displayedOpacity !== opacity) { 280 cc.AtlasNode.prototype.setOpacity.call(this, opacity); 281 var locChildren = this._children; 282 for (var i = 0, len = locChildren.length; i < len; i++) { 283 if (locChildren[i]) 284 locChildren[i].setOpacity(opacity); 285 } 286 } 287 }, 288 289 _setOpacityForWebGL: function (opacity) { 290 if (this._opacity !== opacity) 291 cc.AtlasNode.prototype.setOpacity.call(this, opacity); 292 } 293 }); 294 295 if(cc.Browser.supportWebGL){ 296 cc.LabelAtlas.prototype.updateAtlasValues = cc.LabelAtlas.prototype._updateAtlasValuesForWebGL; 297 cc.LabelAtlas.prototype.setString = cc.LabelAtlas.prototype._setStringForWebGL; 298 cc.LabelAtlas.prototype.setOpacity = cc.LabelAtlas.prototype._setOpacityForWebGL; 299 } else { 300 cc.LabelAtlas.prototype.updateAtlasValues = cc.LabelAtlas.prototype._updateAtlasValuesForCanvas; 301 cc.LabelAtlas.prototype.setString = cc.LabelAtlas.prototype._setStringForCanvas; 302 cc.LabelAtlas.prototype.setOpacity = cc.LabelAtlas.prototype._setOpacityForCanvas; 303 } 304 305 /** 306 * <p> 307 * It accepts two groups of parameters: <br/> 308 * a) string, fntFile <br/> 309 * b) label, textureFilename, width, height, startChar <br/> 310 * </p> 311 * @param {String} strText 312 * @param {String} charMapFile charMapFile or fntFile 313 * @param {Number} [itemWidth=0] 314 * @param {Number} [itemHeight=0] 315 * @param {Number} [startCharMap=""] 316 * @return {cc.LabelAtlas|Null} returns the LabelAtlas object on success 317 * @example 318 * //Example 319 * //creates the cc.LabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas 320 * var myLabel = cc.LabelAtlas.create('Text to display', 'CharMapfile.png', 12, 20, ' ') 321 * 322 * //creates the cc.LabelAtlas with a string, a fnt file 323 * var myLabel = cc.LabelAtlas.create('Text to display', 'CharMapFile.plist‘); 324 */ 325 cc.LabelAtlas.create = function (strText, charMapFile, itemWidth, itemHeight, startCharMap) { 326 var ret = new cc.LabelAtlas(); 327 if (ret && cc.LabelAtlas.prototype.initWithString.apply(ret,arguments)) { 328 return ret; 329 } 330 return null; 331 }; 332 333