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