Schrift.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. #include "Schrift.h"
  2. #include "Bild.h"
  3. #include "Globals.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. // Inhalt der Buchstabe Klasse aus Schrift.h
  12. // Konstruktor
  13. Buchstabe::Buchstabe()
  14. : ReferenceCounter(),
  15. size(0, 0),
  16. alpha(0),
  17. schriftSize(0)
  18. {}
  19. // Destruktor
  20. Buchstabe::~Buchstabe()
  21. {
  22. if (alpha) delete[] alpha;
  23. }
  24. // nicht constant
  25. void Buchstabe::NeuBuchstabe(Punkt& size) // Initialisierung
  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 Buchstabe::setPixel(
  33. Punkt& pos, unsigned char alpha) // setzt den alphawert des Pixels
  34. {
  35. this->alpha[pos.x + pos.y * size.x] = alpha;
  36. }
  37. void Buchstabe::setPixel(int x, int y, unsigned char alpha)
  38. {
  39. this->alpha[x + y * size.x] = alpha;
  40. }
  41. void Buchstabe::setPixel(int i, unsigned char alpha)
  42. {
  43. this->alpha[i] = alpha;
  44. }
  45. void Buchstabe::setSchriftSize(int sg) // setzt die Schriftgröße des Buchstaben
  46. {
  47. schriftSize = sg;
  48. }
  49. int Buchstabe::getSchriftSize() const
  50. {
  51. return schriftSize;
  52. }
  53. // constant
  54. const Punkt& Buchstabe::getSize() const // gibt die Buchstabenbildgröße zurück
  55. {
  56. return size;
  57. }
  58. int Buchstabe::getBreite() const // Buchstabenbreite
  59. {
  60. return size.x;
  61. }
  62. int Buchstabe::getHeight() const // Buchstabenhöhe
  63. {
  64. return size.y;
  65. }
  66. unsigned char* Buchstabe::getBuff() const // gibt den Alphabuffer zurück
  67. {
  68. return alpha;
  69. }
  70. // Inhalt der Alphabet Klasse aus Schrift.h
  71. // Konstruktor
  72. Alphabet::Alphabet()
  73. : ReferenceCounter(),
  74. zeichen(new Buchstabe*[256]),
  75. schriftSize(12)
  76. {
  77. for (int i = 0; i < 256; ++i)
  78. zeichen[i] = 0;
  79. }
  80. // Destruktor
  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. // nicht constant
  90. void Alphabet::NeuAlphabet() // Initialisierung
  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::setBuchstabe(
  100. unsigned char i, Buchstabe* buchstabe) // setzt einen Buchstaben
  101. {
  102. if (zeichen[i]) zeichen[i]->release();
  103. zeichen[i] = buchstabe;
  104. if (zeichen[i])
  105. {
  106. zeichen[i]->setSchriftSize(schriftSize);
  107. }
  108. }
  109. void Alphabet::setSchriftSize(int gr) // setzt die Schriftgröße
  110. {
  111. schriftSize = gr;
  112. for (int i = 0; i < 256; ++i)
  113. {
  114. if (zeichen[i]) zeichen[i]->setSchriftSize(gr);
  115. }
  116. }
  117. // constant
  118. Buchstabe* Alphabet::getBuchstabe(
  119. unsigned char i) const // gibt einen Buchstaben zurück
  120. {
  121. if (zeichen[i]) return dynamic_cast<Buchstabe*>(zeichen[i]->getThis());
  122. return 0;
  123. }
  124. Buchstabe* Alphabet::zBuchstabe(unsigned char i) const
  125. {
  126. return zeichen[i];
  127. }
  128. bool Alphabet::hatBuchstabe(unsigned char b) const
  129. {
  130. return zeichen[b] != 0;
  131. }
  132. int Alphabet::getSchriftSize() const // gibt die Schriftgröße zurück
  133. {
  134. return schriftSize;
  135. }
  136. // Inhalt der AlphabetArray Klasse aus Schrift.h
  137. // Konstruktor
  138. AlphabetArray::AlphabetArray()
  139. {
  140. memset(alphabets, 0, sizeof(Alphabet*) * 256);
  141. }
  142. // nicht constant
  143. bool AlphabetArray::addAlphabet(Alphabet* alphabet) // Fügt ein Alphabet hinzu
  144. {
  145. if (alphabets[alphabet->getSchriftSize()] != 0)
  146. {
  147. alphabet->release();
  148. return 0;
  149. }
  150. alphabets[alphabet->getSchriftSize()] = alphabet;
  151. return 1;
  152. }
  153. bool AlphabetArray::removeAlphabet(unsigned char sg) // entfernt ein Alphabet
  154. {
  155. if (alphabets[sg])
  156. {
  157. alphabets[sg]->release();
  158. alphabets[sg] = 0;
  159. return 1;
  160. }
  161. return 0;
  162. }
  163. // constant
  164. Alphabet* AlphabetArray::getAlphabet(
  165. unsigned char sg) const // gibt getThis von einem Alphabet zurück
  166. {
  167. if (alphabets[sg]) return dynamic_cast<Alphabet*>(alphabets[sg]->getThis());
  168. return 0;
  169. }
  170. Alphabet* AlphabetArray::zAlphabet(
  171. unsigned char sg) const // gibt ein Alphabet zurück
  172. {
  173. return alphabets[sg];
  174. }
  175. // Inhalt der Schrift Klasse aus Schrift.h
  176. // Konstruktor
  177. Schrift::Schrift()
  178. : ReferenceCounter(),
  179. alphabetAnzahl(0),
  180. alphabet(new AlphabetArray())
  181. {}
  182. // Destruktor
  183. Schrift::~Schrift()
  184. {
  185. delete alphabet;
  186. }
  187. bool Schrift::addAlphabet(
  188. Alphabet* alphabet) // Fügt der Schrift ein Alphabet hinzu
  189. {
  190. if (this->alphabet->addAlphabet(alphabet))
  191. {
  192. ++alphabetAnzahl;
  193. return true;
  194. }
  195. return false;
  196. }
  197. void Schrift::removeAlphabet(unsigned char sg) // Entfernt ein Alphabet
  198. {
  199. if (alphabet->removeAlphabet(sg)) --alphabetAnzahl;
  200. }
  201. // constant
  202. Alphabet* Schrift::getAlphabet(unsigned char sg) const
  203. {
  204. Alphabet* drawAlphabet = alphabet->zAlphabet(sg);
  205. if (!drawAlphabet)
  206. {
  207. for (int i = 0; i < 256; ++i)
  208. {
  209. if (sg - i > 0)
  210. {
  211. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i));
  212. if (drawAlphabet) break;
  213. }
  214. if (sg + i < 256)
  215. {
  216. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i));
  217. if (drawAlphabet) break;
  218. }
  219. }
  220. }
  221. return dynamic_cast<Alphabet*>(drawAlphabet->getThis());
  222. }
  223. Alphabet* Schrift::zAlphabet(unsigned char sg) const
  224. {
  225. Alphabet* drawAlphabet = alphabet->zAlphabet(sg);
  226. if (!drawAlphabet)
  227. {
  228. for (int i = 0; i < 256; ++i)
  229. {
  230. if (sg - i > 0)
  231. {
  232. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg - i));
  233. if (drawAlphabet) break;
  234. }
  235. if (sg + i < 256)
  236. {
  237. drawAlphabet = alphabet->zAlphabet((unsigned char)(sg + i));
  238. if (drawAlphabet) break;
  239. }
  240. }
  241. }
  242. return drawAlphabet;
  243. }
  244. unsigned char Schrift::getAlphabetAnzahl()
  245. const // gibt die anzahl von in der Schrift enthaltenen Alphabeten zurück
  246. {
  247. return alphabetAnzahl;
  248. }
  249. TextRenderer::TextRenderer()
  250. : TextRenderer(0)
  251. {}
  252. TextRenderer::TextRenderer(Schrift* schrift)
  253. : ReferenceCounter()
  254. {
  255. s = schrift;
  256. zeilenAbstand = 5;
  257. zeichenAbstand = 0;
  258. schriftSize = 0;
  259. setSchriftSize(12);
  260. }
  261. TextRenderer::~TextRenderer()
  262. {
  263. if (s) s->release();
  264. }
  265. void TextRenderer::setSchriftZ(Schrift* schrift)
  266. {
  267. if (s != schrift)
  268. {
  269. if (s) s->release();
  270. s = schrift;
  271. memset(charWidths, 0, sizeof(charWidths));
  272. memset(charHeights, 0, sizeof(charHeights));
  273. if (s)
  274. {
  275. Alphabet* a = s->zAlphabet((unsigned char)schriftSize);
  276. for (int i = 0; i < 256; i++)
  277. {
  278. Buchstabe* b = a->zBuchstabe((unsigned char)i);
  279. if (b)
  280. {
  281. charWidths[i]
  282. = (int)((b->getBreite() / (double)a->getSchriftSize())
  283. * schriftSize
  284. + 0.5);
  285. charHeights[i]
  286. = (int)((b->getHeight() / (double)a->getSchriftSize())
  287. * schriftSize
  288. + 0.5);
  289. }
  290. else
  291. {
  292. charWidths[i] = 0;
  293. charHeights[i] = 0;
  294. }
  295. }
  296. }
  297. }
  298. else
  299. {
  300. schrift->release();
  301. }
  302. }
  303. Schrift* TextRenderer::getSchrift()
  304. {
  305. if (s) return dynamic_cast<Schrift*>(s->getThis());
  306. return 0;
  307. }
  308. Schrift* TextRenderer::zSchrift()
  309. {
  310. return s;
  311. }
  312. // Setzt die Schriftgröße, in der gezeichnet werden soll. Die Schrift wählt
  313. // automatisch das passende Alphabet zum Zeichnen
  314. // sg: Die Schriftgröße
  315. void TextRenderer::setSchriftSize(int sg)
  316. {
  317. if (schriftSize != sg)
  318. {
  319. schriftSize = sg;
  320. memset(charWidths, 0, sizeof(charWidths));
  321. memset(charHeights, 0, sizeof(charHeights));
  322. if (s)
  323. {
  324. Alphabet* a = s->zAlphabet((unsigned char)schriftSize);
  325. for (int i = 0; i < 256; i++)
  326. {
  327. Buchstabe* b = a->zBuchstabe((unsigned char)i);
  328. if (b)
  329. {
  330. charWidths[i]
  331. = (int)((b->getBreite() / (double)a->getSchriftSize())
  332. * schriftSize
  333. + 0.5);
  334. charHeights[i]
  335. = (int)((b->getHeight() / (double)a->getSchriftSize())
  336. * schriftSize
  337. + 0.5);
  338. }
  339. else
  340. {
  341. charWidths[i] = 0;
  342. charHeights[i] = 0;
  343. }
  344. }
  345. }
  346. }
  347. }
  348. // Setzt den Zeilenabstand, der zum zeichnen verwendet werden soll
  349. // za: Der Zeilenabstand zum unteren Ende der darüber liegenden zeile in Pixeln
  350. void TextRenderer::setZeilenAbstand(int za)
  351. {
  352. zeilenAbstand = za;
  353. }
  354. // Setzt den Zeichenabstand, der zum zeichnen verwendet werden soll
  355. // za: Der Zeichenabstand zum unteren Ende der darüber liegenden zeile in
  356. // Pixeln
  357. void TextRenderer::setZeichenAbstand(int za)
  358. {
  359. zeichenAbstand = za;
  360. }
  361. // Fügt Zeilenumbrüche in den Text ein, so dass er bei einer vorgegebenen Breite
  362. // follständig angezeigt wird
  363. // zText: Der text, in den die Zeilenumbrüche eingefügt werden sollen
  364. // maxBreite: Die Breite in Pixeln auf der der Text follständig angezeigt
  365. // werden soll
  366. void TextRenderer::textFormatieren(Text* zTxt, int maxBreite)
  367. {
  368. int lastPos = -1;
  369. int x = 0;
  370. const char* txt = zTxt->getText();
  371. Text result = txt;
  372. int len = zTxt->getLength();
  373. for (int i = 0; i < len; ++i)
  374. {
  375. if (txt[i] == ' ')
  376. {
  377. lastPos = i;
  378. x += schriftSize / 2 + zeichenAbstand;
  379. continue;
  380. }
  381. if (txt[i] == '\t')
  382. {
  383. lastPos = i;
  384. x += schriftSize + zeichenAbstand;
  385. continue;
  386. }
  387. if (txt[i] == '\n')
  388. {
  389. x = 0;
  390. lastPos = -1;
  391. continue;
  392. }
  393. x += getCharWidth(txt[i]) + zeichenAbstand;
  394. if (x > maxBreite && lastPos > -1)
  395. {
  396. result.ersetzen(lastPos, lastPos + 1, "\n");
  397. x = 0;
  398. i = lastPos;
  399. lastPos = -1;
  400. }
  401. }
  402. zTxt->setText(result);
  403. }
  404. // Zeichnet einen Bestimmten Text mit Cursor und einfärbung auf ein Bild
  405. // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe
  406. // zu verändern
  407. // x: x position des ersten zeichens
  408. // y: y position des ersten zeichens
  409. // txt: Der Text, der gezeichnet werden soll
  410. // zRObj: Das Bild, auf das gezeichnet werden soll
  411. // cpos: Die position des Cursors im Text
  412. // cf: Die Farbe des Cursors
  413. // fbeg: Die Position des Zeichens im Text, wo die Einfärbung beginnen soll.
  414. // Der Text wird von dort bis zur Cursorposition eingefärbt ff: Die Hintergrund
  415. // Farbe des eingefärbten Textes f: Eine Funktion die für jeden Buchstaben
  416. // aufgerufen wird und seine Farbe zurückgibt
  417. void TextRenderer::renderText(int x,
  418. int y,
  419. const char* txt,
  420. Bild& zRObj,
  421. std::function<int(int, int, int)> f,
  422. int cpos,
  423. int cf,
  424. int fbeg,
  425. int ff)
  426. {
  427. if (!s) return;
  428. if (fbeg == -1) fbeg = cpos;
  429. int zRObjBr = zRObj.getBreite();
  430. int zRObjHi = zRObj.getHeight();
  431. const Punkt& zRObjOff = zRObj.getDrawOff();
  432. int beginX = x;
  433. int zh = getZeilenHeight();
  434. if (y + (zh + zeilenAbstand) * Text(txt).anzahlVon('\n') + zh + zRObjOff.y
  435. < 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.drawLinieVAlpha(x, y, zh, cf);
  446. faerb = !faerb;
  447. }
  448. if (txt[i] == ' ')
  449. {
  450. if (faerb)
  451. zRObj.alphaRegion(
  452. x, y, schriftSize / 2 + zeichenAbstand, zh, ff);
  453. x += schriftSize / 2 + zeichenAbstand;
  454. continue;
  455. }
  456. if (txt[i] == '\t')
  457. {
  458. if (faerb)
  459. zRObj.alphaRegion(x, y, schriftSize + zeichenAbstand, zh, ff);
  460. x += schriftSize + zeichenAbstand;
  461. continue;
  462. }
  463. if (txt[i] == '\n')
  464. {
  465. y += zh + zeilenAbstand;
  466. x = beginX;
  467. continue;
  468. }
  469. renderChar(x, y, txt[i], zRObj, f(x, y, i), 0, faerb, ff);
  470. }
  471. if (textLength(txt) == cpos) zRObj.drawLinieVAlpha(x, y, zh, cf);
  472. }
  473. // Zeichnet einen Bestimmten Text mit Cursor und einfärbung auf ein Bild
  474. // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe
  475. // zu verändern
  476. // x: x position des ersten zeichens
  477. // y: y position des ersten zeichens
  478. // txt: Der Text, der gezeichnet werden soll
  479. // zRObj: Das Bild, auf das gezeichnet werden soll
  480. // cpos: Die position des Cursors im Text
  481. // cf: Die Farbe des Cursors
  482. // fbeg: Die Position des Zeichens im Text, wo die Einfärbung beginnen soll.
  483. // Der Text wird von dort bis zur Cursorposition eingefärbt ff: Die Hintergrund
  484. // Farbe des eingefärbten Textes f: Die Farbe, in der der Text gezeichnet
  485. // werden soll
  486. void TextRenderer::renderText(int x,
  487. int y,
  488. const char* txt,
  489. Bild& zRObj,
  490. int f,
  491. int cpos,
  492. int cf,
  493. int fbeg,
  494. int ff)
  495. {
  496. return renderText(
  497. x,
  498. y,
  499. txt,
  500. zRObj,
  501. [f](int a, int b, int c) { return f; },
  502. cpos,
  503. cf,
  504. fbeg,
  505. ff);
  506. }
  507. // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild
  508. // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe
  509. // zu verändern
  510. // x: x position des ersten zeichens
  511. // y: y position des ersten zeichens
  512. // txt: Der Text, der gezeichnet werden soll
  513. // zRObj: Das Bild, auf das gezeichnet werden soll
  514. // color: Die Farbe, in der der Text gezeichnet werden soll
  515. // underlined: 1, falls der Text unterstrichen sein soll
  516. // selected: 1, falls das zeichen eingefärbt sein soll
  517. // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes
  518. void TextRenderer::renderChar(int& x,
  519. int y,
  520. char c,
  521. Bild& zRObj,
  522. int color,
  523. bool underlined,
  524. bool selected,
  525. int selectedBackgroundColor)
  526. {
  527. if (!s) return;
  528. Alphabet* a = s->zAlphabet((unsigned char)schriftSize);
  529. if (!a) return;
  530. Buchstabe* b = a->zBuchstabe(c);
  531. if (b)
  532. {
  533. if (x >= zRObj.getBreite()) return;
  534. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  535. {
  536. if (selected)
  537. {
  538. int br = getCharWidth(c) + zeichenAbstand;
  539. zRObj.alphaRegion(
  540. x, y, br, getZeilenHeight(), selectedBackgroundColor);
  541. }
  542. if (b->getBuff())
  543. {
  544. const Punkt& zRObjGr = zRObj.getDrawGr();
  545. const Punkt& zRObjPos = zRObj.getDrawPos();
  546. const Punkt& zRObjOff = zRObj.getDrawOff();
  547. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  548. int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  549. ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  550. int br = b->getBreite();
  551. unsigned char a2 = (unsigned char)(255 - (color >> 24));
  552. color &= 0x00FFFFFF;
  553. float xoff = (float)b->getSchriftSize() / (float)schriftSize,
  554. yoff = (float)b->getSchriftSize() / (float)schriftSize;
  555. float x = (float)xs * xoff, y = (float)ys * yoff;
  556. int maxX = getCharWidth(c), maxY = getCharHeight(c);
  557. maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX;
  558. maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY;
  559. int a, dx, ygr, ygr2;
  560. if (zRObj.hasAlpha3D())
  561. {
  562. for (int dy = ys; dy < maxY; ++dy)
  563. {
  564. ygr2 = (yp + dy) * zRObj.getBreite() + xp;
  565. ygr = (int)y * br;
  566. for (dx = xs; dx < maxX; ++dx)
  567. {
  568. a = b->getBuff()[(int)x + ygr] - a2;
  569. zRObj.alphaPixel3D(dx + ygr2, color | (a << 24));
  570. x += xoff;
  571. }
  572. x = (float)xs;
  573. y += yoff;
  574. }
  575. }
  576. else
  577. {
  578. for (int dy = ys; dy < maxY; ++dy)
  579. {
  580. ygr2 = (yp + dy) * zRObj.getBreite() + xp;
  581. ygr = (int)y * br;
  582. for (dx = xs; dx < maxX; ++dx)
  583. {
  584. a = b->getBuff()[(int)x + ygr] - a2;
  585. zRObj.alphaPixel2D(dx + ygr2, color | (a << 24));
  586. x += xoff;
  587. }
  588. x = (float)xs;
  589. y += yoff;
  590. }
  591. }
  592. }
  593. if (underlined)
  594. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  595. y + getZeilenHeight() + getZeichenAbstand() / 2,
  596. getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5),
  597. 0xFF000000 | color);
  598. }
  599. x += getCharWidth(c) + zeichenAbstand;
  600. }
  601. else if (c == ' ')
  602. {
  603. if (selected)
  604. zRObj.alphaRegion(x,
  605. y,
  606. schriftSize / 2 + zeichenAbstand,
  607. getZeilenHeight(),
  608. selectedBackgroundColor);
  609. if (underlined)
  610. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  611. y + getZeilenHeight() + getZeichenAbstand() / 2,
  612. schriftSize / 2 + zeichenAbstand
  613. + (int)(zeichenAbstand / 2.0 + 0.5),
  614. 0xFF000000 | color);
  615. x += schriftSize / 2 + zeichenAbstand;
  616. }
  617. else if (c == '\t')
  618. {
  619. if (selected)
  620. zRObj.alphaRegion(x,
  621. y,
  622. schriftSize + zeichenAbstand,
  623. getZeilenHeight(),
  624. selectedBackgroundColor);
  625. if (underlined)
  626. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  627. y + getZeilenHeight() + getZeichenAbstand() / 2,
  628. schriftSize + zeichenAbstand
  629. + (int)(zeichenAbstand / 2.0 + 0.5),
  630. 0xFF000000 | color);
  631. x += schriftSize + zeichenAbstand;
  632. }
  633. }
  634. // Gibt die Schriftgröße zurück, die zum Zeichnen verwendet wird
  635. int TextRenderer::getSchriftSize() const
  636. {
  637. return schriftSize;
  638. }
  639. // Gibt den Abstand in Pixeln zum unteren Ende der darüber ligenden Zeile zurück
  640. int TextRenderer::getZeilenabstand() const
  641. {
  642. return zeilenAbstand;
  643. }
  644. // Gibt den Abstand in Pixeln zum zwischen zwei zeichen auf der x Achse zurück
  645. int TextRenderer::getZeichenAbstand() const
  646. {
  647. return zeichenAbstand;
  648. }
  649. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text
  650. // vollständig darzustellen
  651. // txt: Der Text, von dem die Breite in Pixeln ermitelt werden soll
  652. int TextRenderer::getTextBreite(const char* txt) const
  653. {
  654. int ret = 0;
  655. int tmp = 0;
  656. int len = textLength(txt);
  657. for (int i = 0; i < len; ++i)
  658. {
  659. if (txt[i] == '\n')
  660. {
  661. if (tmp > ret) ret = tmp;
  662. tmp = 0;
  663. }
  664. else if (txt[i] == '\t')
  665. tmp += schriftSize + zeichenAbstand;
  666. else if (txt[i] == ' ')
  667. tmp += schriftSize / 2 + zeichenAbstand;
  668. else
  669. tmp += getCharWidth(txt[i]) + zeichenAbstand;
  670. }
  671. if (tmp > ret) ret = tmp;
  672. return ret;
  673. }
  674. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text
  675. // vollständig darzustellen
  676. // txt: Der Text, von dem die Höhe in Pixeln ermitelt werden soll
  677. int TextRenderer::getTextHeight(const char* txt) const
  678. {
  679. int hi = getZeilenHeight();
  680. return hi + ((hi + zeilenAbstand) * Text(txt).anzahlVon('\n'));
  681. }
  682. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben
  683. // vollständig darzustellen
  684. // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll
  685. int TextRenderer::getCharWidth(const char c) const
  686. {
  687. return charWidths[(unsigned char)c];
  688. }
  689. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text
  690. // vollständig darzustellen
  691. // c: Der Buchstabe, von dem die Höhe in Pixeln ermitelt werden soll
  692. int TextRenderer::getCharHeight(const char c) const
  693. {
  694. return charHeights[(unsigned char)c];
  695. }
  696. // Gibt den Abstand in Pixeln zum unteren Ende der darüber ligenden Zeile zurück
  697. int TextRenderer::getZeilenAbstand() const
  698. {
  699. return zeilenAbstand;
  700. }
  701. // Gibt die skallierte Höhe zurück, die eine gezeichnete Zeile in Pixeln
  702. // benötigt
  703. int TextRenderer::getZeilenHeight() const
  704. {
  705. int zh = 0;
  706. for (int i = 0; i < 256; ++i)
  707. {
  708. zh = maxInt(getCharHeight((char)i), zh);
  709. }
  710. return zh;
  711. }
  712. // Ermittelt das Zeichen im Text, auf das die Maus zeigt
  713. // txt: Der Text, auf den die Maus Zeigt
  714. // mausX: Die X Position der Maus in Pixeln Relativ zur Position des ersten
  715. // Zeichens mausY: Die Y Position der Maus in Pixeln Relativ zur Position des
  716. // ersten Zeichens
  717. int TextRenderer::textPos(const char* txt, int mausX, int mausY) const
  718. {
  719. int tx = 0;
  720. int ty = 0;
  721. int sh = getZeilenHeight();
  722. if (mausX < 0 || mausY < 0) return -1;
  723. int len = textLength(txt);
  724. for (int i = 0; i < len; ++i)
  725. {
  726. if (txt[i] == '\n')
  727. {
  728. ty += sh + zeilenAbstand;
  729. tx = 0;
  730. if (mausY < ty) return i;
  731. }
  732. if (txt[i] == '\t') tx += schriftSize + zeichenAbstand;
  733. if (txt[i] == ' ') tx += schriftSize / 2 + zeichenAbstand;
  734. tx += getCharWidth(txt[i]);
  735. int txpl = getCharWidth(txt[i + 1]) / 2;
  736. if (mausX < tx - txpl && mausY < ty + sh + zeilenAbstand) return i;
  737. }
  738. if (mausY < ty + sh + zeilenAbstand) return textLength(txt);
  739. return -1;
  740. }
  741. GravurTextRenderer::GravurTextRenderer()
  742. : GravurTextRenderer(0)
  743. {}
  744. GravurTextRenderer::GravurTextRenderer(Schrift* schrift)
  745. : TextRenderer(schrift)
  746. {}
  747. GravurTextRenderer::~GravurTextRenderer() {}
  748. // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild
  749. // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe
  750. // zu verändern
  751. // x: x position des ersten zeichens
  752. // y: y position des ersten zeichens
  753. // txt: Der Text, der gezeichnet werden soll
  754. // zRObj: Das Bild, auf das gezeichnet werden soll
  755. // color: Die Farbe, in der der Text gezeichnet werden soll
  756. // underlined: 1, falls der Text unterstrichen sein soll
  757. // selected: 1, falls das zeichen eingefärbt sein soll
  758. // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes
  759. void GravurTextRenderer::renderChar(int& x,
  760. int y,
  761. char c,
  762. Bild& zRObj,
  763. int color,
  764. bool underlined,
  765. bool selected,
  766. int selectedBackgroundColor)
  767. {
  768. if (!s) return;
  769. Alphabet* a = s->zAlphabet((unsigned char)schriftSize);
  770. Buchstabe* b = a->zBuchstabe(c);
  771. if (b)
  772. {
  773. if (x >= zRObj.getBreite()) return;
  774. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  775. {
  776. if (selected)
  777. {
  778. int br = getCharWidth(c) + zeichenAbstand;
  779. zRObj.alphaRegion(
  780. x, y, br, getZeilenHeight(), selectedBackgroundColor);
  781. }
  782. if (b->getBuff())
  783. {
  784. const Punkt& zRObjGr = zRObj.getDrawGr();
  785. const Punkt& zRObjPos = zRObj.getDrawPos();
  786. const Punkt& zRObjOff = zRObj.getDrawOff();
  787. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  788. int xs = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  789. ys = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  790. int br = b->getBreite(), h = b->getHeight();
  791. color &= 0x00FFFFFF;
  792. double xoff = (double)b->getSchriftSize() / (schriftSize * 2.0),
  793. yoff = (double)b->getSchriftSize() / (schriftSize * 2.0);
  794. double x = xs * xoff, y = ys * yoff;
  795. int maxX = getCharWidth(c), maxY = getCharHeight(c);
  796. maxX = (xp + maxX) >= zRObjGr.x ? (zRObjGr.x - xp) : maxX;
  797. maxY = (yp + maxY) >= zRObjGr.y ? (zRObjGr.y - yp) : maxY;
  798. int dx, ygr, ygr2;
  799. if (zRObj.hasAlpha3D())
  800. {
  801. for (int dy = ys; dy < maxY; ++dy)
  802. {
  803. ygr2 = (yp + dy) * zRObj.getBreite();
  804. ygr = (int)y * br;
  805. for (dx = xs; dx < maxX; ++dx)
  806. {
  807. int f = 0;
  808. if (b->getBuff()[(int)x + ygr])
  809. f = 0x50000000;
  810. else if (((int)(x + xoff) < br
  811. && b->getBuff()[(int)(x + xoff) + ygr])
  812. || ((int)(y - yoff) < h
  813. && b->getBuff()[(int)x
  814. + (int)(y - yoff) * br]
  815. > 0xF0))
  816. f = 0xA0000000;
  817. else if (((int)(x - xoff) < br
  818. && b->getBuff()[(int)(x - xoff) + ygr])
  819. || ((int)(y + yoff) < h
  820. && b->getBuff()[(int)x
  821. + (int)(y + yoff) * br]
  822. > 0xF0))
  823. {
  824. f = 0xA0FFFFFF;
  825. }
  826. zRObj.alphaPixel3D(xp + dx + ygr2, f);
  827. x += xoff;
  828. }
  829. x = xs;
  830. y += yoff;
  831. }
  832. }
  833. else
  834. {
  835. for (int dy = ys; dy < maxY; ++dy)
  836. {
  837. ygr2 = (yp + dy) * zRObj.getBreite();
  838. ygr = (int)y * br;
  839. for (dx = xs; dx < maxX; ++dx)
  840. {
  841. int f = 0;
  842. if (b->getBuff()[(int)x + ygr])
  843. f = 0x50000000;
  844. else if (((int)(x + xoff) < br
  845. && b->getBuff()[(int)(x + xoff) + ygr])
  846. || ((int)(y - yoff) < h
  847. && b->getBuff()[(int)x
  848. + (int)(y - yoff) * br]
  849. > 0xF0))
  850. f = 0xA0000000;
  851. else if (((int)(x - xoff) < br
  852. && b->getBuff()[(int)(x - xoff) + ygr])
  853. || ((int)(y + yoff) < h
  854. && b->getBuff()[(int)x
  855. + (int)(y + yoff) * br]
  856. > 0xF0))
  857. {
  858. f = 0xA0FFFFFF;
  859. }
  860. zRObj.alphaPixel2D(xp + dx + ygr2, f);
  861. x += xoff;
  862. }
  863. x = xs;
  864. y += yoff;
  865. }
  866. }
  867. }
  868. if (underlined)
  869. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  870. y + getZeilenHeight() + getZeichenAbstand() / 2,
  871. getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5),
  872. 0xFF000000 | color);
  873. }
  874. x += getCharWidth(c) + zeichenAbstand;
  875. }
  876. else if (c == ' ')
  877. {
  878. if (selected)
  879. zRObj.alphaRegion(x,
  880. y,
  881. schriftSize / 2 + zeichenAbstand,
  882. getZeilenHeight(),
  883. selectedBackgroundColor);
  884. if (underlined)
  885. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  886. y + getZeilenHeight() + getZeichenAbstand() / 2,
  887. schriftSize / 2 + zeichenAbstand
  888. + (int)(zeichenAbstand / 2.0 + 0.5),
  889. 0xFF000000 | color);
  890. x += schriftSize / 2 + zeichenAbstand;
  891. }
  892. else if (c == '\t')
  893. {
  894. if (selected)
  895. zRObj.alphaRegion(x,
  896. y,
  897. schriftSize + zeichenAbstand,
  898. getZeilenHeight(),
  899. selectedBackgroundColor);
  900. if (underlined)
  901. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  902. y + getZeilenHeight() + getZeichenAbstand() / 2,
  903. schriftSize + zeichenAbstand
  904. + (int)(zeichenAbstand / 2.0 + 0.5),
  905. 0xFF000000 | color);
  906. x += schriftSize + zeichenAbstand;
  907. }
  908. }
  909. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben
  910. // vollständig darzustellen
  911. // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll
  912. int GravurTextRenderer::getCharWidth(const char c) const
  913. {
  914. return TextRenderer::getCharWidth(c) * 2;
  915. }
  916. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Text
  917. // vollständig darzustellen
  918. // c: Der Buchstabe, von dem die Höhe in Pixeln ermitelt werden soll
  919. int GravurTextRenderer::getCharHeight(const char c) const
  920. {
  921. return TextRenderer::getCharHeight(c) * 2;
  922. }
  923. KursivTextRenderer::KursivTextRenderer()
  924. : KursivTextRenderer(0)
  925. {}
  926. KursivTextRenderer::KursivTextRenderer(Schrift* schrift)
  927. : TextRenderer(schrift)
  928. {}
  929. KursivTextRenderer::~KursivTextRenderer() {}
  930. // Zeichnet einen Bestimmten Buchstaben mit einfärbung auf ein Bild
  931. // Nutze (setPosition) und (setDrawSchriftGröße) um die Position und die Größe
  932. // zu verändern
  933. // x: x position des ersten zeichens
  934. // y: y position des ersten zeichens
  935. // txt: Der Text, der gezeichnet werden soll
  936. // zRObj: Das Bild, auf das gezeichnet werden soll
  937. // color: Die Farbe, in der der Text gezeichnet werden soll
  938. // underlined: 1, falls der Text unterstrichen sein soll
  939. // selected: 1, falls das zeichen eingefärbt sein soll
  940. // selectedBackgroundColor: Die Hintergrund Farbe des eingefärbten Textes
  941. void KursivTextRenderer::renderChar(int& x,
  942. int y,
  943. char c,
  944. Bild& zRObj,
  945. int color,
  946. bool underlined,
  947. bool selected,
  948. int selectedBackgroundColor)
  949. {
  950. if (!s) return;
  951. Alphabet* a = s->zAlphabet((unsigned char)schriftSize);
  952. if (!a) return;
  953. Buchstabe* b = a->zBuchstabe(c);
  954. if (b)
  955. {
  956. if (x >= zRObj.getBreite()) return;
  957. if (zRObj.isAreaDrawable(x, y, getCharWidth(c), getCharHeight(c)))
  958. {
  959. if (selected)
  960. {
  961. int br = getCharWidth(c) + zeichenAbstand;
  962. zRObj.alphaRegion(
  963. x, y, br, getZeilenHeight(), selectedBackgroundColor);
  964. }
  965. if (b->getBuff())
  966. {
  967. const Punkt& zRObjGr = zRObj.getDrawGr();
  968. const Punkt& zRObjPos = zRObj.getDrawPos();
  969. const Punkt& zRObjOff = zRObj.getDrawOff();
  970. int xp = x + zRObjOff.x, yp = y + zRObjOff.y;
  971. int xStartBuffer = xp < zRObjPos.x ? (zRObjPos.x - xp) : 0,
  972. yStartBuffer = yp < zRObjPos.y ? (zRObjPos.y - yp) : 0;
  973. int bufferBreite = b->getBreite(),
  974. bufferHeight = b->getHeight();
  975. unsigned char colorAlpha = (unsigned char)(255 - (color >> 24));
  976. color &= 0x00FFFFFF;
  977. double xStepBuffer
  978. = (double)b->getSchriftSize() / (double)schriftSize,
  979. yStepBuffer
  980. = (double)b->getSchriftSize() / (double)schriftSize;
  981. double xBuffer = xStartBuffer * xStepBuffer,
  982. yBuffer = yStartBuffer * yStepBuffer;
  983. int charHeight = getCharHeight(c);
  984. int maxXBuffer = getCharWidth(c), maxYBuffer = charHeight;
  985. maxXBuffer = (xp + maxXBuffer) >= zRObjGr.x ? (zRObjGr.x - xp)
  986. : maxXBuffer;
  987. maxYBuffer = (yp + maxYBuffer) >= zRObjGr.y ? (zRObjGr.y - yp)
  988. : maxYBuffer;
  989. std::function<int(int x, int y)> colorF = [charHeight,
  990. bufferBreite,
  991. bufferHeight,
  992. colorAlpha,
  993. b,
  994. color](
  995. int xx, int yy) {
  996. xx -= (int)((float)(charHeight - yy) / 4.f + 0.5f);
  997. if (xx < 0 || xx >= bufferBreite) return 0x00FFFFFF;
  998. int a = b->getBuff()[yy * bufferBreite + xx] - colorAlpha;
  999. return color | (a << 24);
  1000. };
  1001. if (zRObj.hasAlpha3D())
  1002. {
  1003. for (int yS = yStartBuffer; yS < maxYBuffer; ++yS)
  1004. {
  1005. int ygr2 = (yp + yS) * zRObj.getBreite();
  1006. for (int xS = xStartBuffer; xS < maxXBuffer; ++xS)
  1007. {
  1008. zRObj.alphaPixel3D(
  1009. xp + xS + ygr2, colorF((int)xS, (int)yS));
  1010. xBuffer += xStepBuffer;
  1011. }
  1012. xBuffer = xStartBuffer;
  1013. yBuffer += yStepBuffer;
  1014. }
  1015. }
  1016. else
  1017. {
  1018. for (int yS = yStartBuffer; yS < maxYBuffer; ++yS)
  1019. {
  1020. int ygr2 = (yp + yS) * zRObj.getBreite();
  1021. for (int xS = xStartBuffer; xS < maxXBuffer; ++xS)
  1022. {
  1023. zRObj.alphaPixel2D(
  1024. xp + xS + ygr2, colorF((int)xS, (int)yS));
  1025. xBuffer += xStepBuffer;
  1026. }
  1027. xBuffer = xStartBuffer;
  1028. yBuffer += yStepBuffer;
  1029. }
  1030. }
  1031. }
  1032. if (underlined)
  1033. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  1034. y + getZeilenHeight() + getZeichenAbstand() / 2,
  1035. getCharWidth(c) + (int)(zeichenAbstand / 2.0 + 0.5),
  1036. 0xFF000000 | color);
  1037. }
  1038. x += getCharWidth(c) + zeichenAbstand;
  1039. }
  1040. else if (c == ' ')
  1041. {
  1042. if (selected)
  1043. zRObj.alphaRegion(x,
  1044. y,
  1045. schriftSize / 2 + zeichenAbstand,
  1046. getZeilenHeight(),
  1047. selectedBackgroundColor);
  1048. if (underlined)
  1049. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  1050. y + getZeilenHeight() + getZeichenAbstand() / 2,
  1051. schriftSize / 2 + zeichenAbstand
  1052. + (int)(zeichenAbstand / 2.0 + 0.5),
  1053. 0xFF000000 | color);
  1054. x += schriftSize / 2 + zeichenAbstand;
  1055. }
  1056. else if (c == '\t')
  1057. {
  1058. if (selected)
  1059. zRObj.alphaRegion(x,
  1060. y,
  1061. schriftSize + zeichenAbstand,
  1062. getZeilenHeight(),
  1063. selectedBackgroundColor);
  1064. if (underlined)
  1065. zRObj.drawLinieHAlpha(x - (int)(zeichenAbstand / 2.0 + 0.5),
  1066. y + getZeilenHeight() + getZeichenAbstand() / 2,
  1067. schriftSize + zeichenAbstand
  1068. + (int)(zeichenAbstand / 2.0 + 0.5),
  1069. 0xFF000000 | color);
  1070. x += schriftSize + zeichenAbstand;
  1071. }
  1072. }
  1073. // Ermittelt, wie viele Pixel benötigt werden, um einen Bestimmten Buchstaben
  1074. // vollständig darzustellen
  1075. // c: Der Buchstabe, von dem die Breite in Pixeln ermitelt werden soll
  1076. int KursivTextRenderer::getCharWidth(const char c) const
  1077. {
  1078. return (int)(TextRenderer::getCharWidth(c) + getCharHeight(c) / 4.0 + 0.5);
  1079. }