CCLabel.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216
  1. /****************************************************************************
  2. Copyright (c) 2013 Zynga Inc.
  3. Copyright (c) 2013-2016 Chukong Technologies Inc.
  4. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  5. http://www.cocos2d-x.org
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. ****************************************************************************/
  22. #include "2d/CCLabel.h"
  23. #include <algorithm>
  24. #include "2d/CCFont.h"
  25. #include "2d/CCFontAtlasCache.h"
  26. #include "2d/CCFontAtlas.h"
  27. #include "2d/CCSprite.h"
  28. #include "2d/CCSpriteBatchNode.h"
  29. #include "2d/CCDrawNode.h"
  30. #include "2d/CCCamera.h"
  31. #include "base/ccUTF8.h"
  32. #include "platform/CCFileUtils.h"
  33. #include "renderer/CCRenderer.h"
  34. #include "renderer/ccGLStateCache.h"
  35. #include "base/CCDirector.h"
  36. #include "base/CCEventListenerCustom.h"
  37. #include "base/CCEventDispatcher.h"
  38. #include "base/CCEventCustom.h"
  39. #include "2d/CCFontFNT.h"
  40. NS_CC_BEGIN
  41. /**
  42. * LabelLetter used to update the quad in texture atlas without SpriteBatchNode.
  43. */
  44. class LabelLetter : public Sprite
  45. {
  46. public:
  47. LabelLetter()
  48. {
  49. _textureAtlas = nullptr;
  50. _letterVisible = true;
  51. }
  52. static LabelLetter* createWithTexture(Texture2D *texture, const Rect& rect, bool rotated = false)
  53. {
  54. auto letter = new (std::nothrow) LabelLetter();
  55. if (letter && letter->initWithTexture(texture, rect, rotated))
  56. {
  57. letter->Sprite::setVisible(false);
  58. letter->autorelease();
  59. return letter;
  60. }
  61. CC_SAFE_DELETE(letter);
  62. return nullptr;
  63. }
  64. CREATE_FUNC(LabelLetter);
  65. virtual void updateTransform() override
  66. {
  67. if (isDirty())
  68. {
  69. _transformToBatch = getNodeToParentTransform();
  70. Size &size = _rect.size;
  71. float x1 = _offsetPosition.x;
  72. float y1 = _offsetPosition.y;
  73. float x2 = x1 + size.width;
  74. float y2 = y1 + size.height;
  75. // issue #17022: don't flip, again, the letter since they are flipped in sprite's code
  76. //if (_flippedX) std::swap(x1, x2);
  77. //if (_flippedY) std::swap(y1, y2);
  78. float x = _transformToBatch.m[12];
  79. float y = _transformToBatch.m[13];
  80. float cr = _transformToBatch.m[0];
  81. float sr = _transformToBatch.m[1];
  82. float cr2 = _transformToBatch.m[5];
  83. float sr2 = -_transformToBatch.m[4];
  84. float ax = x1 * cr - y1 * sr2 + x;
  85. float ay = x1 * sr + y1 * cr2 + y;
  86. float bx = x2 * cr - y1 * sr2 + x;
  87. float by = x2 * sr + y1 * cr2 + y;
  88. float cx = x2 * cr - y2 * sr2 + x;
  89. float cy = x2 * sr + y2 * cr2 + y;
  90. float dx = x1 * cr - y2 * sr2 + x;
  91. float dy = x1 * sr + y2 * cr2 + y;
  92. _quad.bl.vertices.set(SPRITE_RENDER_IN_SUBPIXEL(ax), SPRITE_RENDER_IN_SUBPIXEL(ay), _positionZ);
  93. _quad.br.vertices.set(SPRITE_RENDER_IN_SUBPIXEL(bx), SPRITE_RENDER_IN_SUBPIXEL(by), _positionZ);
  94. _quad.tl.vertices.set(SPRITE_RENDER_IN_SUBPIXEL(dx), SPRITE_RENDER_IN_SUBPIXEL(dy), _positionZ);
  95. _quad.tr.vertices.set(SPRITE_RENDER_IN_SUBPIXEL(cx), SPRITE_RENDER_IN_SUBPIXEL(cy), _positionZ);
  96. if (_textureAtlas)
  97. {
  98. _textureAtlas->updateQuad(&_quad, _atlasIndex);
  99. }
  100. _recursiveDirty = false;
  101. setDirty(false);
  102. }
  103. Node::updateTransform();
  104. }
  105. virtual void updateColor() override
  106. {
  107. if (_textureAtlas == nullptr)
  108. {
  109. return;
  110. }
  111. auto displayedOpacity = _displayedOpacity;
  112. if(!_letterVisible)
  113. {
  114. displayedOpacity = 0.0f;
  115. }
  116. Color4B color4(_displayedColor.r, _displayedColor.g, _displayedColor.b, displayedOpacity);
  117. // special opacity for premultiplied textures
  118. if (_opacityModifyRGB)
  119. {
  120. color4.r *= displayedOpacity / 255.0f;
  121. color4.g *= displayedOpacity / 255.0f;
  122. color4.b *= displayedOpacity / 255.0f;
  123. }
  124. _quad.bl.colors = color4;
  125. _quad.br.colors = color4;
  126. _quad.tl.colors = color4;
  127. _quad.tr.colors = color4;
  128. _textureAtlas->updateQuad(&_quad, _atlasIndex);
  129. }
  130. void setVisible(bool visible) override
  131. {
  132. _letterVisible = visible;
  133. updateColor();
  134. }
  135. //LabelLetter doesn't need to draw directly.
  136. void draw(Renderer* /*renderer*/, const Mat4 & /*transform*/, uint32_t /*flags*/) override
  137. {
  138. }
  139. private:
  140. bool _letterVisible;
  141. };
  142. Label* Label::create()
  143. {
  144. auto ret = new (std::nothrow) Label;
  145. if (ret)
  146. {
  147. ret->autorelease();
  148. }
  149. return ret;
  150. }
  151. Label* Label::create(const std::string& text, const std::string& font, float fontSize, const Size& dimensions /* = Size::ZERO */, TextHAlignment hAlignment /* = TextHAlignment::LEFT */, TextVAlignment vAlignment /* = TextVAlignment::TOP */)
  152. {
  153. if (FileUtils::getInstance()->isFileExist(font))
  154. {
  155. return createWithTTF(text,font,fontSize,dimensions,hAlignment,vAlignment);
  156. }
  157. else
  158. {
  159. return createWithSystemFont(text,font,fontSize,dimensions,hAlignment,vAlignment);
  160. }
  161. }
  162. Label* Label::createWithSystemFont(const std::string& text, const std::string& font, float fontSize, const Size& dimensions /* = Size::ZERO */, TextHAlignment hAlignment /* = TextHAlignment::LEFT */, TextVAlignment vAlignment /* = TextVAlignment::TOP */)
  163. {
  164. auto ret = new (std::nothrow) Label(hAlignment,vAlignment);
  165. if (ret)
  166. {
  167. ret->setSystemFontName(font);
  168. ret->setSystemFontSize(fontSize);
  169. ret->setDimensions(dimensions.width, dimensions.height);
  170. ret->setString(text);
  171. ret->autorelease();
  172. return ret;
  173. }
  174. return nullptr;
  175. }
  176. Label* Label::createWithTTF(const std::string& text, const std::string& fontFile, float fontSize, const Size& dimensions /* = Size::ZERO */, TextHAlignment hAlignment /* = TextHAlignment::LEFT */, TextVAlignment vAlignment /* = TextVAlignment::TOP */)
  177. {
  178. auto ret = new (std::nothrow) Label(hAlignment,vAlignment);
  179. if (ret && ret->initWithTTF(text, fontFile, fontSize, dimensions, hAlignment, vAlignment))
  180. {
  181. ret->autorelease();
  182. return ret;
  183. }
  184. CC_SAFE_DELETE(ret);
  185. return nullptr;
  186. }
  187. Label* Label::createWithTTF(const TTFConfig& ttfConfig, const std::string& text, TextHAlignment hAlignment /* = TextHAlignment::CENTER */, int maxLineWidth /* = 0 */)
  188. {
  189. auto ret = new (std::nothrow) Label(hAlignment);
  190. if (ret && ret->initWithTTF(ttfConfig, text, hAlignment, maxLineWidth))
  191. {
  192. ret->autorelease();
  193. return ret;
  194. }
  195. CC_SAFE_DELETE(ret);
  196. return nullptr;
  197. }
  198. Label* Label::createWithBMFont(const std::string& bmfontFilePath, const std::string& text,const TextHAlignment& hAlignment /* = TextHAlignment::LEFT */, int maxLineWidth /* = 0 */, const Vec2& imageOffset /* = Vec2::ZERO */)
  199. {
  200. auto ret = new (std::nothrow) Label(hAlignment);
  201. if (ret && ret->setBMFontFilePath(bmfontFilePath,imageOffset))
  202. {
  203. ret->setMaxLineWidth(maxLineWidth);
  204. ret->setString(text);
  205. ret->autorelease();
  206. return ret;
  207. }
  208. delete ret;
  209. return nullptr;
  210. }
  211. Label* Label::createWithCharMap(const std::string& plistFile)
  212. {
  213. auto ret = new (std::nothrow) Label();
  214. if (ret && ret->setCharMap(plistFile))
  215. {
  216. ret->autorelease();
  217. return ret;
  218. }
  219. delete ret;
  220. return nullptr;
  221. }
  222. Label* Label::createWithCharMap(Texture2D* texture, int itemWidth, int itemHeight, int startCharMap)
  223. {
  224. auto ret = new (std::nothrow) Label();
  225. if (ret && ret->setCharMap(texture,itemWidth,itemHeight,startCharMap))
  226. {
  227. ret->autorelease();
  228. return ret;
  229. }
  230. delete ret;
  231. return nullptr;
  232. }
  233. Label* Label::createWithCharMap(const std::string& charMapFile, int itemWidth, int itemHeight, int startCharMap)
  234. {
  235. auto ret = new (std::nothrow) Label();
  236. if (ret && ret->setCharMap(charMapFile,itemWidth,itemHeight,startCharMap))
  237. {
  238. ret->autorelease();
  239. return ret;
  240. }
  241. delete ret;
  242. return nullptr;
  243. }
  244. bool Label::setCharMap(const std::string& plistFile)
  245. {
  246. auto newAtlas = FontAtlasCache::getFontAtlasCharMap(plistFile);
  247. if (!newAtlas)
  248. {
  249. reset();
  250. return false;
  251. }
  252. _currentLabelType = LabelType::CHARMAP;
  253. setFontAtlas(newAtlas);
  254. return true;
  255. }
  256. bool Label::initWithTTF(const std::string& text,
  257. const std::string& fontFilePath, float fontSize,
  258. const Size& dimensions,
  259. TextHAlignment /*hAlignment*/, TextVAlignment /*vAlignment*/)
  260. {
  261. if (FileUtils::getInstance()->isFileExist(fontFilePath))
  262. {
  263. TTFConfig ttfConfig(fontFilePath, fontSize, GlyphCollection::DYNAMIC);
  264. if (setTTFConfig(ttfConfig))
  265. {
  266. setDimensions(dimensions.width, dimensions.height);
  267. setString(text);
  268. }
  269. return true;
  270. }
  271. return false;
  272. }
  273. bool Label::initWithTTF(const TTFConfig& ttfConfig, const std::string& text, TextHAlignment /*hAlignment*/, int maxLineWidth)
  274. {
  275. if (FileUtils::getInstance()->isFileExist(ttfConfig.fontFilePath) && setTTFConfig(ttfConfig))
  276. {
  277. setMaxLineWidth(maxLineWidth);
  278. setString(text);
  279. return true;
  280. }
  281. return false;
  282. }
  283. bool Label::setCharMap(Texture2D* texture, int itemWidth, int itemHeight, int startCharMap)
  284. {
  285. auto newAtlas = FontAtlasCache::getFontAtlasCharMap(texture,itemWidth,itemHeight,startCharMap);
  286. if (!newAtlas)
  287. {
  288. reset();
  289. return false;
  290. }
  291. _currentLabelType = LabelType::CHARMAP;
  292. setFontAtlas(newAtlas);
  293. return true;
  294. }
  295. bool Label::setCharMap(const std::string& charMapFile, int itemWidth, int itemHeight, int startCharMap)
  296. {
  297. auto newAtlas = FontAtlasCache::getFontAtlasCharMap(charMapFile,itemWidth,itemHeight,startCharMap);
  298. if (!newAtlas)
  299. {
  300. reset();
  301. return false;
  302. }
  303. _currentLabelType = LabelType::CHARMAP;
  304. setFontAtlas(newAtlas);
  305. return true;
  306. }
  307. Label::Label(TextHAlignment hAlignment /* = TextHAlignment::LEFT */,
  308. TextVAlignment vAlignment /* = TextVAlignment::TOP */)
  309. : _textSprite(nullptr)
  310. , _shadowNode(nullptr)
  311. , _fontAtlas(nullptr)
  312. , _reusedLetter(nullptr)
  313. , _horizontalKernings(nullptr)
  314. , _boldEnabled(false)
  315. , _underlineNode(nullptr)
  316. , _strikethroughEnabled(false)
  317. {
  318. setAnchorPoint(Vec2::ANCHOR_MIDDLE);
  319. reset();
  320. _hAlignment = hAlignment;
  321. _vAlignment = vAlignment;
  322. #if CC_LABEL_DEBUG_DRAW
  323. _debugDrawNode = DrawNode::create();
  324. addChild(_debugDrawNode);
  325. #endif
  326. _purgeTextureListener = EventListenerCustom::create(FontAtlas::CMD_PURGE_FONTATLAS, [this](EventCustom* event){
  327. if (_fontAtlas && _currentLabelType == LabelType::TTF && event->getUserData() == _fontAtlas)
  328. {
  329. for (auto&& it : _letters)
  330. {
  331. it.second->setTexture(nullptr);
  332. }
  333. _batchNodes.clear();
  334. if (_fontAtlas)
  335. {
  336. FontAtlasCache::releaseFontAtlas(_fontAtlas);
  337. }
  338. }
  339. });
  340. _eventDispatcher->addEventListenerWithFixedPriority(_purgeTextureListener, 1);
  341. _resetTextureListener = EventListenerCustom::create(FontAtlas::CMD_RESET_FONTATLAS, [this](EventCustom* event){
  342. if (_fontAtlas && _currentLabelType == LabelType::TTF && event->getUserData() == _fontAtlas)
  343. {
  344. _fontAtlas = nullptr;
  345. auto lineHeight = _lineHeight;
  346. this->setTTFConfig(_fontConfig);
  347. if (_currentLabelType != LabelType::STRING_TEXTURE)
  348. {
  349. setLineHeight(lineHeight);
  350. }
  351. for (auto&& it : _letters)
  352. {
  353. getLetter(it.first);
  354. }
  355. }
  356. });
  357. _eventDispatcher->addEventListenerWithFixedPriority(_resetTextureListener, 2);
  358. }
  359. Label::~Label()
  360. {
  361. delete [] _horizontalKernings;
  362. if (_fontAtlas)
  363. {
  364. Node::removeAllChildrenWithCleanup(true);
  365. CC_SAFE_RELEASE_NULL(_reusedLetter);
  366. _batchNodes.clear();
  367. FontAtlasCache::releaseFontAtlas(_fontAtlas);
  368. }
  369. _eventDispatcher->removeEventListener(_purgeTextureListener);
  370. _eventDispatcher->removeEventListener(_resetTextureListener);
  371. CC_SAFE_RELEASE_NULL(_textSprite);
  372. CC_SAFE_RELEASE_NULL(_shadowNode);
  373. }
  374. void Label::reset()
  375. {
  376. CC_SAFE_RELEASE_NULL(_textSprite);
  377. CC_SAFE_RELEASE_NULL(_shadowNode);
  378. Node::removeAllChildrenWithCleanup(true);
  379. CC_SAFE_RELEASE_NULL(_reusedLetter);
  380. _letters.clear();
  381. _batchNodes.clear();
  382. _lettersInfo.clear();
  383. if (_fontAtlas)
  384. {
  385. FontAtlasCache::releaseFontAtlas(_fontAtlas);
  386. _fontAtlas = nullptr;
  387. }
  388. _currentLabelType = LabelType::STRING_TEXTURE;
  389. _currLabelEffect = LabelEffect::NORMAL;
  390. _contentDirty = false;
  391. _numberOfLines = 0;
  392. _lengthOfString = 0;
  393. _utf32Text.clear();
  394. _utf8Text.clear();
  395. TTFConfig temp;
  396. _fontConfig = temp;
  397. _outlineSize = 0.f;
  398. _bmFontPath = "";
  399. _systemFontDirty = false;
  400. _systemFont = "Helvetica";
  401. _systemFontSize = 12;
  402. if (_horizontalKernings)
  403. {
  404. delete[] _horizontalKernings;
  405. _horizontalKernings = nullptr;
  406. }
  407. _additionalKerning = 0.f;
  408. _lineHeight = 0.f;
  409. _lineSpacing = 0.f;
  410. _maxLineWidth = 0.f;
  411. _labelDimensions.width = 0.f;
  412. _labelDimensions.height = 0.f;
  413. _labelWidth = 0.f;
  414. _labelHeight = 0.f;
  415. _lineBreakWithoutSpaces = false;
  416. _hAlignment = TextHAlignment::LEFT;
  417. _vAlignment = TextVAlignment::TOP;
  418. _effectColorF = Color4F::BLACK;
  419. _textColor = Color4B::WHITE;
  420. _textColorF = Color4F::WHITE;
  421. setColor(Color3B::WHITE);
  422. _shadowDirty = false;
  423. _shadowEnabled = false;
  424. _shadowBlurRadius = 0.f;
  425. _uniformEffectColor = -1;
  426. _uniformEffectType = -1;
  427. _uniformTextColor = -1;
  428. _useDistanceField = false;
  429. _useA8Shader = false;
  430. _clipEnabled = false;
  431. _blendFuncDirty = false;
  432. _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
  433. _isOpacityModifyRGB = false;
  434. _insideBounds = true;
  435. _enableWrap = true;
  436. _bmFontSize = -1;
  437. _bmfontScale = 1.0f;
  438. _overflow = Overflow::NONE;
  439. _originalFontSize = 0.0f;
  440. _boldEnabled = false;
  441. if (_underlineNode)
  442. {
  443. removeChild(_underlineNode);
  444. _underlineNode = nullptr;
  445. }
  446. _strikethroughEnabled = false;
  447. setRotationSkewX(0); // reverse italics
  448. }
  449. // ETC1 ALPHA supports, for LabelType::BMFONT & LabelType::CHARMAP
  450. static Texture2D* _getTexture(Label* label)
  451. {
  452. auto fontAtlas = label->getFontAtlas();
  453. Texture2D* texture = nullptr;
  454. if (fontAtlas != nullptr) {
  455. auto textures = fontAtlas->getTextures();
  456. if(!textures.empty()) {
  457. texture = textures.begin()->second;
  458. }
  459. }
  460. return texture;
  461. }
  462. void Label::updateShaderProgram()
  463. {
  464. switch (_currLabelEffect)
  465. {
  466. case cocos2d::LabelEffect::NORMAL:
  467. if (_useDistanceField)
  468. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_NORMAL));
  469. else if (_useA8Shader)
  470. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_LABEL_NORMAL));
  471. else if (_shadowEnabled)
  472. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR, _getTexture(this)));
  473. else
  474. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, _getTexture(this)));
  475. break;
  476. case cocos2d::LabelEffect::OUTLINE:
  477. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_LABEL_OUTLINE));
  478. _uniformEffectColor = glGetUniformLocation(getGLProgram()->getProgram(), "u_effectColor");
  479. _uniformEffectType = glGetUniformLocation(getGLProgram()->getProgram(), "u_effectType");
  480. break;
  481. case cocos2d::LabelEffect::GLOW:
  482. if (_useDistanceField)
  483. {
  484. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_LABEL_DISTANCEFIELD_GLOW));
  485. _uniformEffectColor = glGetUniformLocation(getGLProgram()->getProgram(), "u_effectColor");
  486. }
  487. break;
  488. default:
  489. return;
  490. }
  491. _uniformTextColor = glGetUniformLocation(getGLProgram()->getProgram(), "u_textColor");
  492. }
  493. void Label::setFontAtlas(FontAtlas* atlas,bool distanceFieldEnabled /* = false */, bool useA8Shader /* = false */)
  494. {
  495. if(atlas)
  496. {
  497. _systemFontDirty = false;
  498. }
  499. if (atlas == _fontAtlas)
  500. return;
  501. CC_SAFE_RETAIN(atlas);
  502. if (_fontAtlas)
  503. {
  504. _batchNodes.clear();
  505. FontAtlasCache::releaseFontAtlas(_fontAtlas);
  506. }
  507. _fontAtlas = atlas;
  508. if (_reusedLetter == nullptr)
  509. {
  510. _reusedLetter = Sprite::create();
  511. _reusedLetter->setOpacityModifyRGB(_isOpacityModifyRGB);
  512. _reusedLetter->retain();
  513. _reusedLetter->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT);
  514. }
  515. if (_fontAtlas)
  516. {
  517. _lineHeight = _fontAtlas->getLineHeight();
  518. _contentDirty = true;
  519. _systemFontDirty = false;
  520. }
  521. _useDistanceField = distanceFieldEnabled;
  522. _useA8Shader = useA8Shader;
  523. if (_currentLabelType != LabelType::TTF)
  524. {
  525. _currLabelEffect = LabelEffect::NORMAL;
  526. updateShaderProgram();
  527. }
  528. }
  529. bool Label::setTTFConfig(const TTFConfig& ttfConfig)
  530. {
  531. _originalFontSize = ttfConfig.fontSize;
  532. return setTTFConfigInternal(ttfConfig);
  533. }
  534. bool Label::setBMFontFilePath(const std::string& bmfontFilePath, const Vec2& imageOffset, float fontSize)
  535. {
  536. FontAtlas *newAtlas = FontAtlasCache::getFontAtlasFNT(bmfontFilePath,imageOffset);
  537. if (!newAtlas)
  538. {
  539. reset();
  540. return false;
  541. }
  542. //assign the default fontSize
  543. if (std::abs(fontSize) < FLT_EPSILON) {
  544. FontFNT *bmFont = (FontFNT*)newAtlas->getFont();
  545. if (bmFont) {
  546. float originalFontSize = bmFont->getOriginalFontSize();
  547. _bmFontSize = originalFontSize / CC_CONTENT_SCALE_FACTOR();
  548. }
  549. }
  550. if(fontSize > 0.0f){
  551. _bmFontSize = fontSize;
  552. }
  553. _bmFontPath = bmfontFilePath;
  554. _currentLabelType = LabelType::BMFONT;
  555. setFontAtlas(newAtlas);
  556. return true;
  557. }
  558. void Label::setString(const std::string& text)
  559. {
  560. if (text.compare(_utf8Text))
  561. {
  562. _utf8Text = text;
  563. _contentDirty = true;
  564. std::u32string utf32String;
  565. if (StringUtils::UTF8ToUTF32(_utf8Text, utf32String))
  566. {
  567. _utf32Text = utf32String;
  568. }
  569. }
  570. }
  571. void Label::setAlignment(TextHAlignment hAlignment,TextVAlignment vAlignment)
  572. {
  573. if (hAlignment != _hAlignment || vAlignment != _vAlignment)
  574. {
  575. _hAlignment = hAlignment;
  576. _vAlignment = vAlignment;
  577. _contentDirty = true;
  578. }
  579. }
  580. void Label::setMaxLineWidth(float maxLineWidth)
  581. {
  582. if (_labelWidth == 0 && _maxLineWidth != maxLineWidth)
  583. {
  584. _maxLineWidth = maxLineWidth;
  585. _contentDirty = true;
  586. }
  587. }
  588. void Label::setDimensions(float width, float height)
  589. {
  590. if(_overflow == Overflow::RESIZE_HEIGHT){
  591. height = 0;
  592. }
  593. if (height != _labelHeight || width != _labelWidth)
  594. {
  595. _labelWidth = width;
  596. _labelHeight = height;
  597. _labelDimensions.width = width;
  598. _labelDimensions.height = height;
  599. _maxLineWidth = width;
  600. _contentDirty = true;
  601. if(_overflow == Overflow::SHRINK){
  602. if (_originalFontSize > 0) {
  603. this->restoreFontSize();
  604. }
  605. }
  606. }
  607. }
  608. void Label::restoreFontSize()
  609. {
  610. if(_currentLabelType == LabelType::TTF){
  611. auto ttfConfig = this->getTTFConfig();
  612. ttfConfig.fontSize = _originalFontSize;
  613. this->setTTFConfigInternal(ttfConfig);
  614. }else if(_currentLabelType == LabelType::BMFONT){
  615. this->setBMFontSizeInternal(_originalFontSize);
  616. }else if(_currentLabelType == LabelType::STRING_TEXTURE){
  617. this->setSystemFontSize(_originalFontSize);
  618. }
  619. }
  620. void Label::setLineBreakWithoutSpace(bool breakWithoutSpace)
  621. {
  622. if (breakWithoutSpace != _lineBreakWithoutSpaces)
  623. {
  624. _lineBreakWithoutSpaces = breakWithoutSpace;
  625. _contentDirty = true;
  626. }
  627. }
  628. void Label::updateLabelLetters()
  629. {
  630. if (!_letters.empty())
  631. {
  632. Rect uvRect;
  633. LabelLetter* letterSprite;
  634. int letterIndex;
  635. for (auto it = _letters.begin(); it != _letters.end();)
  636. {
  637. letterIndex = it->first;
  638. letterSprite = (LabelLetter*)it->second;
  639. if (letterIndex >= _lengthOfString)
  640. {
  641. Node::removeChild(letterSprite, true);
  642. it = _letters.erase(it);
  643. }
  644. else
  645. {
  646. auto& letterInfo = _lettersInfo[letterIndex];
  647. auto& letterDef = _fontAtlas->_letterDefinitions[letterInfo.utf32Char];
  648. uvRect.size.height = letterDef.height;
  649. uvRect.size.width = letterDef.width;
  650. uvRect.origin.x = letterDef.U;
  651. uvRect.origin.y = letterDef.V;
  652. auto batchNode = _batchNodes.at(letterDef.textureID);
  653. letterSprite->setTextureAtlas(batchNode->getTextureAtlas());
  654. letterSprite->setTexture(_fontAtlas->getTexture(letterDef.textureID));
  655. if (letterDef.width <= 0.f || letterDef.height <= 0.f)
  656. {
  657. letterSprite->setTextureAtlas(nullptr);
  658. }
  659. else
  660. {
  661. letterSprite->setTextureRect(uvRect, false, uvRect.size);
  662. letterSprite->setTextureAtlas(_batchNodes.at(letterDef.textureID)->getTextureAtlas());
  663. letterSprite->setAtlasIndex(_lettersInfo[letterIndex].atlasIndex);
  664. }
  665. auto px = letterInfo.positionX + letterDef.width / 2 + _linesOffsetX[letterInfo.lineIndex];
  666. auto py = letterInfo.positionY - letterDef.height / 2 + _letterOffsetY;
  667. letterSprite->setPosition(px, py);
  668. this->updateLetterSpriteScale(letterSprite);
  669. ++it;
  670. }
  671. }
  672. }
  673. }
  674. bool Label::alignText()
  675. {
  676. if (_fontAtlas == nullptr || _utf32Text.empty())
  677. {
  678. setContentSize(Size::ZERO);
  679. return true;
  680. }
  681. bool ret = true;
  682. do {
  683. _fontAtlas->prepareLetterDefinitions(_utf32Text);
  684. auto& textures = _fontAtlas->getTextures();
  685. auto size = textures.size();
  686. if (size > static_cast<size_t>(_batchNodes.size()))
  687. {
  688. for (auto index = static_cast<size_t>(_batchNodes.size()); index < size; ++index)
  689. {
  690. auto batchNode = SpriteBatchNode::createWithTexture(textures.at(index));
  691. if (batchNode)
  692. {
  693. _isOpacityModifyRGB = batchNode->getTexture()->hasPremultipliedAlpha();
  694. _blendFunc = batchNode->getBlendFunc();
  695. batchNode->setAnchorPoint(Vec2::ANCHOR_TOP_LEFT);
  696. batchNode->setPosition(Vec2::ZERO);
  697. _batchNodes.pushBack(batchNode);
  698. }
  699. }
  700. }
  701. if (_batchNodes.empty())
  702. {
  703. return true;
  704. }
  705. // optimize for one-texture-only scenario
  706. // if multiple textures, then we should count how many chars
  707. // are per texture
  708. if (_batchNodes.size()==1)
  709. _batchNodes.at(0)->reserveCapacity(_utf32Text.size());
  710. _reusedLetter->setBatchNode(_batchNodes.at(0));
  711. _lengthOfString = 0;
  712. _textDesiredHeight = 0.f;
  713. _linesWidth.clear();
  714. if (_maxLineWidth > 0.f && !_lineBreakWithoutSpaces)
  715. {
  716. multilineTextWrapByWord();
  717. }
  718. else
  719. {
  720. multilineTextWrapByChar();
  721. }
  722. computeAlignmentOffset();
  723. if(_overflow == Overflow::SHRINK){
  724. float fontSize = this->getRenderingFontSize();
  725. if(fontSize > 0 && isVerticalClamp()){
  726. this->shrinkLabelToContentSize(CC_CALLBACK_0(Label::isVerticalClamp, this));
  727. }
  728. }
  729. if(!updateQuads()){
  730. ret = false;
  731. if(_overflow == Overflow::SHRINK){
  732. this->shrinkLabelToContentSize(CC_CALLBACK_0(Label::isHorizontalClamp, this));
  733. }
  734. break;
  735. }
  736. updateLabelLetters();
  737. updateColor();
  738. }while (0);
  739. return ret;
  740. }
  741. bool Label::computeHorizontalKernings(const std::u32string& stringToRender)
  742. {
  743. if (_horizontalKernings)
  744. {
  745. delete [] _horizontalKernings;
  746. _horizontalKernings = nullptr;
  747. }
  748. int letterCount = 0;
  749. _horizontalKernings = _fontAtlas->getFont()->getHorizontalKerningForTextUTF32(stringToRender, letterCount);
  750. if(!_horizontalKernings)
  751. return false;
  752. else
  753. return true;
  754. }
  755. bool Label::isHorizontalClamped(float letterPositionX, int lineIndex)
  756. {
  757. auto wordWidth = this->_linesWidth[lineIndex];
  758. bool letterOverClamp = (letterPositionX > _contentSize.width || letterPositionX < 0);
  759. if (!_enableWrap) {
  760. return letterOverClamp;
  761. }else{
  762. return (wordWidth > this->_contentSize.width && letterOverClamp);
  763. }
  764. }
  765. bool Label::updateQuads()
  766. {
  767. bool ret = true;
  768. for (auto&& batchNode : _batchNodes)
  769. {
  770. batchNode->getTextureAtlas()->removeAllQuads();
  771. }
  772. for (int ctr = 0; ctr < _lengthOfString; ++ctr)
  773. {
  774. if (_lettersInfo[ctr].valid)
  775. {
  776. auto& letterDef = _fontAtlas->_letterDefinitions[_lettersInfo[ctr].utf32Char];
  777. _reusedRect.size.height = letterDef.height;
  778. _reusedRect.size.width = letterDef.width;
  779. _reusedRect.origin.x = letterDef.U;
  780. _reusedRect.origin.y = letterDef.V;
  781. auto py = _lettersInfo[ctr].positionY + _letterOffsetY;
  782. if (_labelHeight > 0.f) {
  783. if (py > _tailoredTopY)
  784. {
  785. auto clipTop = py - _tailoredTopY;
  786. _reusedRect.origin.y += clipTop;
  787. _reusedRect.size.height -= clipTop;
  788. py -= clipTop;
  789. }
  790. if (py - letterDef.height * _bmfontScale < _tailoredBottomY)
  791. {
  792. _reusedRect.size.height = (py < _tailoredBottomY) ? 0.f : (py - _tailoredBottomY);
  793. }
  794. }
  795. auto lineIndex = _lettersInfo[ctr].lineIndex;
  796. auto px = _lettersInfo[ctr].positionX + letterDef.width/2 * _bmfontScale + _linesOffsetX[lineIndex];
  797. if(_labelWidth > 0.f){
  798. if (this->isHorizontalClamped(px, lineIndex)) {
  799. if(_overflow == Overflow::CLAMP){
  800. _reusedRect.size.width = 0;
  801. }else if(_overflow == Overflow::SHRINK){
  802. if (_contentSize.width > letterDef.width) {
  803. ret = false;
  804. break;
  805. }else{
  806. _reusedRect.size.width = 0;
  807. }
  808. }
  809. }
  810. }
  811. if (_reusedRect.size.height > 0.f && _reusedRect.size.width > 0.f)
  812. {
  813. _reusedLetter->setTextureRect(_reusedRect, false, _reusedRect.size);
  814. float letterPositionX = _lettersInfo[ctr].positionX + _linesOffsetX[_lettersInfo[ctr].lineIndex];
  815. _reusedLetter->setPosition(letterPositionX, py);
  816. auto index = static_cast<int>(_batchNodes.at(letterDef.textureID)->getTextureAtlas()->getTotalQuads());
  817. _lettersInfo[ctr].atlasIndex = index;
  818. this->updateLetterSpriteScale(_reusedLetter);
  819. _batchNodes.at(letterDef.textureID)->insertQuadFromSprite(_reusedLetter, index);
  820. }
  821. }
  822. }
  823. return ret;
  824. }
  825. bool Label::setTTFConfigInternal(const TTFConfig& ttfConfig)
  826. {
  827. FontAtlas *newAtlas = FontAtlasCache::getFontAtlasTTF(&ttfConfig);
  828. if (!newAtlas)
  829. {
  830. reset();
  831. return false;
  832. }
  833. _currentLabelType = LabelType::TTF;
  834. setFontAtlas(newAtlas,ttfConfig.distanceFieldEnabled,true);
  835. _fontConfig = ttfConfig;
  836. if (_fontConfig.outlineSize > 0)
  837. {
  838. _fontConfig.distanceFieldEnabled = false;
  839. _useDistanceField = false;
  840. _useA8Shader = false;
  841. _currLabelEffect = LabelEffect::OUTLINE;
  842. updateShaderProgram();
  843. }
  844. else
  845. {
  846. _currLabelEffect = LabelEffect::NORMAL;
  847. updateShaderProgram();
  848. }
  849. if (_fontConfig.italics)
  850. this->enableItalics();
  851. if (_fontConfig.bold)
  852. this->enableBold();
  853. if (_fontConfig.underline)
  854. this->enableUnderline();
  855. if (_fontConfig.strikethrough)
  856. this->enableStrikethrough();
  857. return true;
  858. }
  859. void Label::setBMFontSizeInternal(float fontSize)
  860. {
  861. if(_currentLabelType == LabelType::BMFONT){
  862. this->setBMFontFilePath(_bmFontPath, Vec2::ZERO, fontSize);
  863. _contentDirty = true;
  864. }
  865. }
  866. void Label::scaleFontSizeDown(float fontSize)
  867. {
  868. bool shouldUpdateContent = true;
  869. if(_currentLabelType == LabelType::TTF){
  870. auto ttfConfig = this->getTTFConfig();
  871. ttfConfig.fontSize = fontSize;
  872. this->setTTFConfigInternal(ttfConfig);
  873. }else if(_currentLabelType == LabelType::BMFONT){
  874. if (std::abs(fontSize) < FLT_EPSILON) {
  875. fontSize = 0.1f;
  876. shouldUpdateContent = false;
  877. }
  878. this->setBMFontSizeInternal(fontSize);
  879. }else if (_currentLabelType == LabelType::STRING_TEXTURE){
  880. this->setSystemFontSize(fontSize);
  881. }
  882. if (shouldUpdateContent) {
  883. this->updateContent();
  884. }
  885. }
  886. void Label::enableGlow(const Color4B& glowColor)
  887. {
  888. if (_currentLabelType == LabelType::TTF)
  889. {
  890. if (_fontConfig.distanceFieldEnabled == false)
  891. {
  892. auto config = _fontConfig;
  893. config.outlineSize = 0;
  894. config.distanceFieldEnabled = true;
  895. setTTFConfig(config);
  896. _contentDirty = true;
  897. }
  898. _currLabelEffect = LabelEffect::GLOW;
  899. _effectColorF.r = glowColor.r / 255.0f;
  900. _effectColorF.g = glowColor.g / 255.0f;
  901. _effectColorF.b = glowColor.b / 255.0f;
  902. _effectColorF.a = glowColor.a / 255.0f;
  903. updateShaderProgram();
  904. }
  905. }
  906. void Label::enableOutline(const Color4B& outlineColor,int outlineSize /* = -1 */)
  907. {
  908. CCASSERT(_currentLabelType == LabelType::STRING_TEXTURE || _currentLabelType == LabelType::TTF, "Only supported system font and TTF!");
  909. if (outlineSize > 0 || _currLabelEffect == LabelEffect::OUTLINE)
  910. {
  911. if (_currentLabelType == LabelType::TTF)
  912. {
  913. _effectColorF.r = outlineColor.r / 255.0f;
  914. _effectColorF.g = outlineColor.g / 255.0f;
  915. _effectColorF.b = outlineColor.b / 255.0f;
  916. _effectColorF.a = outlineColor.a / 255.0f;
  917. if (outlineSize > 0 && _fontConfig.outlineSize != outlineSize)
  918. {
  919. _fontConfig.outlineSize = outlineSize;
  920. setTTFConfig(_fontConfig);
  921. }
  922. }
  923. else if (_effectColorF != outlineColor || _outlineSize != outlineSize)
  924. {
  925. _effectColorF.r = outlineColor.r / 255.f;
  926. _effectColorF.g = outlineColor.g / 255.f;
  927. _effectColorF.b = outlineColor.b / 255.f;
  928. _effectColorF.a = outlineColor.a / 255.f;
  929. _currLabelEffect = LabelEffect::OUTLINE;
  930. _contentDirty = true;
  931. }
  932. _outlineSize = outlineSize;
  933. }
  934. }
  935. void Label::enableShadow(const Color4B& shadowColor /* = Color4B::BLACK */,
  936. const Size &offset /* = Size(2 ,-2)*/,
  937. int /* blurRadius = 0 */)
  938. {
  939. _shadowEnabled = true;
  940. _shadowDirty = true;
  941. _shadowOffset.width = offset.width;
  942. _shadowOffset.height = offset.height;
  943. //TODO: support blur for shadow
  944. _shadowColor3B.r = shadowColor.r;
  945. _shadowColor3B.g = shadowColor.g;
  946. _shadowColor3B.b = shadowColor.b;
  947. _shadowOpacity = shadowColor.a;
  948. if (!_systemFontDirty && !_contentDirty && _textSprite)
  949. {
  950. auto fontDef = _getFontDefinition();
  951. if (_shadowNode)
  952. {
  953. if (shadowColor != _shadowColor4F)
  954. {
  955. _shadowNode->release();
  956. _shadowNode = nullptr;
  957. createShadowSpriteForSystemFont(fontDef);
  958. }
  959. else
  960. {
  961. _shadowNode->setPosition(_shadowOffset.width, _shadowOffset.height);
  962. }
  963. }
  964. else
  965. {
  966. createShadowSpriteForSystemFont(fontDef);
  967. }
  968. }
  969. _shadowColor4F.r = shadowColor.r / 255.0f;
  970. _shadowColor4F.g = shadowColor.g / 255.0f;
  971. _shadowColor4F.b = shadowColor.b / 255.0f;
  972. _shadowColor4F.a = shadowColor.a / 255.0f;
  973. if (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP)
  974. {
  975. setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(_shadowEnabled ? GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR : GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, _getTexture(this)));
  976. }
  977. }
  978. void Label::enableItalics()
  979. {
  980. setRotationSkewX(12);
  981. }
  982. void Label::enableBold()
  983. {
  984. if (!_boldEnabled)
  985. {
  986. // bold is implemented with outline
  987. enableShadow(Color4B::WHITE, Size(0.9f, 0), 0);
  988. // add one to kerning
  989. setAdditionalKerning(_additionalKerning+1);
  990. _boldEnabled = true;
  991. }
  992. }
  993. void Label::enableUnderline()
  994. {
  995. // remove it, just in case to prevent adding two or more
  996. if (!_underlineNode)
  997. {
  998. _underlineNode = DrawNode::create();
  999. addChild(_underlineNode, 100000);
  1000. _contentDirty = true;
  1001. }
  1002. }
  1003. void Label::enableStrikethrough()
  1004. {
  1005. if (!_strikethroughEnabled)
  1006. {
  1007. enableUnderline();
  1008. _strikethroughEnabled = true;
  1009. }
  1010. }
  1011. void Label::disableEffect()
  1012. {
  1013. disableEffect(LabelEffect::ALL);
  1014. }
  1015. void Label::disableEffect(LabelEffect effect)
  1016. {
  1017. switch (effect)
  1018. {
  1019. case cocos2d::LabelEffect::NORMAL:
  1020. break;
  1021. case cocos2d::LabelEffect::OUTLINE:
  1022. if (_currLabelEffect == LabelEffect::OUTLINE)
  1023. {
  1024. if (_currentLabelType == LabelType::TTF)
  1025. {
  1026. _fontConfig.outlineSize = 0;
  1027. setTTFConfig(_fontConfig);
  1028. }
  1029. _currLabelEffect = LabelEffect::NORMAL;
  1030. _contentDirty = true;
  1031. }
  1032. break;
  1033. case cocos2d::LabelEffect::SHADOW:
  1034. if (_shadowEnabled)
  1035. {
  1036. _shadowEnabled = false;
  1037. CC_SAFE_RELEASE_NULL(_shadowNode);
  1038. updateShaderProgram();
  1039. }
  1040. break;
  1041. case cocos2d::LabelEffect::GLOW:
  1042. if (_currLabelEffect == LabelEffect::GLOW)
  1043. {
  1044. _currLabelEffect = LabelEffect::NORMAL;
  1045. updateShaderProgram();
  1046. }
  1047. break;
  1048. case cocos2d::LabelEffect::ITALICS:
  1049. setRotationSkewX(0);
  1050. break;
  1051. case cocos2d::LabelEffect::BOLD:
  1052. if (_boldEnabled) {
  1053. _boldEnabled = false;
  1054. _additionalKerning -= 1;
  1055. disableEffect(LabelEffect::SHADOW);
  1056. }
  1057. break;
  1058. case cocos2d::LabelEffect::UNDERLINE:
  1059. if (_underlineNode) {
  1060. removeChild(_underlineNode);
  1061. _underlineNode = nullptr;
  1062. }
  1063. break;
  1064. case cocos2d::LabelEffect::STRIKETHROUGH:
  1065. _strikethroughEnabled = false;
  1066. // since it is based on underline, disable it as well
  1067. disableEffect(LabelEffect::UNDERLINE);
  1068. break;
  1069. case LabelEffect::ALL:
  1070. {
  1071. disableEffect(LabelEffect::SHADOW);
  1072. disableEffect(LabelEffect::GLOW);
  1073. disableEffect(LabelEffect::OUTLINE);
  1074. disableEffect(LabelEffect::ITALICS);
  1075. disableEffect(LabelEffect::BOLD);
  1076. disableEffect(LabelEffect::UNDERLINE);
  1077. disableEffect(LabelEffect::STRIKETHROUGH);
  1078. }
  1079. break;
  1080. default:
  1081. break;
  1082. }
  1083. }
  1084. void Label::createSpriteForSystemFont(const FontDefinition& fontDef)
  1085. {
  1086. _currentLabelType = LabelType::STRING_TEXTURE;
  1087. auto texture = new (std::nothrow) Texture2D;
  1088. texture->initWithString(_utf8Text.c_str(), fontDef);
  1089. _textSprite = Sprite::createWithTexture(texture);
  1090. //set camera mask using label's camera mask, because _textSprite may be null when setting camera mask to label
  1091. _textSprite->setCameraMask(getCameraMask());
  1092. _textSprite->setGlobalZOrder(getGlobalZOrder());
  1093. _textSprite->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
  1094. this->setContentSize(_textSprite->getContentSize());
  1095. texture->release();
  1096. if (_blendFuncDirty)
  1097. {
  1098. _textSprite->setBlendFunc(_blendFunc);
  1099. }
  1100. _textSprite->retain();
  1101. _textSprite->updateDisplayedColor(_displayedColor);
  1102. _textSprite->updateDisplayedOpacity(_displayedOpacity);
  1103. }
  1104. void Label::createShadowSpriteForSystemFont(const FontDefinition& fontDef)
  1105. {
  1106. if (!fontDef._stroke._strokeEnabled && fontDef._fontFillColor == _shadowColor3B
  1107. && (fontDef._fontAlpha == _shadowOpacity))
  1108. {
  1109. _shadowNode = Sprite::createWithTexture(_textSprite->getTexture());
  1110. }
  1111. else
  1112. {
  1113. FontDefinition shadowFontDefinition = fontDef;
  1114. shadowFontDefinition._fontFillColor.r = _shadowColor3B.r;
  1115. shadowFontDefinition._fontFillColor.g = _shadowColor3B.g;
  1116. shadowFontDefinition._fontFillColor.b = _shadowColor3B.b;
  1117. shadowFontDefinition._fontAlpha = _shadowOpacity;
  1118. shadowFontDefinition._stroke._strokeColor = shadowFontDefinition._fontFillColor;
  1119. shadowFontDefinition._stroke._strokeAlpha = shadowFontDefinition._fontAlpha;
  1120. auto texture = new (std::nothrow) Texture2D;
  1121. texture->initWithString(_utf8Text.c_str(), shadowFontDefinition);
  1122. _shadowNode = Sprite::createWithTexture(texture);
  1123. texture->release();
  1124. }
  1125. if (_shadowNode)
  1126. {
  1127. if (_blendFuncDirty)
  1128. {
  1129. _shadowNode->setBlendFunc(_blendFunc);
  1130. }
  1131. _shadowNode->setCameraMask(getCameraMask());
  1132. _shadowNode->setGlobalZOrder(getGlobalZOrder());
  1133. _shadowNode->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
  1134. _shadowNode->setPosition(_shadowOffset.width, _shadowOffset.height);
  1135. _shadowNode->retain();
  1136. _shadowNode->updateDisplayedColor(_displayedColor);
  1137. _shadowNode->updateDisplayedOpacity(_displayedOpacity);
  1138. }
  1139. }
  1140. void Label::setCameraMask(unsigned short mask, bool applyChildren)
  1141. {
  1142. Node::setCameraMask(mask, applyChildren);
  1143. if (_textSprite)
  1144. {
  1145. _textSprite->setCameraMask(mask, applyChildren);
  1146. }
  1147. if (_shadowNode)
  1148. {
  1149. _shadowNode->setCameraMask(mask, applyChildren);
  1150. }
  1151. }
  1152. void Label::setFontDefinition(const FontDefinition& textDefinition)
  1153. {
  1154. _systemFont = textDefinition._fontName;
  1155. _systemFontSize = textDefinition._fontSize;
  1156. _hAlignment = textDefinition._alignment;
  1157. _vAlignment = textDefinition._vertAlignment;
  1158. setDimensions(textDefinition._dimensions.width, textDefinition._dimensions.height);
  1159. Color4B textColor = Color4B(textDefinition._fontFillColor);
  1160. textColor.a = textDefinition._fontAlpha;
  1161. setTextColor(textColor);
  1162. #if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) && (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
  1163. if (textDefinition._stroke._strokeEnabled)
  1164. {
  1165. CCLOGERROR("Stroke Currently only supported on iOS and Android!");
  1166. }
  1167. _outlineSize = 0.f;
  1168. #else
  1169. if (textDefinition._stroke._strokeEnabled && textDefinition._stroke._strokeSize > 0.f)
  1170. {
  1171. Color4B outlineColor = Color4B(textDefinition._stroke._strokeColor);
  1172. outlineColor.a = textDefinition._stroke._strokeAlpha;
  1173. enableOutline(outlineColor, textDefinition._stroke._strokeSize);
  1174. }
  1175. #endif
  1176. if (textDefinition._shadow._shadowEnabled)
  1177. {
  1178. enableShadow(Color4B(0, 0, 0, 255 * textDefinition._shadow._shadowOpacity),
  1179. textDefinition._shadow._shadowOffset, textDefinition._shadow._shadowBlur);
  1180. }
  1181. }
  1182. void Label::updateContent()
  1183. {
  1184. if (_systemFontDirty)
  1185. {
  1186. if (_fontAtlas)
  1187. {
  1188. _batchNodes.clear();
  1189. CC_SAFE_RELEASE_NULL(_reusedLetter);
  1190. FontAtlasCache::releaseFontAtlas(_fontAtlas);
  1191. _fontAtlas = nullptr;
  1192. }
  1193. _systemFontDirty = false;
  1194. }
  1195. CC_SAFE_RELEASE_NULL(_textSprite);
  1196. CC_SAFE_RELEASE_NULL(_shadowNode);
  1197. bool updateFinished = true;
  1198. if (_fontAtlas)
  1199. {
  1200. std::u32string utf32String;
  1201. if (StringUtils::UTF8ToUTF32(_utf8Text, utf32String))
  1202. {
  1203. _utf32Text = utf32String;
  1204. }
  1205. computeHorizontalKernings(_utf32Text);
  1206. updateFinished = alignText();
  1207. }
  1208. else
  1209. {
  1210. auto fontDef = _getFontDefinition();
  1211. createSpriteForSystemFont(fontDef);
  1212. if (_shadowEnabled)
  1213. {
  1214. createShadowSpriteForSystemFont(fontDef);
  1215. }
  1216. }
  1217. if (_underlineNode)
  1218. {
  1219. _underlineNode->clear();
  1220. if (_numberOfLines)
  1221. {
  1222. // This is the logic for TTF fonts
  1223. const float charheight = (_textDesiredHeight / _numberOfLines);
  1224. _underlineNode->setLineWidth(charheight/6);
  1225. // atlas font
  1226. for (int i=0; i<_numberOfLines; ++i)
  1227. {
  1228. float offsety = 0;
  1229. if (_strikethroughEnabled)
  1230. offsety += charheight / 2;
  1231. // FIXME: Might not work with different vertical alignments
  1232. float y = (_numberOfLines - i - 1) * charheight + offsety;
  1233. // Github issue #15214. Uses _displayedColor instead of _textColor for the underline.
  1234. // This is to have the same behavior of SystemFonts.
  1235. _underlineNode->drawLine(Vec2(_linesOffsetX[i],y), Vec2(_linesWidth[i] + _linesOffsetX[i],y), Color4F(_displayedColor));
  1236. }
  1237. }
  1238. else if (_textSprite)
  1239. {
  1240. // ...and is the logic for System fonts
  1241. float y = 0;
  1242. const auto spriteSize = _textSprite->getContentSize();
  1243. _underlineNode->setLineWidth(spriteSize.height/6);
  1244. if (_strikethroughEnabled)
  1245. // FIXME: system fonts don't report the height of the font correctly. only the size of the texture, which is POT
  1246. y += spriteSize.height / 2;
  1247. // FIXME: Might not work with different vertical alignments
  1248. _underlineNode->drawLine(Vec2(0,y), Vec2(spriteSize.width,y), Color4F(_textSprite->getDisplayedColor()));
  1249. }
  1250. }
  1251. if(updateFinished){
  1252. _contentDirty = false;
  1253. }
  1254. #if CC_LABEL_DEBUG_DRAW
  1255. _debugDrawNode->clear();
  1256. Vec2 vertices[4] =
  1257. {
  1258. Vec2::ZERO,
  1259. Vec2(_contentSize.width, 0),
  1260. Vec2(_contentSize.width, _contentSize.height),
  1261. Vec2(0, _contentSize.height)
  1262. };
  1263. _debugDrawNode->drawPoly(vertices, 4, true, Color4F::WHITE);
  1264. #endif
  1265. }
  1266. void Label::setBMFontSize(float fontSize)
  1267. {
  1268. this->setBMFontSizeInternal(fontSize);
  1269. _originalFontSize = fontSize;
  1270. }
  1271. float Label::getBMFontSize()const
  1272. {
  1273. return _bmFontSize;
  1274. }
  1275. void Label::onDrawShadow(GLProgram* glProgram, const Color4F& shadowColor)
  1276. {
  1277. if (_currentLabelType == LabelType::TTF)
  1278. {
  1279. if (_currLabelEffect == LabelEffect::OUTLINE)
  1280. {
  1281. glProgram->setUniformLocationWith1i(_uniformEffectType, 2); // 2: shadow
  1282. glProgram->setUniformLocationWith4f(_uniformEffectColor, shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
  1283. }
  1284. else
  1285. {
  1286. glProgram->setUniformLocationWith4f(_uniformTextColor, shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
  1287. if (_currLabelEffect == LabelEffect::GLOW)
  1288. {
  1289. glProgram->setUniformLocationWith4f(_uniformEffectColor, shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
  1290. }
  1291. }
  1292. glProgram->setUniformsForBuiltins(_shadowTransform);
  1293. for (auto&& it : _letters)
  1294. {
  1295. it.second->updateTransform();
  1296. }
  1297. for (auto&& batchNode : _batchNodes)
  1298. {
  1299. batchNode->getTextureAtlas()->drawQuads();
  1300. }
  1301. }
  1302. else
  1303. {
  1304. Color3B oldColor = _realColor;
  1305. GLubyte oldOPacity = _displayedOpacity;
  1306. _displayedOpacity = shadowColor.a * (oldOPacity / 255.0f) * 255;
  1307. setColor(Color3B(shadowColor));
  1308. glProgram->setUniformsForBuiltins(_shadowTransform);
  1309. for (auto&& it : _letters)
  1310. {
  1311. it.second->updateTransform();
  1312. }
  1313. for (auto&& batchNode : _batchNodes)
  1314. {
  1315. batchNode->getTextureAtlas()->drawQuads();
  1316. }
  1317. _displayedOpacity = oldOPacity;
  1318. setColor(oldColor);
  1319. }
  1320. }
  1321. void Label::onDraw(const Mat4& transform, bool /*transformUpdated*/)
  1322. {
  1323. auto glprogram = getGLProgram();
  1324. glprogram->use();
  1325. GL::blendFunc(_blendFunc.src, _blendFunc.dst);
  1326. if (_shadowEnabled)
  1327. {
  1328. if (_boldEnabled)
  1329. onDrawShadow(glprogram, _textColorF);
  1330. else
  1331. onDrawShadow(glprogram, _shadowColor4F);
  1332. }
  1333. glprogram->setUniformsForBuiltins(transform);
  1334. for (auto&& it : _letters)
  1335. {
  1336. it.second->updateTransform();
  1337. }
  1338. if (_currentLabelType == LabelType::TTF)
  1339. {
  1340. switch (_currLabelEffect) {
  1341. case LabelEffect::OUTLINE:
  1342. // draw outline of text
  1343. glprogram->setUniformLocationWith1i(_uniformEffectType, 1); // 1: outline
  1344. glprogram->setUniformLocationWith4f(_uniformEffectColor,
  1345. _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a);
  1346. for (auto&& batchNode : _batchNodes)
  1347. {
  1348. batchNode->getTextureAtlas()->drawQuads();
  1349. }
  1350. // draw text without outline
  1351. glprogram->setUniformLocationWith1i(_uniformEffectType, 0); // 0: text
  1352. glprogram->setUniformLocationWith4f(_uniformTextColor, _textColorF.r, _textColorF.g, _textColorF.b, _textColorF.a);
  1353. break;
  1354. case LabelEffect::GLOW:
  1355. glprogram->setUniformLocationWith4f(_uniformEffectColor,
  1356. _effectColorF.r, _effectColorF.g, _effectColorF.b, _effectColorF.a);
  1357. case LabelEffect::NORMAL:
  1358. glprogram->setUniformLocationWith4f(_uniformTextColor,
  1359. _textColorF.r, _textColorF.g, _textColorF.b, _textColorF.a);
  1360. break;
  1361. default:
  1362. break;
  1363. }
  1364. }
  1365. for (auto&& batchNode : _batchNodes)
  1366. {
  1367. batchNode->getTextureAtlas()->drawQuads();
  1368. }
  1369. }
  1370. void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
  1371. {
  1372. if (_batchNodes.empty() || _lengthOfString <= 0)
  1373. {
  1374. return;
  1375. }
  1376. // Don't do calculate the culling if the transform was not updated
  1377. bool transformUpdated = flags & FLAGS_TRANSFORM_DIRTY;
  1378. #if CC_USE_CULLING
  1379. auto visitingCamera = Camera::getVisitingCamera();
  1380. auto defaultCamera = Camera::getDefaultCamera();
  1381. if (visitingCamera == defaultCamera) {
  1382. _insideBounds = (transformUpdated || visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
  1383. }
  1384. else
  1385. {
  1386. _insideBounds = renderer->checkVisibility(transform, _contentSize);
  1387. }
  1388. if (_insideBounds)
  1389. #endif
  1390. {
  1391. if (!_shadowEnabled && (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP))
  1392. {
  1393. for (auto&& it : _letters)
  1394. {
  1395. it.second->updateTransform();
  1396. }
  1397. // ETC1 ALPHA supports for BMFONT & CHARMAP
  1398. auto textureAtlas = _batchNodes.at(0)->getTextureAtlas();
  1399. auto texture = textureAtlas->getTexture();
  1400. _quadCommand.init(_globalZOrder, texture, getGLProgramState(),
  1401. _blendFunc, textureAtlas->getQuads(), textureAtlas->getTotalQuads(), transform, flags);
  1402. renderer->addCommand(&_quadCommand);
  1403. }
  1404. else
  1405. {
  1406. _customCommand.init(_globalZOrder, transform, flags);
  1407. _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated);
  1408. renderer->addCommand(&_customCommand);
  1409. }
  1410. }
  1411. }
  1412. void Label::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
  1413. {
  1414. if (! _visible || (_utf8Text.empty() && _children.empty()) )
  1415. {
  1416. return;
  1417. }
  1418. if (_systemFontDirty || _contentDirty)
  1419. {
  1420. updateContent();
  1421. }
  1422. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  1423. if (!_utf8Text.empty() && _shadowEnabled && (_shadowDirty || (flags & FLAGS_DIRTY_MASK)))
  1424. {
  1425. _position.x += _shadowOffset.width;
  1426. _position.y += _shadowOffset.height;
  1427. _transformDirty = _inverseDirty = true;
  1428. _shadowTransform = transform(parentTransform);
  1429. _position.x -= _shadowOffset.width;
  1430. _position.y -= _shadowOffset.height;
  1431. _transformDirty = _inverseDirty = true;
  1432. _shadowDirty = false;
  1433. }
  1434. bool visibleByCamera = isVisitableByVisitingCamera();
  1435. if (_children.empty() && !_textSprite && !visibleByCamera)
  1436. {
  1437. return;
  1438. }
  1439. // IMPORTANT:
  1440. // To ease the migration to v3.0, we still support the Mat4 stack,
  1441. // but it is deprecated and your code should not rely on it
  1442. _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  1443. _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  1444. if (!_children.empty())
  1445. {
  1446. sortAllChildren();
  1447. int i = 0;
  1448. // draw children zOrder < 0
  1449. for (auto size = _children.size(); i < size; ++i)
  1450. {
  1451. auto node = _children.at(i);
  1452. if (node && node->getLocalZOrder() < 0)
  1453. node->visit(renderer, _modelViewTransform, flags);
  1454. else
  1455. break;
  1456. }
  1457. this->drawSelf(visibleByCamera, renderer, flags);
  1458. for (auto it = _children.cbegin() + i, itCend = _children.cend(); it != itCend; ++it)
  1459. {
  1460. (*it)->visit(renderer, _modelViewTransform, flags);
  1461. }
  1462. }
  1463. else
  1464. {
  1465. this->drawSelf(visibleByCamera, renderer, flags);
  1466. }
  1467. _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  1468. }
  1469. void Label::drawSelf(bool visibleByCamera, Renderer* renderer, uint32_t flags)
  1470. {
  1471. if (_textSprite)
  1472. {
  1473. if (_shadowNode)
  1474. {
  1475. _shadowNode->visit(renderer, _modelViewTransform, flags);
  1476. }
  1477. _textSprite->visit(renderer, _modelViewTransform, flags);
  1478. }
  1479. else if (visibleByCamera && !_utf8Text.empty())
  1480. {
  1481. draw(renderer, _modelViewTransform, flags);
  1482. }
  1483. }
  1484. void Label::setSystemFontName(const std::string& systemFont)
  1485. {
  1486. if (systemFont != _systemFont)
  1487. {
  1488. _systemFont = systemFont;
  1489. _currentLabelType = LabelType::STRING_TEXTURE;
  1490. _systemFontDirty = true;
  1491. }
  1492. }
  1493. void Label::setSystemFontSize(float fontSize)
  1494. {
  1495. if (_systemFontSize != fontSize)
  1496. {
  1497. _systemFontSize = fontSize;
  1498. _originalFontSize = fontSize;
  1499. _currentLabelType = LabelType::STRING_TEXTURE;
  1500. _systemFontDirty = true;
  1501. }
  1502. }
  1503. ///// PROTOCOL STUFF
  1504. Sprite* Label::getLetter(int letterIndex)
  1505. {
  1506. Sprite* letter = nullptr;
  1507. do
  1508. {
  1509. if (_systemFontDirty || _currentLabelType == LabelType::STRING_TEXTURE)
  1510. {
  1511. break;
  1512. }
  1513. auto contentDirty = _contentDirty;
  1514. if (contentDirty)
  1515. {
  1516. updateContent();
  1517. }
  1518. if (_textSprite == nullptr && letterIndex < _lengthOfString)
  1519. {
  1520. const auto &letterInfo = _lettersInfo[letterIndex];
  1521. if (!letterInfo.valid || letterInfo.atlasIndex<0)
  1522. {
  1523. break;
  1524. }
  1525. if (_letters.find(letterIndex) != _letters.end())
  1526. {
  1527. letter = _letters[letterIndex];
  1528. }
  1529. if (letter == nullptr)
  1530. {
  1531. auto& letterDef = _fontAtlas->_letterDefinitions[letterInfo.utf32Char];
  1532. auto textureID = letterDef.textureID;
  1533. Rect uvRect;
  1534. uvRect.size.height = letterDef.height;
  1535. uvRect.size.width = letterDef.width;
  1536. uvRect.origin.x = letterDef.U;
  1537. uvRect.origin.y = letterDef.V;
  1538. if (letterDef.width <= 0.f || letterDef.height <= 0.f)
  1539. {
  1540. letter = LabelLetter::create();
  1541. }
  1542. else
  1543. {
  1544. this->updateBMFontScale();
  1545. letter = LabelLetter::createWithTexture(_fontAtlas->getTexture(textureID), uvRect);
  1546. letter->setTextureAtlas(_batchNodes.at(textureID)->getTextureAtlas());
  1547. letter->setAtlasIndex(letterInfo.atlasIndex);
  1548. auto px = letterInfo.positionX + _bmfontScale * uvRect.size.width / 2 + _linesOffsetX[letterInfo.lineIndex];
  1549. auto py = letterInfo.positionY - _bmfontScale * uvRect.size.height / 2 + _letterOffsetY;
  1550. letter->setPosition(px,py);
  1551. letter->setOpacity(_realOpacity);
  1552. this->updateLetterSpriteScale(letter);
  1553. }
  1554. addChild(letter);
  1555. _letters[letterIndex] = letter;
  1556. }
  1557. }
  1558. } while (false);
  1559. return letter;
  1560. }
  1561. void Label::setLineHeight(float height)
  1562. {
  1563. CCASSERT(_currentLabelType != LabelType::STRING_TEXTURE, "Not supported system font!");
  1564. if (_lineHeight != height)
  1565. {
  1566. _lineHeight = height;
  1567. _contentDirty = true;
  1568. }
  1569. }
  1570. float Label::getLineHeight() const
  1571. {
  1572. CCASSERT(_currentLabelType != LabelType::STRING_TEXTURE, "Not supported system font!");
  1573. return _textSprite ? 0.0f : _lineHeight * _bmfontScale;
  1574. }
  1575. void Label::setLineSpacing(float height)
  1576. {
  1577. if (_lineSpacing != height)
  1578. {
  1579. _lineSpacing = height;
  1580. _contentDirty = true;
  1581. }
  1582. }
  1583. float Label::getLineSpacing() const
  1584. {
  1585. return _lineSpacing;
  1586. }
  1587. void Label::setAdditionalKerning(float space)
  1588. {
  1589. if (_currentLabelType != LabelType::STRING_TEXTURE)
  1590. {
  1591. if (_additionalKerning != space)
  1592. {
  1593. _additionalKerning = space;
  1594. _contentDirty = true;
  1595. }
  1596. }
  1597. else
  1598. CCLOG("Label::setAdditionalKerning not supported on LabelType::STRING_TEXTURE");
  1599. }
  1600. float Label::getAdditionalKerning() const
  1601. {
  1602. CCASSERT(_currentLabelType != LabelType::STRING_TEXTURE, "Not supported system font!");
  1603. return _additionalKerning;
  1604. }
  1605. void Label::computeStringNumLines()
  1606. {
  1607. int quantityOfLines = 1;
  1608. if (_utf32Text.empty())
  1609. {
  1610. _numberOfLines = 0;
  1611. return;
  1612. }
  1613. // count number of lines
  1614. size_t stringLen = _utf32Text.length();
  1615. for (size_t i = 0; i < stringLen - 1; ++i)
  1616. {
  1617. if (_utf32Text[i] == StringUtils::UnicodeCharacters::NewLine)
  1618. {
  1619. quantityOfLines++;
  1620. }
  1621. }
  1622. _numberOfLines = quantityOfLines;
  1623. }
  1624. int Label::getStringNumLines()
  1625. {
  1626. if (_contentDirty)
  1627. {
  1628. updateContent();
  1629. }
  1630. if (_currentLabelType == LabelType::STRING_TEXTURE)
  1631. {
  1632. computeStringNumLines();
  1633. }
  1634. return _numberOfLines;
  1635. }
  1636. int Label::getStringLength()
  1637. {
  1638. _lengthOfString = static_cast<int>(_utf32Text.length());
  1639. return _lengthOfString;
  1640. }
  1641. // RGBA protocol
  1642. void Label::setOpacityModifyRGB(bool isOpacityModifyRGB)
  1643. {
  1644. if (isOpacityModifyRGB != _isOpacityModifyRGB)
  1645. {
  1646. _isOpacityModifyRGB = isOpacityModifyRGB;
  1647. updateColor();
  1648. }
  1649. }
  1650. void Label::updateDisplayedColor(const Color3B& parentColor)
  1651. {
  1652. Node::updateDisplayedColor(parentColor);
  1653. if (_textSprite)
  1654. {
  1655. _textSprite->updateDisplayedColor(_displayedColor);
  1656. }
  1657. if (_shadowNode)
  1658. {
  1659. _shadowNode->updateDisplayedColor(_displayedColor);
  1660. }
  1661. if (_underlineNode)
  1662. {
  1663. // FIXME: _underlineNode is not a sprite/label. It is a DrawNode
  1664. // and updating its color doesn't work. it must be re-drawn,
  1665. // which makes it super expensive to change update it frequently
  1666. // Correct solution is to update the DrawNode directly since we know it is
  1667. // a line. Returning a pointer to the line is an option
  1668. _contentDirty = true;
  1669. }
  1670. for (auto&& it : _letters)
  1671. {
  1672. it.second->updateDisplayedColor(_displayedColor);
  1673. }
  1674. }
  1675. void Label::updateDisplayedOpacity(GLubyte parentOpacity)
  1676. {
  1677. Node::updateDisplayedOpacity(parentOpacity);
  1678. if (_textSprite)
  1679. {
  1680. _textSprite->updateDisplayedOpacity(_displayedOpacity);
  1681. if (_shadowNode)
  1682. {
  1683. _shadowNode->updateDisplayedOpacity(_displayedOpacity);
  1684. }
  1685. }
  1686. for (auto&& it : _letters)
  1687. {
  1688. it.second->updateDisplayedOpacity(_displayedOpacity);
  1689. }
  1690. }
  1691. // FIXME: it is not clear what is the difference between setTextColor() and setColor()
  1692. // if setTextColor() only changes the text and nothing but the text (no glow, no outline, not underline)
  1693. // that's fine but it should be documented
  1694. void Label::setTextColor(const Color4B &color)
  1695. {
  1696. CCASSERT(_currentLabelType == LabelType::TTF || _currentLabelType == LabelType::STRING_TEXTURE, "Only supported system font and ttf!");
  1697. if (_currentLabelType == LabelType::STRING_TEXTURE && _textColor != color)
  1698. {
  1699. _contentDirty = true;
  1700. }
  1701. _textColor = color;
  1702. _textColorF.r = _textColor.r / 255.0f;
  1703. _textColorF.g = _textColor.g / 255.0f;
  1704. _textColorF.b = _textColor.b / 255.0f;
  1705. _textColorF.a = _textColor.a / 255.0f;
  1706. }
  1707. void Label::updateColor()
  1708. {
  1709. if (_batchNodes.empty())
  1710. {
  1711. return;
  1712. }
  1713. Color4B color4( _displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity );
  1714. // special opacity for premultiplied textures
  1715. if (_isOpacityModifyRGB)
  1716. {
  1717. color4.r *= _displayedOpacity/255.0f;
  1718. color4.g *= _displayedOpacity/255.0f;
  1719. color4.b *= _displayedOpacity/255.0f;
  1720. }
  1721. cocos2d::TextureAtlas* textureAtlas;
  1722. V3F_C4B_T2F_Quad *quads;
  1723. for (auto&& batchNode:_batchNodes)
  1724. {
  1725. textureAtlas = batchNode->getTextureAtlas();
  1726. quads = textureAtlas->getQuads();
  1727. auto count = textureAtlas->getTotalQuads();
  1728. for (int index = 0; index < count; ++index)
  1729. {
  1730. quads[index].bl.colors = color4;
  1731. quads[index].br.colors = color4;
  1732. quads[index].tl.colors = color4;
  1733. quads[index].tr.colors = color4;
  1734. textureAtlas->updateQuad(&quads[index], index);
  1735. }
  1736. }
  1737. }
  1738. std::string Label::getDescription() const
  1739. {
  1740. char tmp[50];
  1741. sprintf(tmp, "<Label | Tag = %d, Label = >", _tag);
  1742. std::string ret = tmp;
  1743. ret += _utf8Text;
  1744. return ret;
  1745. }
  1746. const Size& Label::getContentSize() const
  1747. {
  1748. if (_systemFontDirty || _contentDirty)
  1749. {
  1750. const_cast<Label*>(this)->updateContent();
  1751. }
  1752. return _contentSize;
  1753. }
  1754. Rect Label::getBoundingBox() const
  1755. {
  1756. const_cast<Label*>(this)->getContentSize();
  1757. return Node::getBoundingBox();
  1758. }
  1759. void Label::setBlendFunc(const BlendFunc &blendFunc)
  1760. {
  1761. _blendFunc = blendFunc;
  1762. _blendFuncDirty = true;
  1763. if (_textSprite)
  1764. {
  1765. _textSprite->setBlendFunc(blendFunc);
  1766. if (_shadowNode)
  1767. {
  1768. _shadowNode->setBlendFunc(blendFunc);
  1769. }
  1770. }
  1771. }
  1772. void Label::removeAllChildrenWithCleanup(bool cleanup)
  1773. {
  1774. Node::removeAllChildrenWithCleanup(cleanup);
  1775. _letters.clear();
  1776. }
  1777. void Label::removeChild(Node* child, bool cleanup /* = true */)
  1778. {
  1779. Node::removeChild(child, cleanup);
  1780. for (auto&& it : _letters)
  1781. {
  1782. if (it.second == child)
  1783. {
  1784. _letters.erase(it.first);
  1785. break;
  1786. }
  1787. }
  1788. }
  1789. FontDefinition Label::_getFontDefinition() const
  1790. {
  1791. FontDefinition systemFontDef;
  1792. systemFontDef._fontName = _systemFont;
  1793. systemFontDef._fontSize = _systemFontSize;
  1794. systemFontDef._alignment = _hAlignment;
  1795. systemFontDef._vertAlignment = _vAlignment;
  1796. systemFontDef._dimensions.width = _labelWidth;
  1797. systemFontDef._dimensions.height = _labelHeight;
  1798. systemFontDef._fontFillColor.r = _textColor.r;
  1799. systemFontDef._fontFillColor.g = _textColor.g;
  1800. systemFontDef._fontFillColor.b = _textColor.b;
  1801. systemFontDef._fontAlpha = _textColor.a;
  1802. systemFontDef._shadow._shadowEnabled = false;
  1803. systemFontDef._enableWrap = _enableWrap;
  1804. systemFontDef._overflow = (int)_overflow;
  1805. if (_currLabelEffect == LabelEffect::OUTLINE && _outlineSize > 0.f)
  1806. {
  1807. systemFontDef._stroke._strokeEnabled = true;
  1808. systemFontDef._stroke._strokeSize = _outlineSize;
  1809. systemFontDef._stroke._strokeColor.r = _effectColorF.r * 255;
  1810. systemFontDef._stroke._strokeColor.g = _effectColorF.g * 255;
  1811. systemFontDef._stroke._strokeColor.b = _effectColorF.b * 255;
  1812. systemFontDef._stroke._strokeAlpha = _effectColorF.a * 255;
  1813. }
  1814. else
  1815. {
  1816. systemFontDef._stroke._strokeEnabled = false;
  1817. }
  1818. #if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID) && (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
  1819. if (systemFontDef._stroke._strokeEnabled)
  1820. {
  1821. CCLOGERROR("Stroke Currently only supported on iOS and Android!");
  1822. }
  1823. systemFontDef._stroke._strokeEnabled = false;
  1824. #endif
  1825. return systemFontDef;
  1826. }
  1827. void Label::setGlobalZOrder(float globalZOrder)
  1828. {
  1829. Node::setGlobalZOrder(globalZOrder);
  1830. if (_textSprite)
  1831. {
  1832. _textSprite->setGlobalZOrder(globalZOrder);
  1833. if (_shadowNode)
  1834. {
  1835. _shadowNode->setGlobalZOrder(globalZOrder);
  1836. }
  1837. }
  1838. }
  1839. float Label::getRenderingFontSize()const
  1840. {
  1841. float fontSize;
  1842. if (_currentLabelType == LabelType::BMFONT) {
  1843. fontSize = _bmFontSize;
  1844. }else if(_currentLabelType == LabelType::TTF){
  1845. fontSize = this->getTTFConfig().fontSize;
  1846. }else if(_currentLabelType == LabelType::STRING_TEXTURE){
  1847. fontSize = _systemFontSize;
  1848. }else{ //FIXME: find a way to calculate char map font size
  1849. fontSize = this->getLineHeight();
  1850. }
  1851. return fontSize;
  1852. }
  1853. void Label::enableWrap(bool enable)
  1854. {
  1855. if(enable == _enableWrap || _overflow == Overflow::RESIZE_HEIGHT){
  1856. return;
  1857. }
  1858. this->_enableWrap = enable;
  1859. this->rescaleWithOriginalFontSize();
  1860. _contentDirty = true;
  1861. }
  1862. bool Label::isWrapEnabled()const
  1863. {
  1864. return this->_enableWrap;
  1865. }
  1866. void Label::setOverflow(Overflow overflow)
  1867. {
  1868. if(_overflow == overflow){
  1869. return;
  1870. }
  1871. if (_currentLabelType == LabelType::CHARMAP) {
  1872. if (overflow == Overflow::SHRINK) {
  1873. return;
  1874. }
  1875. }
  1876. if(overflow == Overflow::RESIZE_HEIGHT){
  1877. this->setDimensions(_labelDimensions.width,0);
  1878. this->enableWrap(true);
  1879. }
  1880. _overflow = overflow;
  1881. this->rescaleWithOriginalFontSize();
  1882. _contentDirty = true;
  1883. }
  1884. void Label::rescaleWithOriginalFontSize()
  1885. {
  1886. auto renderingFontSize = this->getRenderingFontSize();
  1887. if (_originalFontSize - renderingFontSize >= 1) {
  1888. this->scaleFontSizeDown(_originalFontSize);
  1889. }
  1890. }
  1891. Label::Overflow Label::getOverflow()const
  1892. {
  1893. return _overflow;
  1894. }
  1895. void Label::updateLetterSpriteScale(Sprite* sprite)
  1896. {
  1897. if (_currentLabelType == LabelType::BMFONT && _bmFontSize > 0)
  1898. {
  1899. sprite->setScale(_bmfontScale);
  1900. }
  1901. else
  1902. {
  1903. if (std::abs(_bmFontSize) < FLT_EPSILON)
  1904. {
  1905. sprite->setScale(0);
  1906. }
  1907. else
  1908. {
  1909. sprite->setScale(1.0);
  1910. }
  1911. }
  1912. }
  1913. NS_CC_END