CCLabel.cpp 73 KB

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