text.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. * FbLib graphic library
  3. *
  4. * Created by Manoël TRAPIER.
  5. * Copyright (c) 2003-2019 986-Studio. All rights reserved.
  6. *
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #include <stdarg.h>
  13. #include <os_dependent.h>
  14. #define DEFAULT_FONT "default_font.psf"
  15. FBLibFont *defaultFont = NULL;
  16. /* Function will fail, if no string terminator */
  17. static int getNextWordLen(char *str)
  18. {
  19. int ret = 0, i;
  20. /* Word delimiters */
  21. char word_lim[] = { ' ', '\t', '\n', 0 };
  22. while (1)
  23. {
  24. for (i = 0 ; word_lim[i] != 0 ; i++)
  25. {
  26. if (*str == word_lim[i])
  27. {
  28. return ret;
  29. }
  30. }
  31. str++;
  32. ret++;
  33. }
  34. }
  35. void graphics_text_line(int x, int y, int w, int charw, uint32_t color, int valign, void *font, char *text)
  36. {
  37. uint32_t len = strlen(text);
  38. switch (valign)
  39. {
  40. default:
  41. case TEXT_VALIGN_LEFT:
  42. graphics_draw_text(x, y, color, (const FBLibFont *)font, text);
  43. break;
  44. case TEXT_VALIGN_CENTER:
  45. graphics_draw_text(x + ((w - len * charw) / 2), y, color, (const FBLibFont *)font, text);
  46. break;
  47. case TEXT_VALIGN_RIGHT:
  48. graphics_draw_text(x + (w - (len * charw)), y, color, (const FBLibFont *)font, text);
  49. break;
  50. }
  51. }
  52. /* Currently halign is not honored, but valign is */
  53. int graphics_text_ex(int x, int y, int w, int h,
  54. void *font,
  55. uint32_t bgcolor, uint32_t fgcolor,
  56. char valign, char halign,
  57. uint16_t options,
  58. void *format, ...)
  59. {
  60. char string[1024];
  61. char line[300];
  62. int charWidth, charHeight;
  63. int textPos = 0;
  64. int wordLen = 0;
  65. int nextWordLen = 0;
  66. va_list va;
  67. uint16_t curColPos = 0, curLinePos = 0;
  68. uint16_t maxCharPerLine, maxTextLine;
  69. FBLibFont *userFont = font;
  70. if (defaultFont == NULL)
  71. {
  72. defaultFont = load_psf(DEFAULT_FONT);
  73. }
  74. if (font == NULL)
  75. {
  76. userFont = defaultFont;
  77. }
  78. /* Do some usefull calculation */
  79. /* We use fixed size font */
  80. graphics_get_text_size(&charWidth, &charHeight, userFont, "A");
  81. maxCharPerLine = w / charWidth;
  82. maxTextLine = h / charHeight;
  83. /* Now convert to a useable string */
  84. va_start(va, format);
  85. vsnprintf(string, 1024, format, va);
  86. va_end(va);
  87. /* Fill rect with bg color */
  88. graphics_drawFillrect(x, y, w, h, bgcolor);
  89. /* Now fill as much as possible */
  90. memset(line, 0, 300);
  91. while (curLinePos < maxTextLine)
  92. {
  93. if (options & TEXT_OPT_WORDWRAP)
  94. {
  95. /* Do thoses check only one time per word, not per characters */
  96. if (wordLen <= 0)
  97. {
  98. /* check if next word is too large for width */
  99. nextWordLen = getNextWordLen(&string[textPos]);
  100. //printf("\nNextword len = %d", nextWordLen);
  101. if (nextWordLen <= maxCharPerLine)
  102. {
  103. if ((curColPos + nextWordLen) > maxCharPerLine)
  104. {
  105. /* Go next line... */
  106. line[curColPos] = 0;
  107. graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont,
  108. line);
  109. curColPos = 0;
  110. curLinePos++;
  111. memset(line, 0, 300);
  112. }
  113. }
  114. wordLen = nextWordLen;
  115. }
  116. /* Now when the word is too long for a line, it will be automatically wrapped to the next line */
  117. }
  118. if ((string[textPos] == '\n') || (string[textPos] == '\r'))
  119. {
  120. textPos++;
  121. line[curColPos] = 0;
  122. graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
  123. curColPos = 0;
  124. curLinePos++;
  125. memset(line, 0, 300);
  126. }
  127. else if (string[textPos] == 0)
  128. {
  129. line[curColPos] = 0;
  130. graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
  131. goto exit;
  132. }
  133. else if (curColPos >= maxCharPerLine)
  134. {
  135. /* display the line */
  136. line[curColPos] = 0;
  137. graphics_text_line(x, y + curLinePos * charHeight, w, charWidth, fgcolor, valign, userFont, line);
  138. /* skip until a "\n" (and exit is "\0" found)) */
  139. if (options & TEXT_OPT_WORDWRAP)
  140. {
  141. curColPos = 0;
  142. curLinePos++;
  143. memset(line, 0, 300);
  144. }
  145. else
  146. {
  147. while (1)
  148. {
  149. if ((string[textPos] == '\r') || (string[textPos] == '\n'))
  150. {
  151. curColPos = 0;
  152. curLinePos++;
  153. memset(line, 0, 300);
  154. break;
  155. }
  156. else if (string[textPos] == 0)
  157. {
  158. goto exit;
  159. }
  160. textPos++;
  161. }
  162. }
  163. }
  164. else
  165. {
  166. line[curColPos++] = string[textPos++];
  167. }
  168. if (options & TEXT_OPT_WORDWRAP)
  169. {
  170. wordLen--;
  171. }
  172. }
  173. exit:
  174. return 0;
  175. }
  176. void *fblib_loadfont(char *filename)
  177. {
  178. return (void *)load_psf(filename);
  179. }
  180. /* PSF management */
  181. #define PSF1_MAGIC0 0x36
  182. #define PSF1_MAGIC1 0x04
  183. #define PSF1_MODE512 0x01
  184. #define PSF1_MODEHASTAB 0x02
  185. #define PSF1_MODEHASSEQ 0x04
  186. #define PSF1_MAXMODE 0x05
  187. #define PSF1_SEPARATOR 0xFFFF
  188. #define PSF1_STARTSEQ 0xFFFE
  189. struct psf1_header
  190. {
  191. unsigned char magic[2]; /* Magic number */
  192. unsigned char mode; /* PSF font mode */
  193. unsigned char charsize; /* Character size */
  194. };
  195. #define PSF2_MAGIC0 0x72
  196. #define PSF2_MAGIC1 0xb5
  197. #define PSF2_MAGIC2 0x4a
  198. #define PSF2_MAGIC3 0x86
  199. /* bits used in flags */
  200. #define PSF2_HAS_UNICODE_TABLE 0x01
  201. /* max version recognized so far */
  202. #define PSF2_MAXVERSION 0
  203. /* UTF8 separators */
  204. #define PSF2_SEPARATOR 0xFF
  205. #define PSF2_STARTSEQ 0xFE
  206. struct psf2_header
  207. {
  208. unsigned char magic[4];
  209. unsigned int version;
  210. unsigned int headersize; /* offset of bitmaps in file */
  211. unsigned int flags;
  212. unsigned int length; /* number of glyphs */
  213. unsigned int charsize; /* number of bytes for each character */
  214. unsigned int height, width; /* max dimensions of glyphs */
  215. /* charsize = height * ((width + 7) / 8) */
  216. };
  217. static FBLibFont *load_psf1(char *filename, FILE *fp)
  218. {
  219. struct psf1_header head;
  220. struct FBLibFont *font;
  221. fread(&head, sizeof(head), 1, fp);
  222. if ((head.magic[0] != PSF1_MAGIC0) || (head.magic[1] != PSF1_MAGIC1))
  223. {
  224. return NULL;
  225. }
  226. font = (FBLibFont *)malloc(sizeof(FBLibFont));
  227. if (font != NULL)
  228. {
  229. font->height = head.charsize;
  230. font->index_mask = 0xFF;
  231. }
  232. return NULL;
  233. }
  234. void printbin(uint32_t val, uint8_t bitlen)
  235. {
  236. int i;
  237. for (i = 0 ; i < bitlen ; i++)
  238. {
  239. if (val & (1 << (bitlen - 1)))
  240. {
  241. printf("*");
  242. }
  243. else
  244. {
  245. printf("_");
  246. }
  247. val <<= 1;
  248. }
  249. }
  250. static FBLibFont *load_psf2(char *filename, FILE *fp)
  251. {
  252. struct psf2_header head;
  253. struct FBLibFont *font, *ret = NULL;
  254. uint32_t charWidth;
  255. uint32_t i, j, k;
  256. uint8_t *bitmap;
  257. fread(&head, sizeof(head), 1, fp);
  258. if ((head.magic[0] != PSF2_MAGIC0) || (head.magic[1] != PSF2_MAGIC1) ||
  259. (head.magic[2] != PSF2_MAGIC2) || (head.magic[3] != PSF2_MAGIC3)
  260. )
  261. {
  262. goto exit;
  263. }
  264. font = (FBLibFont *)malloc(sizeof(FBLibFont));
  265. assert(head.width <= 32); /* For now, do not support font with width larger than 32 pixels */
  266. if (font != NULL)
  267. {
  268. font->height = head.height;
  269. bitmap = (uint8_t *)malloc(sizeof(uint8_t) * head.charsize * head.length);
  270. font->index_mask = 0xFF;
  271. font->offset = (int *)malloc(sizeof(int) * head.length);
  272. font->index = (int *)malloc(sizeof(int) * head.length * 3);
  273. font->content = (uint32_t *)malloc(sizeof(uint32_t) * head.length * head.height);
  274. charWidth = ((head.width + 7) / 8);
  275. assert(bitmap != NULL);
  276. assert(font->offset != NULL);
  277. assert(font->index != NULL);
  278. assert(font->content != NULL);
  279. fread(bitmap, sizeof(uint8_t), head.charsize * head.length, fp);
  280. for (i = 0 ; i < head.length ; i++)
  281. {
  282. font->offset[i] = i * 3;
  283. font->index[(i * 3) + 0] = head.width;
  284. font->index[(i * 3) + 1] = i * head.height;
  285. font->index[(i * 3) + 2] = 0;
  286. for (j = 0 ; j < head.height ; j++)
  287. {
  288. font->content[(i * head.height) + j] = 0;
  289. for (k = 0 ; k < charWidth ; k++)
  290. {
  291. font->content[(i * head.height) + j] |=
  292. (bitmap[(i * head.charsize) + (j * charWidth) + k]) << 8 * (3 - k);
  293. }
  294. }
  295. }
  296. ret = font;
  297. free(bitmap);
  298. }
  299. exit:
  300. fclose(fp);
  301. return ret;
  302. }
  303. FBLibFont *load_psf(char *filename)
  304. {
  305. FILE *fp;
  306. uint8_t byte;
  307. console_printf(Console_Default, "Loading font '%s'\n", filename);
  308. fp = fopen(filename, "rb");
  309. if (fp != NULL)
  310. {
  311. byte = fgetc(fp);
  312. rewind(fp);
  313. switch (byte)
  314. {
  315. default:
  316. fclose(fp);
  317. return NULL; // Unsuported format
  318. case PSF1_MAGIC0:
  319. return load_psf1(filename, fp);
  320. case PSF2_MAGIC0:
  321. return load_psf2(filename, fp);
  322. }
  323. }
  324. return NULL;
  325. }
  326. /* Font rendering code based on BOGL by Ben Pfaff */
  327. static int fblib_draw_glyph(const FBLibFont *font, uint8_t wc, uint32_t **bitmap)
  328. {
  329. int mask = font->index_mask;
  330. int i;
  331. for (;;)
  332. {
  333. for (i = font->offset[wc & mask] ; font->index[i] ; i += 3)
  334. {
  335. if ((font->index[i] & ~mask) == (wc & ~mask))
  336. {
  337. if (bitmap != NULL)
  338. {
  339. *bitmap = &font->content[font->index[i + 1]];
  340. }
  341. return font->index[i] & mask;
  342. }
  343. }
  344. }
  345. return 0;
  346. }
  347. void graphics_get_text_size(int *width, int *height,
  348. const FBLibFont *font,
  349. const char *text)
  350. {
  351. uint8_t *c = (uint8_t *)text;
  352. uint8_t wc;
  353. int k, n, w, h, mw;
  354. if (defaultFont == NULL)
  355. {
  356. defaultFont = load_psf(DEFAULT_FONT);
  357. }
  358. if (font == NULL)
  359. {
  360. font = defaultFont;
  361. }
  362. n = strlen(text);
  363. mw = h = w = 0;
  364. for (k = 0 ; k < n ; k++)
  365. {
  366. wc = *(c++);
  367. if (wc == '\n')
  368. {
  369. if (w > mw)
  370. {
  371. mw = 0;
  372. }
  373. h += font->height;
  374. continue;
  375. }
  376. w += fblib_draw_glyph(font, wc, NULL);
  377. }
  378. if (width != NULL)
  379. {
  380. *width = (w > mw) ? w : mw;
  381. }
  382. if (height != NULL)
  383. {
  384. *height = (h == 0) ? font->height : h;
  385. }
  386. }
  387. void graphics_draw_text(int x, int y,
  388. uint32_t colour,
  389. const FBLibFont *font,
  390. const char *text)
  391. {
  392. int32_t h, w, k, n, cx, cy, dx, dy;
  393. uint8_t *c = (uint8_t *)text;
  394. uint8_t wc;
  395. if (defaultFont == NULL)
  396. {
  397. defaultFont = load_psf(DEFAULT_FONT);
  398. }
  399. if (font == NULL)
  400. {
  401. font = defaultFont;
  402. }
  403. n = strlen(text);
  404. h = font->height;
  405. dx = dy = 0;
  406. for (k = 0 ; k < n ; k++)
  407. {
  408. uint32_t *glyph = NULL;
  409. wc = *(c++);
  410. if (wc == '\n')
  411. {
  412. dy += h;
  413. dx = 0;
  414. continue;
  415. }
  416. w = fblib_draw_glyph(font, wc, &glyph);
  417. if (glyph == NULL)
  418. {
  419. continue;
  420. }
  421. for (cy = 0 ; cy < h ; cy++)
  422. {
  423. uint32_t g = *glyph++;
  424. for (cx = 0 ; cx < w ; cx++)
  425. {
  426. if (g & 0x80000000)
  427. {
  428. graphics_drawpixel(x + dx + cx, y + dy + cy, colour);
  429. }
  430. g <<= 1;
  431. }
  432. }
  433. dx += w;
  434. }
  435. }
  436. /* End of PSF */