CCLabel.cpp 64 KB

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