Font.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. #include "Font.h"
  2. #include "Globals.h"
  3. #include "Image.h"
  4. #include "Scroll.h"
  5. #include "Text.h"
  6. #ifdef WIN32
  7. # include <Windows.h>
  8. #endif
  9. #include "FrameworkMath.h"
  10. using namespace Framework;
  11. // Contents of the Character class from Font.h
  12. // Constructor
  13. Character::Character()
  14. : ReferenceCounter(),
  15. size(0, 0),
  16. alpha(0),
  17. fontSize(0)
  18. {}
  19. // Destructor
  20. Character::~Character()
  21. {
  22. if (alpha) delete[] alpha;
  23. }
  24. // non-constant
  25. void Character::NewCharacter(Point& size) // Initialization
  26. {
  27. this->size = size;
  28. if (alpha) delete[] alpha;
  29. alpha = new unsigned char[size.x * size.y];
  30. ZeroMemory(alpha, size.x * size.y);
  31. }
  32. void Character::setPixel(
  33. Point& pos, unsigned char alpha) // sets the alpha value of the pixel
  34. {
  35. this->alpha[pos.x + pos.y * size.x] = alpha;
  36. }
  37. void Character::setPixel(int x, int y, unsigned char alpha)
  38. {
  39. this->alpha[x + y * size.x] = alpha;
  40. }
  41. void Character::setPixel(int i, unsigned char alpha)
  42. {
  43. this->alpha[i] = alpha;
  44. }
  45. void Character::setFontSize(int sg) // sets the font size of the character
  46. {
  47. fontSize = sg;
  48. }
  49. int Character::getFontSize() const
  50. {
  51. return fontSize;
  52. }
  53. // constant
  54. const Point& Character::getSize() const // returns the character image size
  55. {
  56. return size;
  57. }
  58. int Character::getWidth() const // character width
  59. {
  60. return size.x;
  61. }
  62. int Character::getHeight() const // character height
  63. {
  64. return size.y;
  65. }
  66. unsigned char* Character::getBuff() const // returns the alpha buffer
  67. {
  68. return alpha;
  69. }
  70. // Contents of the Alphabet class from Font.h
  71. // Constructor
  72. Alphabet::Alphabet()
  73. : ReferenceCounter(),
  74. zeichen(new Character*[256]),
  75. fontSize(12)
  76. {
  77. for (int i = 0; i < 256; ++i)
  78. zeichen[i] = 0;
  79. }
  80. // Destructor
  81. Alphabet::~Alphabet()
  82. {
  83. for (int i = 0; i < 256; ++i)
  84. {
  85. if (zeichen[i]) zeichen[i]->release();
  86. }
  87. delete[] zeichen;
  88. }
  89. // non-constant
  90. void Alphabet::NeuAlphabet() // Initialization
  91. {
  92. for (int i = 0; i < 256; ++i)
  93. {
  94. if (zeichen[i]) zeichen[i]->release();
  95. }
  96. for (int i = 0; i < 256; ++i)
  97. zeichen[i] = 0;
  98. }
  99. void Alphabet::setCharacter(
  100. unsigned char i, Character* buchstabe) // sets a character
  101. {
  102. if (zeichen[i]) zeichen[i]->release();
  103. zeichen[i] = buchstabe;
  104. if (zeichen[i])
  105. {
  106. zeichen[i]->setFontSize(fontSize);
  107. }
  108. }
  109. void Alphabet::setFontSize(int gr) // sets the font size
  110. {
  111. fontSize = gr;
  112. for (int i = 0; i < 256; ++i)
  113. {
  114. if (zeichen[i]) zeichen[i]->setFontSize(gr);
  115. }
  116. }
  117. // constant
  118. Character* Alphabet::getCharacter(unsigned char i) const // returns a character
  119. {
  120. if (zeichen[i]) return dynamic_cast<Character*>(zeichen[i]->getThis());
  121. return 0;
  122. }
  123. Character* Alphabet::zCharacter(unsigned char i) const
  124. {
  125. return zeichen[i];
  126. }
  127. bool Alphabet::hasCharacter(unsigned char b) const
  128. {
  129. return zeichen[b] != 0;
  130. }
  131. int Alphabet::getFontSize() const // returns the font size
  132. {
  133. return fontSize;
  134. }
  135. // Contents of the AlphabetArray class from Font.h
  136. // Constructor
  137. AlphabetArray::AlphabetArray()
  138. {
  139. memset(alphabets, 0, sizeof(Alphabet*) * 256);
  140. }
  141. Framework::AlphabetArray::~AlphabetArray()
  142. {
  143. for (int i = 0; i < 256; ++i)
  144. {
  145. if (alphabets[i]) alphabets[i]->release();
  146. }
  147. }
  148. // non-constant
  149. bool AlphabetArray::addAlphabet(Alphabet* alphabet) // Adds an alphabet
  150. {
  151. if (alphabets[alphabet->getFontSize()] != 0)
  152. {
  153. alphabet->release();
  154. return 0;
  155. }
  156. alphabets[alphabet->getFontSize()] = alphabet;
  157. return 1;
  158. }
  159. bool AlphabetArray::removeAlphabet(unsigned char sg) // removes an alphabet
  160. {
  161. if (alphabets[sg])
  162. {
  163. alphabets[sg]->release();
  164. alphabets[sg] = 0;
  165. return 1;
  166. }
  167. return 0;
  168. }
  169. // constant
  170. Alphabet* AlphabetArray::getAlphabet(
  171. unsigned char sg) const // returns getThis of an alphabet
  172. {
  173. if (alphabets[sg]) return dynamic_cast<Alphabet*>(alphabets[sg]->getThis());
  174. return 0;
  175. }
  176. Alphabet* AlphabetArray::zAlphabet(
  177. unsigned char sg) const // returns an alphabet
  178. {
  179. return alphabets[sg];
  180. }
  181. // Contents of the Font class from Font.h
  182. // Constructor
  183. Font::Font()
  184. : ReferenceCounter(),
  185. alphabetCount(0),
  186. alphabet(new AlphabetArray())
  187. {}
  188. // Destructor
  189. Font::~Font()
  190. {
  191. delete alphabet;
  192. }
  193. bool Font::addAlphabet(Alphabet* alphabet) // Adds an alphabet to the font
  194. {
  195. if (this->alphabet->addAlphabet(alphabet))
  196. {
  197. ++alphabetCount;
  198. return true;
  199. }
  200. return false;
  201. }
  202. void Font::removeAlphabet(unsigned char sg) // Removes an alphabet
  203. {
  204. if (alphabet->removeAlphabet(sg)) --alphabetCount;
  205. }
  206. // constant
  207. Alphabet* Font::getAlphabet(unsigned char sg) const
  208. {
  209. Alphabet* drawAlphabet = alphabet->zAlphabet(sg);
  210. if (!drawAlphabet)
  211. {
  212. for (int i = 0; i < 256; ++i)
  213. {
  214. if (sg - i > 0)
  215. {
  216. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i));
  217. if (drawAlphabet) break;
  218. }
  219. if (sg + i < 256)
  220. {
  221. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i));
  222. if (drawAlphabet) break;
  223. }
  224. }
  225. }
  226. return dynamic_cast<Alphabet*>(drawAlphabet->getThis());
  227. }
  228. Alphabet* Font::zAlphabet(unsigned char sg) const
  229. {
  230. Alphabet* drawAlphabet = alphabet->zAlphabet(sg);
  231. if (!drawAlphabet)
  232. {
  233. for (int i = 0; i < 256; ++i)
  234. {
  235. if (sg - i > 0)
  236. {
  237. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i));
  238. if (drawAlphabet) break;
  239. }
  240. if (sg + i < 256)
  241. {
  242. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i));
  243. if (drawAlphabet) break;
  244. }
  245. }
  246. }
  247. return drawAlphabet;
  248. }
  249. unsigned char Font::getAlphabetCount()
  250. const // returns the number of alphabets contained in the font
  251. {
  252. return alphabetCount;
  253. }
  254. TextRenderer::TextRenderer()
  255. : TextRenderer(0)
  256. {}
  257. TextRenderer::TextRenderer(Font* font)
  258. : ReferenceCounter()
  259. {
  260. s = font;
  261. lineSpacing = 5;
  262. charSpacing = 0;
  263. fontSize = 0;
  264. setFontSize(12);
  265. }
  266. TextRenderer::~TextRenderer()
  267. {
  268. if (s) s->release();
  269. }
  270. void TextRenderer::setFontZ(Font* font)
  271. {
  272. if (s != font)
  273. {
  274. if (s) s->release();
  275. s = font;
  276. memset(charWidths, 0, sizeof(charWidths));
  277. memset(charHeights, 0, sizeof(charHeights));
  278. if (s)
  279. {
  280. Alphabet* a = s->zAlphabet((unsigned char)fontSize);
  281. for (int i = 0; i < 256; i++)
  282. {
  283. Character* b = a->zCharacter((unsigned char)i);
  284. if (b)
  285. {
  286. charWidths[i]
  287. = (int)((b->getWidth() / (double)a->getFontSize())
  288. * fontSize
  289. + 0.5);
  290. charHeights[i]
  291. = (int)((b->getHeight() / (double)a->getFontSize())
  292. * fontSize
  293. + 0.5);
  294. }
  295. else
  296. {
  297. charWidths[i] = 0;
  298. charHeights[i] = 0;
  299. }
  300. }
  301. }
  302. }
  303. else
  304. {
  305. font->release();
  306. }
  307. }
  308. Font* TextRenderer::getFont()
  309. {
  310. if (s) return dynamic_cast<Font*>(s->getThis());
  311. return 0;
  312. }
  313. Font* TextRenderer::zFont()
  314. {
  315. return s;
  316. }
  317. // Sets the font size to draw with. The font automatically selects the
  318. // appropriate alphabet for drawing
  319. // sg: The font size
  320. void TextRenderer::setFontSize(int sg)
  321. {
  322. if (fontSize != sg)
  323. {
  324. fontSize = sg;
  325. memset(charWidths, 0, sizeof(charWidths));
  326. memset(charHeights, 0, sizeof(charHeights));
  327. if (s)
  328. {
  329. Alphabet* a = s->zAlphabet((unsigned char)fontSize);
  330. for (int i = 0; i < 256; i++)
  331. {
  332. Character* b = a->zCharacter((unsigned char)i);
  333. if (b)
  334. {
  335. charWidths[i]
  336. = (int)((b->getWidth() / (double)a->getFontSize())
  337. * fontSize
  338. + 0.5);
  339. charHeights[i]
  340. = (int)((b->getHeight() / (double)a->getFontSize())
  341. * fontSize
  342. + 0.5);
  343. }
  344. else
  345. {
  346. charWidths[i] = 0;
  347. charHeights[i] = 0;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. // Sets the line spacing to use for drawing
  354. // za: The line spacing to the bottom of the line above in pixels
  355. void TextRenderer::setLineSpacing(int za)
  356. {
  357. lineSpacing = za;
  358. }
  359. // Sets the character spacing to use for drawing
  360. // za: The character spacing in pixels
  361. void TextRenderer::setCharSpacing(int za)
  362. {
  363. charSpacing = za;
  364. }
  365. // Inserts line breaks into the text so it is fully displayed at a given width
  366. // zText: The text to insert line breaks into
  367. // maxWidth: The width in pixels at which the text should be fully displayed
  368. void TextRenderer::formatText(Text* zTxt, int maxWidth)
  369. {
  370. int lastPos = -1;
  371. int x = 0;
  372. const char* txt = zTxt->getText();
  373. Text result = txt;
  374. int len = zTxt->getLength();
  375. for (int i = 0; i < len; ++i)
  376. {
  377. if (txt[i] == ' ')
  378. {
  379. lastPos = i;
  380. x += fontSize / 2 + charSpacing;
  381. continue;
  382. }
  383. if (txt[i] == '\t')
  384. {
  385. lastPos = i;
  386. x += fontSize + charSpacing;
  387. continue;
  388. }
  389. if (txt[i] == '\n')
  390. {
  391. x = 0;
  392. lastPos = -1;
  393. continue;
  394. }
  395. x += getCharWidth(txt[i]) + charSpacing;
  396. if (x > maxWidth && lastPos > -1)
  397. {
  398. result.replace(lastPos, lastPos + 1, "\n");
  399. x = 0;
  400. i = lastPos;
  401. lastPos = -1;
  402. }
  403. }
  404. zTxt->setText(result);
  405. }
  406. // Draws a specific text with cursor and coloring onto an image
  407. // Use (setPosition) and (setDrawFontGroesse) to change position and size
  408. // x: x position of the first character
  409. // y: y position of the first character
  410. // txt: The text to draw
  411. // zRObj: The image to draw on
  412. // cpos: The position of the cursor in the text
  413. // cf: The color of the cursor
  414. // fbeg: The position of the character in the text where coloring should begin.
  415. // The text is colored from there to the cursor position
  416. // ff: The background color of the colored text
  417. // f: A function called for each character that returns its color
  418. void TextRenderer::renderText(int x,
  419. int y,
  420. const char* txt,
  421. Image& zRObj,
  422. std::function<int(int, int, int)> f,
  423. int cpos,
  424. int cf,
  425. int fbeg,
  426. int ff)
  427. {
  428. if (!s) return;
  429. if (fbeg == -1) fbeg = cpos;
  430. int zRObjBr = zRObj.getWidth();
  431. int zRObjHi = zRObj.getHeight();
  432. const Point& zRObjOff = zRObj.getDrawOff();
  433. int beginX = x;
  434. int zh = getRowHeight();
  435. if (y + (zh + lineSpacing) * Text(txt).countOf('\n') + zh + zRObjOff.y < 0
  436. || x + zRObjOff.x >= zRObjBr || y + zRObjOff.y >= zRObjHi)
  437. return;
  438. bool faerb = 0;
  439. int len = textLength(txt);
  440. for (int i = 0; i < len; ++i)
  441. {
  442. if (i == fbeg) faerb = !faerb;
  443. if (i == cpos)
  444. {
  445. zRObj.drawLineVAlpha(x, y, zh, cf);
  446. faerb = !faerb;
  447. }
  448. if (txt[i] == ' ')
  449. {
  450. if (faerb)
  451. zRObj.alphaRegion(x, y, fontSize / 2 + charSpacing, zh, ff);
  452. x += fontSize / 2 + charSpacing;
  453. continue;
  454. }
  455. if (txt[i] == '\t')
  456. {
  457. if (faerb) zRObj.alphaRegion(x, y, fontSize + charSpacing, zh, ff);
  458. x += fontSize + charSpacing;
  459. continue;
  460. }
  461. if (txt[i] == '\n')
  462. {
  463. y += zh + lineSpacing;
  464. x = beginX;
  465. continue;
  466. }
  467. renderChar(x, y, txt[i], zRObj, f(x, y, i), 0, faerb, ff);
  468. }
  469. if (textLength(txt) == cpos) zRObj.drawLineVAlpha(x, y, zh, cf);
  470. }
  471. // Draws a specific text with cursor and coloring onto an image
  472. // Use (setPosition) and (setDrawFontGroesse) to change position and size
  473. // x: x position of the first character
  474. // y: y position of the first character
  475. // txt: The text to draw
  476. // zRObj: The image to draw on
  477. // cpos: The position of the cursor in the text
  478. // cf: The color of the cursor
  479. // fbeg: The position of the character in the text where coloring should begin.
  480. // The text is colored from there to the cursor position
  481. // ff: The background color of the colored text
  482. // f: The color in which the text should be drawn
  483. void TextRenderer::renderText(int x,
  484. int y,
  485. const char* txt,
  486. Image& zRObj,
  487. int f,
  488. int cpos,
  489. int cf,
  490. int fbeg,
  491. int ff)
  492. {
  493. return renderText(
  494. x,
  495. y,
  496. txt,
  497. zRObj,
  498. [f](int a, int b, int c) { return f; },
  499. cpos,
  500. cf,
  501. fbeg,
  502. ff);
  503. }
  504. // Draws a specific character with coloring onto an image
  505. // Use (setPosition) and (setDrawFontGroesse) to change position and size
  506. // x: x position of the first character
  507. // y: y position of the first character
  508. // txt: The text to draw
  509. // zRObj: The image to draw on
  510. // color: The color in which the text should be drawn
  511. // underlined: 1 if the text should be underlined
  512. // selected: 1 if the character should be colored
  513. // selectedBackgroundColor: The background color of the colored text
  514. void TextRenderer::renderChar(int& x,
  515. int y,
  516. char c,
  517. Image& zRObj,
  518. int color,
  519. bool underlined,
  520. bool selected,
  521. int selectedBackgroundColor)
  522. {
  523. if (!s) return;
  524. Alphabet* a = s->zAlphabet((unsigned char)fontSize);
  525. if (!a) return;
  526. Character* b = a->zCharacter(c);
  527. if (b)
  528. {
  529. if (x >= zRObj.getWidth()) return;
  530. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  531. {
  532. if (selected)
  533. {
  534. int br = getCharWidth(c) + charSpacing;
  535. zRObj.alphaRegion(x,
  536. y,
  537. br,
  538. getRowHeight() + lineSpacing,
  539. selectedBackgroundColor);
  540. }
  541. if (b->getBuff())
  542. {
  543. const Point& zRObjGr = zRObj.getDrawGr();
  544. const Point& zRObjPos = zRObj.getDrawPos();
  545. const Point& zRObjOff = zRObj.getDrawOff();
  546. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  547. int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  548. ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  549. int br = b->getWidth();
  550. unsigned char a2 = (unsigned char)(255 - (color >> 24));
  551. color &= 0x00FFFFFF;
  552. float xoff = (float)b->getFontSize() / (float)fontSize,
  553. yoff = (float)b->getFontSize() / (float)fontSize;
  554. float x = (float)xs * xoff, y = (float)ys * yoff;
  555. int maxX = getCharWidth(c), maxY = getCharHeight(c);
  556. maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX;
  557. maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY;
  558. int a, dx, ygr, ygr2;
  559. if (zRObj.hasAlpha3D())
  560. {
  561. for (int dy = ys; dy < maxY; ++dy)
  562. {
  563. ygr2 = (yp + dy) * zRObj.getWidth() + xp;
  564. ygr = (int)y * br;
  565. for (dx = xs; dx < maxX; ++dx)
  566. {
  567. a = b->getBuff()[(int)x + ygr] - a2;
  568. zRObj.alphaPixel3D(dx + ygr2, color | (a << 24));
  569. x += xoff;
  570. }
  571. x = (float)xs;
  572. y += yoff;
  573. }
  574. }
  575. else
  576. {
  577. for (int dy = ys; dy < maxY; ++dy)
  578. {
  579. ygr2 = (yp + dy) * zRObj.getWidth() + xp;
  580. ygr = (int)y * br;
  581. for (dx = xs; dx < maxX; ++dx)
  582. {
  583. a = b->getBuff()[(int)x + ygr] - a2;
  584. zRObj.alphaPixel2D(dx + ygr2, color | (a << 24));
  585. x += xoff;
  586. }
  587. x = (float)xs;
  588. y += yoff;
  589. }
  590. }
  591. }
  592. if (underlined)
  593. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  594. y + getRowHeight() + getCharSpacing() / 2,
  595. getCharWidth(c) + (int)(charSpacing / 2.0 + 0.5),
  596. 0xFF000000 | color);
  597. }
  598. x += getCharWidth(c) + charSpacing;
  599. }
  600. else if (c == ' ')
  601. {
  602. if (selected)
  603. zRObj.alphaRegion(x,
  604. y,
  605. fontSize / 2 + charSpacing,
  606. getRowHeight() + lineSpacing,
  607. selectedBackgroundColor);
  608. if (underlined)
  609. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  610. y + getRowHeight() + getCharSpacing() / 2,
  611. fontSize / 2 + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  612. 0xFF000000 | color);
  613. x += fontSize / 2 + charSpacing;
  614. }
  615. else if (c == '\t')
  616. {
  617. if (selected)
  618. zRObj.alphaRegion(x,
  619. y,
  620. fontSize + charSpacing,
  621. getRowHeight() + lineSpacing,
  622. selectedBackgroundColor);
  623. if (underlined)
  624. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  625. y + getRowHeight() + getCharSpacing() / 2,
  626. fontSize + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  627. 0xFF000000 | color);
  628. x += fontSize + charSpacing;
  629. }
  630. }
  631. // Returns the font size used for drawing
  632. int TextRenderer::getFontSize() const
  633. {
  634. return fontSize;
  635. }
  636. // Returns the character spacing in pixels on the x axis
  637. int TextRenderer::getCharSpacing() const
  638. {
  639. return charSpacing;
  640. }
  641. // Determines how many pixels are needed to fully display a specific text
  642. // txt: The text whose width in pixels should be determined
  643. int TextRenderer::getTextWidth(const char* txt) const
  644. {
  645. int ret = 0;
  646. int tmp = 0;
  647. int len = textLength(txt);
  648. for (int i = 0; i < len; ++i)
  649. {
  650. if (txt[i] == '\n')
  651. {
  652. if (tmp > ret) ret = tmp;
  653. tmp = 0;
  654. }
  655. else
  656. tmp += getCharWidth(txt[i]) + charSpacing;
  657. }
  658. if (tmp > ret) ret = tmp;
  659. return ret;
  660. }
  661. // Determines how many pixels are needed to fully display a specific text
  662. // txt: The text whose height in pixels should be determined
  663. int TextRenderer::getTextHeight(const char* txt) const
  664. {
  665. int hi = getRowHeight();
  666. return hi + ((hi + lineSpacing) * Text(txt).countOf('\n'));
  667. }
  668. // Determines how many pixels are needed to fully display a specific character
  669. // c: The character whose width in pixels should be determined
  670. int TextRenderer::getCharWidth(const char c) const
  671. {
  672. if (c == '\t')
  673. return fontSize;
  674. else if (c == ' ')
  675. return fontSize / 2;
  676. else
  677. return charWidths[(unsigned char)c];
  678. }
  679. int Framework::TextRenderer::getMaxCharWidth() const
  680. {
  681. int result = 0;
  682. for (int i = 0; i < 256; i++)
  683. {
  684. result = MAX(result, getCharWidth((char)i));
  685. }
  686. return result;
  687. }
  688. // Determines how many pixels are needed to fully display a specific character
  689. // c: The character whose height in pixels should be determined
  690. int TextRenderer::getCharHeight(const char c) const
  691. {
  692. return charHeights[(unsigned char)c];
  693. }
  694. // Returns the line spacing in pixels to the bottom of the line above
  695. int TextRenderer::getLineSpacing() const
  696. {
  697. return lineSpacing;
  698. }
  699. // Returns the scaled height needed by a drawn line in pixels
  700. int TextRenderer::getRowHeight() const
  701. {
  702. int zh = 0;
  703. for (int i = 0; i < 256; ++i)
  704. {
  705. zh = maxInt(getCharHeight((char)i), zh);
  706. }
  707. return zh;
  708. }
  709. // Determines the character in the text that the mouse points to
  710. // txt: The text the mouse points to
  711. // mouseX: The X position of the mouse in pixels relative to the position of
  712. // the first character
  713. // mouseY: The Y position of the mouse in pixels relative to the position of
  714. // the first character
  715. int TextRenderer::textPos(const char* txt, int mouseX, int mouseY) const
  716. {
  717. int tx = 0;
  718. int ty = 0;
  719. int sh = getRowHeight();
  720. if (mouseX < 0 || mouseY < 0) return -1;
  721. int len = textLength(txt);
  722. for (int i = 0; i < len; ++i)
  723. {
  724. if (txt[i] == '\n')
  725. {
  726. ty += sh + lineSpacing;
  727. tx = 0;
  728. if (mouseY < ty) return i;
  729. }
  730. if (txt[i] == '\t')
  731. {
  732. tx += fontSize + charSpacing;
  733. }
  734. else if (txt[i] == ' ')
  735. {
  736. tx += fontSize / 2 + charSpacing;
  737. }
  738. else
  739. {
  740. tx += getCharWidth(txt[i]) + charSpacing;
  741. }
  742. int txpl = getCharWidth(txt[i]) / 2;
  743. if (mouseX < tx - txpl && mouseY < ty + sh + lineSpacing) return i;
  744. }
  745. if (mouseY < ty + sh + lineSpacing) return textLength(txt);
  746. return -1;
  747. }
  748. EngravedTextRenderer::EngravedTextRenderer()
  749. : EngravedTextRenderer(0)
  750. {}
  751. EngravedTextRenderer::EngravedTextRenderer(Font* font)
  752. : TextRenderer(font)
  753. {}
  754. EngravedTextRenderer::~EngravedTextRenderer() {}
  755. // Draws a specific character with coloring onto an image
  756. // Use (setPosition) and (setDrawFontGroesse) to change position and size
  757. // x: x position of the first character
  758. // y: y position of the first character
  759. // txt: The text to draw
  760. // zRObj: The image to draw on
  761. // color: The color in which the text should be drawn
  762. // underlined: 1 if the text should be underlined
  763. // selected: 1 if the character should be colored
  764. // selectedBackgroundColor: The background color of the colored text
  765. void EngravedTextRenderer::renderChar(int& x,
  766. int y,
  767. char c,
  768. Image& zRObj,
  769. int color,
  770. bool underlined,
  771. bool selected,
  772. int selectedBackgroundColor)
  773. {
  774. if (!s) return;
  775. Alphabet* a = s->zAlphabet((unsigned char)fontSize);
  776. Character* b = a->zCharacter(c);
  777. if (b)
  778. {
  779. if (x >= zRObj.getWidth()) return;
  780. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  781. {
  782. if (selected)
  783. {
  784. int br = getCharWidth(c) + charSpacing;
  785. zRObj.alphaRegion(x,
  786. y,
  787. br,
  788. getRowHeight() + lineSpacing,
  789. selectedBackgroundColor);
  790. }
  791. if (b->getBuff())
  792. {
  793. const Point& zRObjGr = zRObj.getDrawGr();
  794. const Point& zRObjPos = zRObj.getDrawPos();
  795. const Point& zRObjOff = zRObj.getDrawOff();
  796. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  797. int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  798. ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  799. int br = b->getWidth(), h = b->getHeight();
  800. color &= 0x00FFFFFF;
  801. double xoff = (double)b->getFontSize() / (fontSize * 2.0),
  802. yoff = (double)b->getFontSize() / (fontSize * 2.0);
  803. double x = xs * xoff, y = ys * yoff;
  804. int maxX = getCharWidth(c), maxY = getCharHeight(c);
  805. maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX;
  806. maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY;
  807. int dx, ygr, ygr2;
  808. if (zRObj.hasAlpha3D())
  809. {
  810. for (int dy = ys; dy < maxY; ++dy)
  811. {
  812. ygr2 = (yp + dy) * zRObj.getWidth();
  813. ygr = (int)y * br;
  814. for (dx = xs; dx < maxX; ++dx)
  815. {
  816. int f = 0;
  817. if (b->getBuff()[(int)x + ygr])
  818. f = 0x50000000;
  819. else if (((int)(x + xoff) < br
  820. && b->getBuff()[(int)(x + xoff) + ygr])
  821. || ((int)(y - yoff) < h
  822. && b->getBuff()[(int)x
  823. + (int)(y - yoff) * br]
  824. > 0xF0))
  825. f = 0xA0000000;
  826. else if (((int)(x - xoff) < br
  827. && b->getBuff()[(int)(x - xoff) + ygr])
  828. || ((int)(y + yoff) < h
  829. && b->getBuff()[(int)x
  830. + (int)(y + yoff) * br]
  831. > 0xF0))
  832. {
  833. f = 0xA0FFFFFF;
  834. }
  835. zRObj.alphaPixel3D(xp + dx + ygr2, f);
  836. x += xoff;
  837. }
  838. x = xs;
  839. y += yoff;
  840. }
  841. }
  842. else
  843. {
  844. for (int dy = ys; dy < maxY; ++dy)
  845. {
  846. ygr2 = (yp + dy) * zRObj.getWidth();
  847. ygr = (int)y * br;
  848. for (dx = xs; dx < maxX; ++dx)
  849. {
  850. int f = 0;
  851. if (b->getBuff()[(int)x + ygr])
  852. f = 0x50000000;
  853. else if (((int)(x + xoff) < br
  854. && b->getBuff()[(int)(x + xoff) + ygr])
  855. || ((int)(y - yoff) < h
  856. && b->getBuff()[(int)x
  857. + (int)(y - yoff) * br]
  858. > 0xF0))
  859. f = 0xA0000000;
  860. else if (((int)(x - xoff) < br
  861. && b->getBuff()[(int)(x - xoff) + ygr])
  862. || ((int)(y + yoff) < h
  863. && b->getBuff()[(int)x
  864. + (int)(y + yoff) * br]
  865. > 0xF0))
  866. {
  867. f = 0xA0FFFFFF;
  868. }
  869. zRObj.alphaPixel2D(xp + dx + ygr2, f);
  870. x += xoff;
  871. }
  872. x = xs;
  873. y += yoff;
  874. }
  875. }
  876. }
  877. if (underlined)
  878. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  879. y + getRowHeight() + getCharSpacing() / 2,
  880. getCharWidth(c) + (int)(charSpacing / 2.0 + 0.5),
  881. 0xFF000000 | color);
  882. }
  883. x += getCharWidth(c) + charSpacing;
  884. }
  885. else if (c == ' ')
  886. {
  887. if (selected)
  888. zRObj.alphaRegion(x,
  889. y,
  890. fontSize / 2 + charSpacing,
  891. getRowHeight() + lineSpacing,
  892. selectedBackgroundColor);
  893. if (underlined)
  894. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  895. y + getRowHeight() + getCharSpacing() / 2,
  896. fontSize / 2 + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  897. 0xFF000000 | color);
  898. x += fontSize / 2 + charSpacing;
  899. }
  900. else if (c == '\t')
  901. {
  902. if (selected)
  903. zRObj.alphaRegion(x,
  904. y,
  905. fontSize + charSpacing,
  906. getRowHeight() + lineSpacing,
  907. selectedBackgroundColor);
  908. if (underlined)
  909. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  910. y + getRowHeight() + getCharSpacing() / 2,
  911. fontSize + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  912. 0xFF000000 | color);
  913. x += fontSize + charSpacing;
  914. }
  915. }
  916. // Determines how many pixels are needed to fully display a specific character
  917. // c: The character whose width in pixels should be determined
  918. int EngravedTextRenderer::getCharWidth(const char c) const
  919. {
  920. if (c == '\t')
  921. return fontSize;
  922. else if (c == ' ')
  923. return fontSize / 2;
  924. else
  925. return TextRenderer::getCharWidth(c) * 2;
  926. }
  927. // Determines how many pixels are needed to fully display a specific character
  928. // c: The character whose height in pixels should be determined
  929. int EngravedTextRenderer::getCharHeight(const char c) const
  930. {
  931. return TextRenderer::getCharHeight(c) * 2;
  932. }
  933. ItalicTextRenderer::ItalicTextRenderer()
  934. : ItalicTextRenderer(0)
  935. {}
  936. ItalicTextRenderer::ItalicTextRenderer(Font* font)
  937. : TextRenderer(font)
  938. {}
  939. ItalicTextRenderer::~ItalicTextRenderer() {}
  940. // Draws a specific character with coloring onto an image
  941. // Use (setPosition) and (setDrawFontGroesse) to change position and size
  942. // x: x position of the first character
  943. // y: y position of the first character
  944. // txt: The text to draw
  945. // zRObj: The image to draw on
  946. // color: The color in which the text should be drawn
  947. // underlined: 1 if the text should be underlined
  948. // selected: 1 if the character should be colored
  949. // selectedBackgroundColor: The background color of the colored text
  950. void ItalicTextRenderer::renderChar(int& x,
  951. int y,
  952. char c,
  953. Image& zRObj,
  954. int color,
  955. bool underlined,
  956. bool selected,
  957. int selectedBackgroundColor)
  958. {
  959. if (!s) return;
  960. Alphabet* a = s->zAlphabet((unsigned char)fontSize);
  961. if (!a) return;
  962. Character* b = a->zCharacter(c);
  963. if (b)
  964. {
  965. if (x >= zRObj.getWidth()) return;
  966. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  967. {
  968. if (selected)
  969. {
  970. int br = getCharWidth(c) + charSpacing;
  971. zRObj.alphaRegion(x,
  972. y,
  973. br,
  974. getRowHeight() + lineSpacing,
  975. selectedBackgroundColor);
  976. }
  977. if (b->getBuff())
  978. {
  979. const Point& zRObjGr = zRObj.getDrawGr();
  980. const Point& zRObjPos = zRObj.getDrawPos();
  981. const Point& zRObjOff = zRObj.getDrawOff();
  982. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  983. int xStartBuffer = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  984. yStartBuffer = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  985. int bufferWidth = b->getWidth(), bufferHeight = b->getHeight();
  986. unsigned char colorAlpha = (unsigned char)(255 - (color >> 24));
  987. color &= 0x00FFFFFF;
  988. double xStepBuffer
  989. = (double)b->getFontSize() / (double)fontSize,
  990. yStepBuffer = (double)b->getFontSize() / (double)fontSize;
  991. double xBuffer = xStartBuffer * xStepBuffer,
  992. yBuffer = yStartBuffer * yStepBuffer;
  993. int charHeight = getCharHeight(c);
  994. int maxXBuffer = getCharWidth(c), maxYBuffer = charHeight;
  995. maxXBuffer = (xp + maxXBuffer) >= zRObjGr.x ? (zRObjGr.x - xp)
  996. : maxXBuffer;
  997. maxYBuffer = (yp + maxYBuffer) >= zRObjGr.y ? (zRObjGr.y - yp)
  998. : maxYBuffer;
  999. std::function<int(int x, int y)> colorF = [charHeight,
  1000. bufferWidth,
  1001. bufferHeight,
  1002. colorAlpha,
  1003. b,
  1004. color](
  1005. int xx, int yy) {
  1006. xx -= (int)((float)(charHeight - yy) / 4.f + 0.5f);
  1007. if (xx < 0 || xx >= bufferWidth) return 0x00FFFFFF;
  1008. int a = b->getBuff()[yy * bufferWidth + xx] - colorAlpha;
  1009. return color | (a << 24);
  1010. };
  1011. if (zRObj.hasAlpha3D())
  1012. {
  1013. for (int yS = yStartBuffer; yS < maxYBuffer; ++yS)
  1014. {
  1015. int ygr2 = (yp + yS) * zRObj.getWidth();
  1016. for (int xS = xStartBuffer; xS < maxXBuffer; ++xS)
  1017. {
  1018. zRObj.alphaPixel3D(
  1019. xp + xS + ygr2, colorF((int)xS, (int)yS));
  1020. xBuffer += xStepBuffer;
  1021. }
  1022. xBuffer = xStartBuffer;
  1023. yBuffer += yStepBuffer;
  1024. }
  1025. }
  1026. else
  1027. {
  1028. for (int yS = yStartBuffer; yS < maxYBuffer; ++yS)
  1029. {
  1030. int ygr2 = (yp + yS) * zRObj.getWidth();
  1031. for (int xS = xStartBuffer; xS < maxXBuffer; ++xS)
  1032. {
  1033. zRObj.alphaPixel2D(
  1034. xp + xS + ygr2, colorF((int)xS, (int)yS));
  1035. xBuffer += xStepBuffer;
  1036. }
  1037. xBuffer = xStartBuffer;
  1038. yBuffer += yStepBuffer;
  1039. }
  1040. }
  1041. }
  1042. if (underlined)
  1043. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  1044. y + getRowHeight() + getCharSpacing() / 2,
  1045. getCharWidth(c) + (int)(charSpacing / 2.0 + 0.5),
  1046. 0xFF000000 | color);
  1047. }
  1048. x += getCharWidth(c) + charSpacing;
  1049. }
  1050. else if (c == ' ')
  1051. {
  1052. if (selected)
  1053. zRObj.alphaRegion(x,
  1054. y,
  1055. fontSize / 2 + charSpacing,
  1056. getRowHeight() + lineSpacing,
  1057. selectedBackgroundColor);
  1058. if (underlined)
  1059. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  1060. y + getRowHeight() + getCharSpacing() / 2,
  1061. fontSize / 2 + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  1062. 0xFF000000 | color);
  1063. x += fontSize / 2 + charSpacing;
  1064. }
  1065. else if (c == '\t')
  1066. {
  1067. if (selected)
  1068. zRObj.alphaRegion(x,
  1069. y,
  1070. fontSize + charSpacing,
  1071. getRowHeight() + lineSpacing,
  1072. selectedBackgroundColor);
  1073. if (underlined)
  1074. zRObj.drawLineHAlpha(x - (int)(charSpacing / 2.0 + 0.5),
  1075. y + getRowHeight() + getCharSpacing() / 2,
  1076. fontSize + charSpacing + (int)(charSpacing / 2.0 + 0.5),
  1077. 0xFF000000 | color);
  1078. x += fontSize + charSpacing;
  1079. }
  1080. }
  1081. // Determines how many pixels are needed to fully display a specific character
  1082. // c: The character whose width in pixels should be determined
  1083. int ItalicTextRenderer::getCharWidth(const char c) const
  1084. {
  1085. if (c == '\t')
  1086. return fontSize;
  1087. else if (c == ' ')
  1088. return fontSize / 2;
  1089. else
  1090. return (
  1091. int)(TextRenderer::getCharWidth(c) + getCharHeight(c) / 4.0 + 0.5);
  1092. }