Font.cpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. #include "Base.h"
  2. #include "Font.h"
  3. #include "Game.h"
  4. #include "FileSystem.h"
  5. #include "Package.h"
  6. // Default font vertex shader
  7. #define FONT_VSH \
  8. "uniform mat4 u_projectionMatrix;\n" \
  9. "attribute vec3 a_position;\n" \
  10. "attribute vec2 a_texCoord;\n" \
  11. "attribute vec4 a_color;\n" \
  12. "varying vec2 v_texCoord;\n" \
  13. "varying vec4 v_color;\n" \
  14. "void main()\n" \
  15. "{\n" \
  16. "gl_Position = u_projectionMatrix * vec4(a_position, 1);\n" \
  17. "v_texCoord = a_texCoord;\n" \
  18. "v_color = a_color;\n" \
  19. "}\n"
  20. // Default font fragment shader
  21. #define FONT_FSH \
  22. "#ifdef OPENGL_ES\n" \
  23. "precision highp float;\n" \
  24. "#endif\n" \
  25. "varying vec2 v_texCoord;\n" \
  26. "varying vec4 v_color;\n" \
  27. "uniform sampler2D u_texture;\n" \
  28. "void main()\n" \
  29. "{\n" \
  30. "gl_FragColor = v_color;\n" \
  31. "gl_FragColor.a = texture2D(u_texture, v_texCoord).a;\n" \
  32. "}"
  33. namespace gameplay
  34. {
  35. static std::vector<Font*> __fontCache;
  36. static Effect* __fontEffect = NULL;
  37. Font::Font() :
  38. _style(PLAIN), _size(0), _glyphs(NULL), _glyphCount(0), _texture(NULL), _batch(NULL)
  39. {
  40. }
  41. Font::Font(const Font& copy)
  42. {
  43. // hidden
  44. }
  45. Font::~Font()
  46. {
  47. // Remove this Font from the font cache.
  48. std::vector<Font*>::iterator itr = std::find(__fontCache.begin(), __fontCache.end(), this);
  49. if (itr != __fontCache.end())
  50. {
  51. __fontCache.erase(itr);
  52. }
  53. SAFE_DELETE(_batch);
  54. SAFE_DELETE_ARRAY(_glyphs);
  55. SAFE_RELEASE(_texture);
  56. }
  57. Font* Font::create(const char* path, const char* id)
  58. {
  59. // Search the font cache for a font with the given path and ID.
  60. for (unsigned int i = 0, count = __fontCache.size(); i < count; ++i)
  61. {
  62. Font* f = __fontCache[i];
  63. if (f->_path == path && (id == NULL || f->_id == id))
  64. {
  65. // Found a match.
  66. f->addRef();
  67. return f;
  68. }
  69. }
  70. // Load the package.
  71. Package* pkg = Package::create(path);
  72. if (pkg == NULL)
  73. {
  74. return NULL;
  75. }
  76. Font* font = NULL;
  77. if (id == NULL)
  78. {
  79. // Get the ID of the first/only object in the package (assume it's a Font).
  80. const char* id;
  81. if (pkg->getObjectCount() != 1 || (id = pkg->getObjectID(0)) == NULL)
  82. {
  83. return NULL;
  84. }
  85. // Load the font using the ID of the first object in the package.
  86. font = pkg->loadFont(pkg->getObjectID(0));
  87. }
  88. else
  89. {
  90. // Load the font with the given ID.
  91. font = pkg->loadFont(id);
  92. }
  93. if (font)
  94. {
  95. // Add this font to the cache.
  96. __fontCache.push_back(font);
  97. }
  98. SAFE_RELEASE(pkg);
  99. return font;
  100. }
  101. Font* Font::create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture)
  102. {
  103. // Create the effect for the font's sprite batch.
  104. if (__fontEffect == NULL)
  105. {
  106. __fontEffect = Effect::createFromSource(FONT_VSH, FONT_FSH);
  107. if (__fontEffect == NULL)
  108. {
  109. LOG_ERROR("Failed to create effect for font.");
  110. SAFE_RELEASE(texture);
  111. return NULL;
  112. }
  113. }
  114. else
  115. {
  116. __fontEffect->addRef();
  117. }
  118. // Create batch for the font.
  119. SpriteBatch* batch = SpriteBatch::create(texture, __fontEffect, 128);
  120. // Release __fontEffect since the SpriteBatch keeps a reference to it
  121. SAFE_RELEASE(__fontEffect);
  122. if (batch == NULL)
  123. {
  124. LOG_ERROR("Failed to create batch for font.");
  125. return NULL;
  126. }
  127. // Increase the ref count of the texture to retain it.
  128. texture->addRef();
  129. Font* font = new Font();
  130. font->_family = family;
  131. font->_style = style;
  132. font->_size = size;
  133. font->_texture = texture;
  134. font->_batch = batch;
  135. // Copy the glyphs array.
  136. font->_glyphs = new Glyph[glyphCount];
  137. memcpy(font->_glyphs, glyphs, sizeof(Glyph) * glyphCount);
  138. font->_glyphCount = glyphCount;
  139. return font;
  140. }
  141. unsigned int Font::getSize()
  142. {
  143. return _size;
  144. }
  145. void Font::begin()
  146. {
  147. _batch->begin();
  148. }
  149. void Font::drawText(const char* text, int x, int y, const Vector4& color, unsigned int size, bool rightToLeft)
  150. {
  151. float scale = (float)size / _size;
  152. const char* cursor = NULL;
  153. if (rightToLeft)
  154. {
  155. cursor = text;
  156. }
  157. int xPos = x, yPos = y;
  158. bool done = false;
  159. while (!done)
  160. {
  161. int length;
  162. int startIndex;
  163. int iteration;
  164. if (rightToLeft)
  165. {
  166. char delimiter = cursor[0];
  167. while (!done &&
  168. (delimiter == ' ' ||
  169. delimiter == '\t' ||
  170. delimiter == '\r' ||
  171. delimiter == '\n' ||
  172. delimiter == 0))
  173. {
  174. switch (delimiter)
  175. {
  176. case ' ':
  177. xPos += (float)size*0.5f;
  178. break;
  179. case '\r':
  180. case '\n':
  181. yPos += size;
  182. xPos = x;
  183. break;
  184. case '\t':
  185. xPos += ((float)size*0.5f)*4;
  186. break;
  187. case 0:
  188. done = true;
  189. break;
  190. }
  191. if (!done)
  192. {
  193. ++cursor;
  194. delimiter = cursor[0];
  195. }
  196. }
  197. length = strcspn(cursor, "\r\n");
  198. startIndex = length - 1;
  199. iteration = -1;
  200. }
  201. else
  202. {
  203. length = strlen(text);
  204. startIndex = 0;
  205. iteration = 1;
  206. }
  207. for (int i = startIndex; i < length && i >= 0; i += iteration)
  208. {
  209. char c = 0;
  210. if (rightToLeft)
  211. {
  212. c = cursor[i];
  213. }
  214. else
  215. {
  216. c = text[i];
  217. }
  218. // Draw this character.
  219. switch (c)
  220. {
  221. case ' ':
  222. xPos += (float)size*0.5f;
  223. break;
  224. case '\r':
  225. case '\n':
  226. yPos += size;
  227. xPos = x;
  228. break;
  229. case '\t':
  230. xPos += ((float)size*0.5f)*4;
  231. break;
  232. default:
  233. int index = c - 32; // HACK for ASCII
  234. if (index >= 0 && index < (int)_glyphCount)
  235. {
  236. Glyph& g = _glyphs[index];
  237. _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
  238. xPos += g.width * scale + ((float)size*0.125f);
  239. break;
  240. }
  241. }
  242. }
  243. if (rightToLeft)
  244. {
  245. cursor += length;
  246. }
  247. else
  248. {
  249. done = true;
  250. }
  251. }
  252. }
  253. void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size, Justify justify, bool wrap, bool rightToLeft)
  254. {
  255. float scale = (float)size / _size;
  256. const char* token = text;
  257. const int length = strlen(text);
  258. int yPos = area.y;
  259. Justify vAlign = static_cast<Justify>(justify & 0xF0);
  260. if (vAlign == 0)
  261. {
  262. vAlign = ALIGN_TOP;
  263. }
  264. Justify hAlign = static_cast<Justify>(justify & 0x0F);
  265. if (hAlign == 0)
  266. {
  267. hAlign = ALIGN_LEFT;
  268. }
  269. token = text;
  270. // For alignments other than top-left, need to calculate the y position to begin drawing from
  271. // and the starting x position of each line. For right-to-left text, need to determine
  272. // the number of characters on each line.
  273. std::vector<int> xPositions;
  274. std::vector<unsigned int> lineLengths;
  275. if (vAlign != ALIGN_TOP || hAlign != ALIGN_LEFT || rightToLeft)
  276. {
  277. int lineWidth = 0;
  278. int delimWidth = 0;
  279. if (wrap)
  280. {
  281. // Go a word at a time.
  282. bool reachedEOF = false;
  283. unsigned int lineLength = 0;
  284. while (token[0] != 0)
  285. {
  286. unsigned int tokenWidth = 0;
  287. // Handle delimiters until next token.
  288. char delimiter = token[0];
  289. while (delimiter == ' ' ||
  290. delimiter == '\t' ||
  291. delimiter == '\r' ||
  292. delimiter == '\n' ||
  293. delimiter == 0)
  294. {
  295. switch (delimiter)
  296. {
  297. case ' ':
  298. delimWidth += (float)size*0.5f;
  299. lineLength++;
  300. break;
  301. case '\r':
  302. case '\n':
  303. yPos += size;
  304. if (lineWidth > 0)
  305. {
  306. addLineInfo(area, lineWidth, lineLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  307. }
  308. lineWidth = 0;
  309. lineLength = 0;
  310. delimWidth = 0;
  311. break;
  312. case '\t':
  313. delimWidth += ((float)size*0.5f)*4;
  314. lineLength++;
  315. break;
  316. case 0:
  317. reachedEOF = true;
  318. break;
  319. }
  320. if (reachedEOF)
  321. {
  322. break;
  323. }
  324. token++;
  325. delimiter = token[0];
  326. }
  327. if (reachedEOF || token == NULL)
  328. {
  329. break;
  330. }
  331. unsigned int tokenLength = strcspn(token, " \r\n\t");
  332. tokenWidth += getTokenWidth(token, tokenLength, size, scale);
  333. // Wrap if necessary.
  334. if (lineWidth + tokenWidth + delimWidth > area.width)
  335. {
  336. yPos += size;
  337. // Push position of current line.
  338. if (lineLength)
  339. {
  340. addLineInfo(area, lineWidth, lineLength-1, hAlign, &xPositions, &lineLengths, rightToLeft);
  341. }
  342. else
  343. {
  344. addLineInfo(area, lineWidth, tokenLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  345. }
  346. // Move token to the next line.
  347. lineWidth = 0;
  348. lineLength = 0;
  349. delimWidth = 0;
  350. }
  351. else
  352. {
  353. lineWidth += delimWidth;
  354. delimWidth = 0;
  355. }
  356. lineWidth += tokenWidth;
  357. lineLength += tokenLength;
  358. token += tokenLength;
  359. }
  360. // Final calculation of vertical position.
  361. int textHeight = yPos - area.y;
  362. int vWhiteSpace = area.height - textHeight;
  363. if (vAlign == ALIGN_VCENTER)
  364. {
  365. yPos = area.y + vWhiteSpace / 2;
  366. }
  367. else if (vAlign == ALIGN_BOTTOM)
  368. {
  369. yPos = area.y + vWhiteSpace;
  370. }
  371. // Calculation of final horizontal position.
  372. addLineInfo(area, lineWidth, lineLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  373. }
  374. else
  375. {
  376. // Go a line at a time.
  377. while (token[0] != 0)
  378. {
  379. char delimiter = token[0];
  380. while (delimiter == '\n')
  381. {
  382. yPos += size;
  383. ++token;
  384. delimiter = token[0];
  385. }
  386. unsigned int tokenLength = strcspn(token, "\n");
  387. if (tokenLength == 0)
  388. {
  389. tokenLength = strlen(token);
  390. }
  391. int lineWidth = getTokenWidth(token, tokenLength, size, scale);
  392. addLineInfo(area, lineWidth, tokenLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  393. token += tokenLength;
  394. }
  395. int textHeight = yPos - area.y;
  396. int vWhiteSpace = area.height - textHeight;
  397. if (vAlign == ALIGN_VCENTER)
  398. {
  399. yPos = area.y + vWhiteSpace / 2;
  400. }
  401. else if (vAlign == ALIGN_BOTTOM)
  402. {
  403. yPos = area.y + vWhiteSpace;
  404. }
  405. }
  406. if (vAlign == ALIGN_TOP)
  407. {
  408. yPos = area.y;
  409. }
  410. }
  411. // Now we have the info we need in order to render.
  412. int xPos = area.x;
  413. std::vector<int>::const_iterator xPositionsIt = xPositions.begin();
  414. if (xPositionsIt != xPositions.end())
  415. {
  416. xPos = *xPositionsIt++;
  417. }
  418. token = text;
  419. int iteration = 1;
  420. unsigned int lineLength;
  421. unsigned int currentLineLength = 0;
  422. const char* lineStart;
  423. std::vector<unsigned int>::const_iterator lineLengthsIt;
  424. if (rightToLeft)
  425. {
  426. lineStart = token;
  427. lineLengthsIt = lineLengths.begin();
  428. lineLength = *lineLengthsIt++;
  429. token += lineLength - 1;
  430. iteration = -1;
  431. }
  432. while (token[0] != 0)
  433. {
  434. // Handle delimiters until next token.
  435. if (!handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &currentLineLength, &xPositionsIt, xPositions.end()))
  436. {
  437. break;
  438. }
  439. bool truncated = false;
  440. unsigned int tokenLength;
  441. unsigned int tokenWidth;
  442. unsigned int startIndex;
  443. if (rightToLeft)
  444. {
  445. tokenLength = getReversedTokenLength(token, text);
  446. currentLineLength += tokenLength;
  447. token -= (tokenLength - 1);
  448. tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  449. iteration = -1;
  450. startIndex = tokenLength - 1;
  451. }
  452. else
  453. {
  454. tokenLength = strcspn(token, " \r\n\t");
  455. tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  456. iteration = 1;
  457. startIndex = 0;
  458. }
  459. // Wrap if necessary.
  460. if (wrap &&
  461. xPos + tokenWidth > area.x + area.width ||
  462. (rightToLeft && currentLineLength > lineLength))
  463. {
  464. yPos += size;
  465. currentLineLength = tokenLength;
  466. if (xPositionsIt != xPositions.end())
  467. {
  468. xPos = *xPositionsIt++;
  469. }
  470. else
  471. {
  472. xPos = area.x;
  473. }
  474. }
  475. bool draw = true;
  476. if (yPos < area.y)
  477. {
  478. // Skip drawing until line break or wrap.
  479. draw = false;
  480. }
  481. else if (yPos > area.y + area.height)
  482. {
  483. // Truncate below area's vertical limit.
  484. break;
  485. }
  486. for (int i = startIndex; i < (int)tokenLength && i >= 0; i += iteration)
  487. {
  488. char c = token[i];
  489. int glyphIndex = c - 32; // HACK for ASCII
  490. if (glyphIndex >= 0 && glyphIndex < (int)_glyphCount)
  491. {
  492. Glyph& g = _glyphs[glyphIndex];
  493. if (xPos + (int)(g.width*scale) > area.x + area.width)
  494. {
  495. // Truncate this line and go on to the next one.
  496. truncated = true;
  497. break;
  498. }
  499. else if (xPos >= area.x)
  500. {
  501. // Draw this character.
  502. if (draw)
  503. {
  504. _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
  505. }
  506. }
  507. xPos += g.width*scale + ((float)size*0.125f);
  508. }
  509. }
  510. if (!truncated)
  511. {
  512. if (rightToLeft)
  513. {
  514. if (token == lineStart)
  515. {
  516. token += lineLength;
  517. // Now handle delimiters going forwards.
  518. if (!handleDelimiters(&token, size, 1, area.x, &xPos, &yPos, &currentLineLength, &xPositionsIt, xPositions.end()))
  519. {
  520. break;
  521. }
  522. if (lineLengthsIt != lineLengths.end())
  523. {
  524. lineLength = *lineLengthsIt++;
  525. }
  526. lineStart = token;
  527. token += lineLength-1;
  528. }
  529. else
  530. {
  531. token--;
  532. }
  533. }
  534. else
  535. {
  536. token += tokenLength;
  537. }
  538. }
  539. else
  540. {
  541. if (rightToLeft)
  542. {
  543. token = lineStart + lineLength;
  544. if (!handleDelimiters(&token, size, 1, area.x, &xPos, &yPos, &currentLineLength, &xPositionsIt, xPositions.end()))
  545. {
  546. break;
  547. }
  548. if (lineLengthsIt != lineLengths.end())
  549. {
  550. lineLength = *lineLengthsIt++;
  551. }
  552. lineStart = token;
  553. token += lineLength-1;
  554. }
  555. else
  556. {
  557. // Skip the rest of this line.
  558. unsigned int tokenLength = strcspn(token, "\n");
  559. if (tokenLength > 0)
  560. {
  561. // Get first token of next line.
  562. token += tokenLength;
  563. }
  564. }
  565. }
  566. }
  567. }
  568. void Font::end()
  569. {
  570. _batch->end();
  571. }
  572. void Font::measureText(const char* text, unsigned int size, unsigned int* width, unsigned int* height)
  573. {
  574. float scale = (float)size / _size;
  575. const int length = strlen(text);
  576. const char* token = text;
  577. *width = 0;
  578. *height = 0;
  579. // Measure a line at a time.
  580. while (token[0] != 0)
  581. {
  582. while (token[0] == '\n')
  583. {
  584. *height += size;
  585. ++token;
  586. }
  587. unsigned int tokenLength = strcspn(token, "\n");
  588. unsigned int tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  589. if (tokenWidth > *width)
  590. {
  591. *width = tokenWidth;
  592. }
  593. token += tokenLength;
  594. }
  595. }
  596. void Font::measureText(const char* text, const Rectangle& viewport, unsigned int size, Rectangle* out, Justify justify, bool wrap, bool ignoreClip)
  597. {
  598. float scale = (float)size / _size;
  599. Justify vAlign = static_cast<Justify>(justify & 0xF0);
  600. if (vAlign == 0)
  601. {
  602. vAlign = ALIGN_TOP;
  603. }
  604. Justify hAlign = static_cast<Justify>(justify & 0x0F);
  605. if (hAlign == 0)
  606. {
  607. hAlign = ALIGN_LEFT;
  608. }
  609. const char* token = text;
  610. std::vector<bool> emptyLines;
  611. std::vector<Vector2> lines;
  612. unsigned int lineWidth = 0;
  613. int yPos = viewport.y;
  614. if (wrap)
  615. {
  616. unsigned int delimWidth = 0;
  617. bool reachedEOF = false;
  618. while (token[0] != 0)
  619. {
  620. // Handle delimiters until next token.
  621. char delimiter = token[0];
  622. while (delimiter == ' ' ||
  623. delimiter == '\t' ||
  624. delimiter == '\r' ||
  625. delimiter == '\n' ||
  626. delimiter == 0)
  627. {
  628. switch (delimiter)
  629. {
  630. case ' ':
  631. delimWidth += (float)size*0.5f;
  632. break;
  633. case '\r':
  634. case '\n':
  635. // Add line-height to vertical cursor.
  636. yPos += size;
  637. if (lineWidth > 0)
  638. {
  639. // Determine horizontal position and width.
  640. int hWhitespace = viewport.width - lineWidth;
  641. int xPos = viewport.x;
  642. if (hAlign == ALIGN_HCENTER)
  643. {
  644. xPos += hWhitespace / 2;
  645. }
  646. else if (hAlign == ALIGN_RIGHT)
  647. {
  648. xPos += hWhitespace;
  649. }
  650. // Record this line's size.
  651. emptyLines.push_back(false);
  652. lines.push_back(Vector2(xPos, lineWidth));
  653. }
  654. else
  655. {
  656. // Record the existence of an empty line.
  657. emptyLines.push_back(true);
  658. lines.push_back(Vector2(FLT_MAX, 0));
  659. }
  660. lineWidth = 0;
  661. delimWidth = 0;
  662. break;
  663. case '\t':
  664. delimWidth += ((float)size*0.5f)*4;
  665. break;
  666. case 0:
  667. reachedEOF = true;
  668. break;
  669. }
  670. if (reachedEOF)
  671. {
  672. break;
  673. }
  674. token++;
  675. delimiter = token[0];
  676. }
  677. if (reachedEOF)
  678. {
  679. break;
  680. }
  681. // Measure the next token.
  682. unsigned int tokenLength = strcspn(token, " \r\n\t");
  683. unsigned int tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  684. // Wrap if necessary.
  685. if (lineWidth + tokenWidth + delimWidth > viewport.width)
  686. {
  687. // Add line-height to vertical cursor.
  688. yPos += size;
  689. // Determine horizontal position and width.
  690. int hWhitespace = viewport.width - lineWidth;
  691. int xPos = viewport.x;
  692. if (hAlign == ALIGN_HCENTER)
  693. {
  694. xPos += hWhitespace / 2;
  695. }
  696. else if (hAlign == ALIGN_RIGHT)
  697. {
  698. xPos += hWhitespace;
  699. }
  700. // Record this line's size.
  701. emptyLines.push_back(false);
  702. lines.push_back(Vector2(xPos, lineWidth));
  703. lineWidth = 0;
  704. }
  705. else
  706. {
  707. lineWidth += delimWidth;
  708. }
  709. delimWidth = 0;
  710. lineWidth += tokenWidth;
  711. token += tokenLength;
  712. }
  713. }
  714. else
  715. {
  716. // Measure a whole line at a time.
  717. int emptyLinesCount = 0;
  718. while (token[0] != 0)
  719. {
  720. // Handle any number of consecutive newlines.
  721. bool nextLine = true;
  722. while (token[0] == '\n')
  723. {
  724. if (nextLine)
  725. {
  726. // Add line-height to vertical cursor.
  727. yPos += size * (emptyLinesCount+1);
  728. nextLine = false;
  729. emptyLinesCount = 0;
  730. emptyLines.push_back(false);
  731. }
  732. else
  733. {
  734. // Record the existence of an empty line.
  735. ++emptyLinesCount;
  736. emptyLines.push_back(true);
  737. lines.push_back(Vector2(FLT_MAX, 0));
  738. }
  739. token++;
  740. }
  741. // Measure the next line.
  742. unsigned int tokenLength = strcspn(token, "\n");
  743. lineWidth = getTokenWidth(token, tokenLength, size, scale);
  744. // Determine horizontal position and width.
  745. int xPos = viewport.x;
  746. int hWhitespace = viewport.width - lineWidth;
  747. if (hAlign == ALIGN_HCENTER)
  748. {
  749. xPos += hWhitespace / 2;
  750. }
  751. else if (hAlign == ALIGN_RIGHT)
  752. {
  753. xPos += hWhitespace;
  754. }
  755. // Record this line's size.
  756. lines.push_back(Vector2(xPos, lineWidth));
  757. token += tokenLength;
  758. }
  759. yPos += size;
  760. }
  761. if (wrap)
  762. {
  763. // Record the size of the last line.
  764. int hWhitespace = viewport.width - lineWidth;
  765. int xPos = viewport.x;
  766. if (hAlign == ALIGN_HCENTER)
  767. {
  768. xPos += hWhitespace / 2;
  769. }
  770. else if (hAlign == ALIGN_RIGHT)
  771. {
  772. xPos += hWhitespace;
  773. }
  774. lines.push_back(Vector2(xPos, lineWidth));
  775. }
  776. int x = INT_MAX;
  777. int y = viewport.y;
  778. unsigned int width = 0;
  779. int height = yPos - viewport.y;
  780. // Calculate top of text without clipping.
  781. int vWhitespace = viewport.height - height;
  782. if (vAlign == ALIGN_VCENTER)
  783. {
  784. y += vWhitespace / 2;
  785. }
  786. else if (vAlign == ALIGN_BOTTOM)
  787. {
  788. y += vWhitespace;
  789. }
  790. int clippedTop = 0;
  791. int clippedBottom = 0;
  792. if (!ignoreClip)
  793. {
  794. // Trim rect to fit text that would actually be drawn within the given viewport.
  795. if (y >= viewport.y)
  796. {
  797. // Text goes off the bottom of the viewport.
  798. clippedBottom = (height - viewport.height) / size + 1;
  799. if (clippedBottom > 0)
  800. {
  801. // Also need to crop empty lines above non-empty lines that have been clipped.
  802. unsigned int emptyIndex = emptyLines.size() - clippedBottom;
  803. while (emptyIndex < emptyLines.size() && emptyLines[emptyIndex] == true)
  804. {
  805. height -= size;
  806. emptyIndex++;
  807. }
  808. height -= size * clippedBottom;
  809. }
  810. else
  811. {
  812. clippedBottom = 0;
  813. }
  814. }
  815. else
  816. {
  817. // Text goes above the top of the viewport.
  818. clippedTop = (viewport.y - y) / size + 1;
  819. if (clippedTop < 0)
  820. {
  821. clippedTop = 0;
  822. }
  823. // Also need to crop empty lines below non-empty lines that have been clipped.
  824. unsigned int emptyIndex = clippedTop;
  825. while (emptyIndex < emptyLines.size() && emptyLines[emptyIndex] == true)
  826. {
  827. y += size;
  828. height -= size;
  829. emptyIndex++;
  830. }
  831. if (vAlign == ALIGN_VCENTER)
  832. {
  833. // In this case lines may be clipped off the bottom as well.
  834. clippedBottom = (height - viewport.height + vWhitespace/2 + 0.01) / size + 1;
  835. if (clippedBottom > 0)
  836. {
  837. emptyIndex = emptyLines.size() - clippedBottom;
  838. while (emptyIndex < emptyLines.size() && emptyLines[emptyIndex] == true)
  839. {
  840. height -= size;
  841. emptyIndex++;
  842. }
  843. height -= size * clippedBottom;
  844. }
  845. else
  846. {
  847. clippedBottom = 0;
  848. }
  849. }
  850. y = y + size * clippedTop;
  851. height = height - size * clippedTop;
  852. }
  853. }
  854. // Determine left-most x coordinate and largest width out of lines that have not been clipped.
  855. for (int i = clippedTop; i < (int)lines.size() - clippedBottom; ++i)
  856. {
  857. if (lines[i].x < x)
  858. {
  859. x = lines[i].x;
  860. }
  861. if (lines[i].y > width)
  862. {
  863. width = lines[i].y;
  864. }
  865. }
  866. if (!ignoreClip)
  867. {
  868. // Guarantee that the output rect will fit within the viewport.
  869. out->x = (x >= viewport.x)? x : viewport.x;
  870. out->y = (y >= viewport.y)? y : viewport.y;
  871. out->width = (width <= viewport.width)? width : viewport.width;
  872. out->height = (height <= viewport.height)? height : viewport.height;
  873. }
  874. else
  875. {
  876. out->x = x;
  877. out->y = y;
  878. out->width = width;
  879. out->height = height;
  880. }
  881. }
  882. unsigned int Font::getIndexAtLocation(const char* text, const Rectangle& area, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
  883. Justify justify, bool wrap, bool rightToLeft)
  884. {
  885. return getIndexOrLocation(text, area, size, inLocation, outLocation, -1, justify, wrap, rightToLeft);
  886. }
  887. void Font::getLocationAtIndex(const char* text, const Rectangle& clip, unsigned int size, Vector2* outLocation, const unsigned int destIndex,
  888. Justify justify, bool wrap, bool rightToLeft)
  889. {
  890. getIndexOrLocation(text, clip, size, *outLocation, outLocation, (const int)destIndex, justify, wrap, rightToLeft);
  891. }
  892. unsigned int Font::getIndexOrLocation(const char* text, const Rectangle& area, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
  893. const int destIndex, Justify justify, bool wrap, bool rightToLeft)
  894. {
  895. unsigned int charIndex = 0;
  896. // Essentially need to measure text until we reach inLocation.
  897. float scale = (float)size / _size;
  898. const char* token = text;
  899. const int length = strlen(text);
  900. int yPos = area.y;
  901. Justify vAlign = static_cast<Justify>(justify & 0xF0);
  902. if (vAlign == 0)
  903. {
  904. vAlign = ALIGN_TOP;
  905. }
  906. Justify hAlign = static_cast<Justify>(justify & 0x0F);
  907. if (hAlign == 0)
  908. {
  909. hAlign = ALIGN_LEFT;
  910. }
  911. token = text;
  912. // For alignments other than top-left, need to calculate the y position to begin drawing from
  913. // and the starting x position of each line. For right-to-left text, need to determine
  914. // the number of characters on each line.
  915. std::vector<int> xPositions;
  916. std::vector<unsigned int> lineLengths;
  917. if (vAlign != ALIGN_TOP || hAlign != ALIGN_LEFT || rightToLeft)
  918. {
  919. int lineWidth = 0;
  920. int delimWidth = 0;
  921. if (wrap)
  922. {
  923. // Go a word at a time.
  924. bool reachedEOF = false;
  925. unsigned int lineLength = 0;
  926. while (token[0] != 0)
  927. {
  928. unsigned int tokenWidth = 0;
  929. // Handle delimiters until next token.
  930. char delimiter = token[0];
  931. while (delimiter == ' ' ||
  932. delimiter == '\t' ||
  933. delimiter == '\r' ||
  934. delimiter == '\n' ||
  935. delimiter == 0)
  936. {
  937. switch (delimiter)
  938. {
  939. case ' ':
  940. delimWidth += (float)size*0.5f;
  941. lineLength++;
  942. break;
  943. case '\r':
  944. case '\n':
  945. yPos += size;
  946. if (lineWidth > 0)
  947. {
  948. addLineInfo(area, lineWidth, lineLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  949. }
  950. lineWidth = 0;
  951. lineLength = 0;
  952. delimWidth = 0;
  953. break;
  954. case '\t':
  955. delimWidth += ((float)size*0.5f)*4;
  956. lineLength++;
  957. break;
  958. case 0:
  959. reachedEOF = true;
  960. break;
  961. }
  962. if (reachedEOF)
  963. {
  964. break;
  965. }
  966. token++;
  967. delimiter = token[0];
  968. }
  969. if (reachedEOF || token == NULL)
  970. {
  971. break;
  972. }
  973. unsigned int tokenLength = strcspn(token, " \r\n\t");
  974. tokenWidth += getTokenWidth(token, tokenLength, size, scale);
  975. // Wrap if necessary.
  976. if (lineWidth + tokenWidth + delimWidth > area.width)
  977. {
  978. yPos += size;
  979. // Push position of current line.
  980. if (lineLength)
  981. {
  982. addLineInfo(area, lineWidth, lineLength-1, hAlign, &xPositions, &lineLengths, rightToLeft);
  983. }
  984. else
  985. {
  986. addLineInfo(area, lineWidth, tokenLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  987. }
  988. // Move token to the next line.
  989. lineWidth = 0;
  990. lineLength = 0;
  991. delimWidth = 0;
  992. }
  993. else
  994. {
  995. lineWidth += delimWidth;
  996. delimWidth = 0;
  997. }
  998. lineWidth += tokenWidth;
  999. lineLength += tokenLength;
  1000. token += tokenLength;
  1001. }
  1002. // Final calculation of vertical position.
  1003. int textHeight = yPos - area.y;
  1004. int vWhiteSpace = area.height - textHeight;
  1005. if (vAlign == ALIGN_VCENTER)
  1006. {
  1007. yPos = area.y + vWhiteSpace / 2;
  1008. }
  1009. else if (vAlign == ALIGN_BOTTOM)
  1010. {
  1011. yPos = area.y + vWhiteSpace;
  1012. }
  1013. // Calculation of final horizontal position.
  1014. addLineInfo(area, lineWidth, lineLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  1015. }
  1016. else
  1017. {
  1018. // Go a line at a time.
  1019. while (token[0] != 0)
  1020. {
  1021. char delimiter = token[0];
  1022. while (delimiter == '\n')
  1023. {
  1024. yPos += size;
  1025. ++token;
  1026. delimiter = token[0];
  1027. }
  1028. unsigned int tokenLength = strcspn(token, "\n");
  1029. if (tokenLength == 0)
  1030. {
  1031. tokenLength = strlen(token);
  1032. }
  1033. int lineWidth = getTokenWidth(token, tokenLength, size, scale);
  1034. addLineInfo(area, lineWidth, tokenLength, hAlign, &xPositions, &lineLengths, rightToLeft);
  1035. token += tokenLength;
  1036. }
  1037. int textHeight = yPos - area.y;
  1038. int vWhiteSpace = area.height - textHeight;
  1039. if (vAlign == ALIGN_VCENTER)
  1040. {
  1041. yPos = area.y + vWhiteSpace / 2;
  1042. }
  1043. else if (vAlign == ALIGN_BOTTOM)
  1044. {
  1045. yPos = area.y + vWhiteSpace;
  1046. }
  1047. }
  1048. if (vAlign == ALIGN_TOP)
  1049. {
  1050. yPos = area.y;
  1051. }
  1052. }
  1053. // Now we have the info we need in order to render.
  1054. int xPos = area.x;
  1055. std::vector<int>::const_iterator xPositionsIt = xPositions.begin();
  1056. if (xPositionsIt != xPositions.end())
  1057. {
  1058. xPos = *xPositionsIt++;
  1059. }
  1060. token = text;
  1061. int iteration = 1;
  1062. unsigned int lineLength;
  1063. unsigned int currentLineLength = 0;
  1064. const char* lineStart;
  1065. std::vector<unsigned int>::const_iterator lineLengthsIt;
  1066. if (rightToLeft)
  1067. {
  1068. lineStart = token;
  1069. lineLengthsIt = lineLengths.begin();
  1070. lineLength = *lineLengthsIt++;
  1071. token += lineLength - 1;
  1072. iteration = -1;
  1073. }
  1074. while (token[0] != 0)
  1075. {
  1076. // Handle delimiters until next token.
  1077. unsigned int delimLength = 0;
  1078. int result;
  1079. if (destIndex == -1)
  1080. {
  1081. result = handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &delimLength, &xPositionsIt, xPositions.end(), &charIndex, &inLocation);
  1082. }
  1083. else
  1084. {
  1085. result = handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &delimLength, &xPositionsIt, xPositions.end(), &charIndex, NULL, charIndex, destIndex);
  1086. }
  1087. currentLineLength += delimLength;
  1088. if (result == 0)
  1089. {
  1090. break;
  1091. }
  1092. else if (result == 2)
  1093. {
  1094. outLocation->x = xPos;
  1095. outLocation->y = yPos;
  1096. return charIndex;
  1097. }
  1098. if (destIndex == (int)charIndex ||
  1099. (destIndex == -1 &&
  1100. inLocation.x >= xPos && inLocation.x < floor(xPos + ((float)size*0.125f)) &&
  1101. inLocation.y >= yPos && inLocation.y < yPos + size))
  1102. {
  1103. outLocation->x = xPos;
  1104. outLocation->y = yPos;
  1105. return charIndex;
  1106. }
  1107. bool truncated = false;
  1108. unsigned int tokenLength;
  1109. unsigned int tokenWidth;
  1110. unsigned int startIndex;
  1111. if (rightToLeft)
  1112. {
  1113. tokenLength = getReversedTokenLength(token, text);
  1114. currentLineLength += tokenLength;
  1115. charIndex += tokenLength;
  1116. token -= (tokenLength - 1);
  1117. tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  1118. iteration = -1;
  1119. startIndex = tokenLength - 1;
  1120. }
  1121. else
  1122. {
  1123. tokenLength = strcspn(token, " \r\n\t");
  1124. tokenWidth = getTokenWidth(token, tokenLength, size, scale);
  1125. iteration = 1;
  1126. startIndex = 0;
  1127. }
  1128. // Wrap if necessary.
  1129. if (wrap &&
  1130. xPos + tokenWidth > area.x + area.width ||
  1131. (rightToLeft && currentLineLength > lineLength))
  1132. {
  1133. yPos += size;
  1134. currentLineLength = tokenLength;
  1135. if (xPositionsIt != xPositions.end())
  1136. {
  1137. xPos = *xPositionsIt++;
  1138. }
  1139. else
  1140. {
  1141. xPos = area.x;
  1142. }
  1143. }
  1144. if (yPos > area.y + area.height)
  1145. {
  1146. // Truncate below area's vertical limit.
  1147. break;
  1148. }
  1149. for (int i = startIndex; i < (int)tokenLength && i >= 0; i += iteration)
  1150. {
  1151. char c = token[i];
  1152. int glyphIndex = c - 32; // HACK for ASCII
  1153. if (glyphIndex >= 0 && glyphIndex < (int)_glyphCount)
  1154. {
  1155. Glyph& g = _glyphs[glyphIndex];
  1156. if (xPos + (int)(g.width*scale) > area.x + area.width)
  1157. {
  1158. // Truncate this line and go on to the next one.
  1159. truncated = true;
  1160. break;
  1161. }
  1162. // Check against inLocation.
  1163. if (destIndex == (int)charIndex ||
  1164. (destIndex == -1 &&
  1165. inLocation.x >= xPos && inLocation.x < floor(xPos + g.width*scale + ((float)size*0.125f)) &&
  1166. inLocation.y >= yPos && inLocation.y < yPos + size))
  1167. {
  1168. outLocation->x = xPos;
  1169. outLocation->y = yPos;
  1170. return charIndex;
  1171. }
  1172. xPos += g.width*scale + ((float)size*0.125f);
  1173. charIndex++;
  1174. }
  1175. }
  1176. if (!truncated)
  1177. {
  1178. if (rightToLeft)
  1179. {
  1180. if (token == lineStart)
  1181. {
  1182. token += lineLength;
  1183. // Now handle delimiters going forwards.
  1184. if (!handleDelimiters(&token, size, 1, area.x, &xPos, &yPos, &currentLineLength, &xPositionsIt, xPositions.end()))
  1185. {
  1186. break;
  1187. }
  1188. charIndex += currentLineLength;
  1189. if (lineLengthsIt != lineLengths.end())
  1190. {
  1191. lineLength = *lineLengthsIt++;
  1192. }
  1193. lineStart = token;
  1194. token += lineLength-1;
  1195. charIndex += tokenLength;
  1196. }
  1197. else
  1198. {
  1199. token--;
  1200. }
  1201. }
  1202. else
  1203. {
  1204. token += tokenLength;
  1205. }
  1206. }
  1207. else
  1208. {
  1209. if (rightToLeft)
  1210. {
  1211. token = lineStart + lineLength;
  1212. if (!handleDelimiters(&token, size, 1, area.x, &xPos, &yPos, &currentLineLength, &xPositionsIt, xPositions.end()))
  1213. {
  1214. break;
  1215. }
  1216. if (lineLengthsIt != lineLengths.end())
  1217. {
  1218. lineLength = *lineLengthsIt++;
  1219. }
  1220. lineStart = token;
  1221. token += lineLength-1;
  1222. }
  1223. else
  1224. {
  1225. // Skip the rest of this line.
  1226. unsigned int tokenLength = strcspn(token, "\n");
  1227. if (tokenLength > 0)
  1228. {
  1229. // Get first token of next line.
  1230. token += tokenLength;
  1231. charIndex += tokenLength;
  1232. }
  1233. }
  1234. }
  1235. }
  1236. outLocation->x = xPos;
  1237. outLocation->y = yPos;
  1238. return charIndex;
  1239. }
  1240. unsigned int Font::getTokenWidth(const char* token, unsigned int length, unsigned int size, float scale)
  1241. {
  1242. // Calculate width of word or line.
  1243. unsigned int tokenWidth = 0;
  1244. for (unsigned int i = 0; i < length; ++i)
  1245. {
  1246. char c = token[i];
  1247. switch (c)
  1248. {
  1249. case ' ':
  1250. tokenWidth += (float)size*0.5f;
  1251. break;
  1252. case '\t':
  1253. tokenWidth += ((float)size*0.5f)*4;
  1254. break;
  1255. default:
  1256. int glyphIndex = c - 32;
  1257. if (glyphIndex >= 0 && glyphIndex < (int)_glyphCount)
  1258. {
  1259. Glyph& g = _glyphs[glyphIndex];
  1260. tokenWidth += g.width * scale + ((float)size*0.125f);
  1261. }
  1262. break;
  1263. }
  1264. }
  1265. return tokenWidth;
  1266. }
  1267. unsigned int Font::getReversedTokenLength(const char* token, const char* bufStart)
  1268. {
  1269. const char* cursor = token;
  1270. char c = cursor[0];
  1271. unsigned int length = 0;
  1272. while (cursor != bufStart && c != ' ' && c != '\r' && c != '\n' && c != '\t')
  1273. {
  1274. length++;
  1275. cursor--;
  1276. c = cursor[0];
  1277. }
  1278. if (cursor == bufStart)
  1279. {
  1280. length++;
  1281. }
  1282. return length;
  1283. }
  1284. int Font::handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
  1285. std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, unsigned int* charIndex,
  1286. const Vector2* stopAtPosition, const int currentIndex, const int destIndex)
  1287. {
  1288. char delimiter = *token[0];
  1289. bool nextLine = true;
  1290. while (delimiter == ' ' ||
  1291. delimiter == '\t' ||
  1292. delimiter == '\r' ||
  1293. delimiter == '\n' ||
  1294. delimiter == 0)
  1295. {
  1296. if ((stopAtPosition &&
  1297. stopAtPosition->x >= *xPos && stopAtPosition->x < floor(*xPos + ((float)size*0.5f)) &&
  1298. stopAtPosition->y >= *yPos && stopAtPosition->y < *yPos + size) ||
  1299. (currentIndex >= 0 && destIndex >= 0 && currentIndex + (int)*lineLength == destIndex))
  1300. {
  1301. // Success + stopAtPosition was reached.
  1302. return 2;
  1303. }
  1304. switch (delimiter)
  1305. {
  1306. case ' ':
  1307. *xPos += (float)size*0.5f;
  1308. (*lineLength)++;
  1309. if (charIndex)
  1310. {
  1311. (*charIndex)++;
  1312. }
  1313. break;
  1314. case '\r':
  1315. case '\n':
  1316. *yPos += size;
  1317. // Only use next xPos for first newline character (in case of multiple consecutive newlines).
  1318. if (nextLine)
  1319. {
  1320. if (*xPositionsIt != xPositionsEnd)
  1321. {
  1322. *xPos = **xPositionsIt;
  1323. (*xPositionsIt)++;
  1324. }
  1325. else
  1326. {
  1327. *xPos = areaX;
  1328. }
  1329. nextLine = false;
  1330. *lineLength = 0;
  1331. if (charIndex)
  1332. {
  1333. (*charIndex)++;
  1334. }
  1335. }
  1336. break;
  1337. case '\t':
  1338. *xPos += ((float)size*0.5f)*4;
  1339. (*lineLength)++;
  1340. if (charIndex)
  1341. {
  1342. (*charIndex)++;
  1343. }
  1344. break;
  1345. case 0:
  1346. // EOF reached.
  1347. return 0;
  1348. }
  1349. *token += iteration;
  1350. delimiter = *token[0];
  1351. }
  1352. // Success.
  1353. return 1;
  1354. }
  1355. void Font::addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
  1356. std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft)
  1357. {
  1358. int hWhitespace = area.width - lineWidth;
  1359. if (hAlign == ALIGN_HCENTER)
  1360. {
  1361. (*xPositions).push_back(area.x + hWhitespace / 2);
  1362. }
  1363. else if (hAlign == ALIGN_RIGHT)
  1364. {
  1365. (*xPositions).push_back(area.x + hWhitespace);
  1366. }
  1367. if (rightToLeft)
  1368. {
  1369. (*lineLengths).push_back(lineLength);
  1370. }
  1371. }
  1372. SpriteBatch* Font::getSpriteBatch()
  1373. {
  1374. return _batch;
  1375. }
  1376. Font::Justify Font::getJustifyFromString(const char* justify)
  1377. {
  1378. if (strcmp(justify, "ALIGN_LEFT") == 0)
  1379. {
  1380. return Font::ALIGN_LEFT;
  1381. }
  1382. else if (strcmp(justify, "ALIGN_HCENTER") == 0)
  1383. {
  1384. return Font::ALIGN_HCENTER;
  1385. }
  1386. else if (strcmp(justify, "ALIGN_RIGHT") == 0)
  1387. {
  1388. return Font::ALIGN_RIGHT;
  1389. }
  1390. else if (strcmp(justify, "ALIGN_TOP") == 0)
  1391. {
  1392. return Font::ALIGN_TOP;
  1393. }
  1394. else if (strcmp(justify, "ALIGN_VCENTER") == 0)
  1395. {
  1396. return Font::ALIGN_VCENTER;
  1397. }
  1398. else if (strcmp(justify, "ALIGN_BOTTOM") == 0)
  1399. {
  1400. return Font::ALIGN_BOTTOM;
  1401. }
  1402. else if (strcmp(justify, "ALIGN_TOP_LEFT") == 0)
  1403. {
  1404. return Font::ALIGN_TOP_LEFT;
  1405. }
  1406. else if (strcmp(justify, "ALIGN_VCENTER_LEFT") == 0)
  1407. {
  1408. return Font::ALIGN_VCENTER_LEFT;
  1409. }
  1410. else if (strcmp(justify, "ALIGN_BOTTOM_LEFT") == 0)
  1411. {
  1412. return Font::ALIGN_BOTTOM_LEFT;
  1413. }
  1414. else if (strcmp(justify, "ALIGN_TOP_HCENTER") == 0)
  1415. {
  1416. return Font::ALIGN_TOP_HCENTER;
  1417. }
  1418. else if (strcmp(justify, "ALIGN_VCENTER_HCENTER") == 0)
  1419. {
  1420. return Font::ALIGN_VCENTER_HCENTER;
  1421. }
  1422. else if (strcmp(justify, "ALIGN_BOTTOM_HCENTER") == 0)
  1423. {
  1424. return Font::ALIGN_BOTTOM_HCENTER;
  1425. }
  1426. else if (strcmp(justify, "ALIGN_TOP_RIGHT") == 0)
  1427. {
  1428. return Font::ALIGN_TOP_RIGHT;
  1429. }
  1430. else if (strcmp(justify, "ALIGN_VCENTER_RIGHT") == 0)
  1431. {
  1432. return Font::ALIGN_VCENTER_RIGHT;
  1433. }
  1434. else if (strcmp(justify, "ALIGN_BOTTOM_RIGHT") == 0)
  1435. {
  1436. return Font::ALIGN_BOTTOM_RIGHT;
  1437. }
  1438. // Default.
  1439. return Font::ALIGN_TOP_LEFT;
  1440. }
  1441. }