bdf_tga.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. bdf_tga.c
  3. Modes:
  4. BDF_BBX_MODE_MINIMAL 0
  5. BDF_BBX_MODE_MAX 1
  6. BDF_BBX_MODE_HEIGHT 2
  7. For all modes, default reference should be the baseline.
  8. This is required for mode 0, but may be optional for 1 and 2
  9. If (x,y) is the user provided baseline point for the glyph, then
  10. the decoding mus tbe start at
  11. (x..., y-h-descent)
  12. BDF_BBX_MODE_MINIMAL
  13. - exact space as intended by the font author
  14. - glyphs my overlap ("mj" with osb18)
  15. BDF_BBX_MODE_MAX
  16. - extra space may be added
  17. - glyphs do not overlap
  18. BDF_BBX_MODE_HEIGHT
  19. - extra space may be added
  20. - glyphs do not overlap
  21. */
  22. #include <stdint.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <assert.h>
  27. #include "fd.h"
  28. static uint16_t tga_width;
  29. static uint16_t tga_height;
  30. static uint16_t tga_used_height;
  31. static uint8_t *tga_data = NULL;
  32. static uint8_t *tga_font;
  33. static int glyph_cnt;
  34. static int bits_per_0;
  35. static int bits_per_1;
  36. static int bits_per_char_width;
  37. static int bits_per_char_height;
  38. static int bits_per_char_x;
  39. static int bits_per_char_y;
  40. static int bits_per_delta_x;
  41. static int char_width;
  42. static int char_height;
  43. static int char_descent;
  44. static unsigned unicode_start_pos;
  45. static int tga_pixel_intersection;
  46. int tga_get_char_width(void)
  47. {
  48. return char_width;
  49. }
  50. int tga_get_char_height(void)
  51. {
  52. return char_height;
  53. }
  54. int tga_init(uint16_t w, uint16_t h)
  55. {
  56. tga_width = 0;
  57. tga_height = 0;
  58. tga_used_height = 0;
  59. tga_pixel_intersection = 0;
  60. if ( tga_data != NULL )
  61. free(tga_data);
  62. tga_data = (uint8_t *)malloc((size_t)w*(size_t)h*3);
  63. if ( tga_data == NULL )
  64. return 0;
  65. tga_width = w;
  66. tga_height = h;
  67. memset(tga_data, 255, tga_width*tga_height*3);
  68. return 1;
  69. }
  70. void tga_clear(void)
  71. {
  72. memset(tga_data, 255, tga_width*tga_height*3);
  73. }
  74. void tga_set_pixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
  75. {
  76. uint8_t *p;
  77. if ( y>= tga_height)
  78. return;
  79. if ( x>= tga_width)
  80. return;
  81. if ( tga_used_height < y )
  82. tga_used_height = y;
  83. p = tga_data + (tga_height-y-1)*(size_t)tga_width*3 + (size_t)x*3;
  84. if ( p[0] != 255 || p[1] != 255 || p[2] != 255 )
  85. tga_pixel_intersection = 1;
  86. //printf("tga_set_pixel %d %d\n", x, y);
  87. *p++ = b;
  88. *p++ = g;
  89. *p++ = r;
  90. }
  91. int tga_is_pixel_intersection(void)
  92. {
  93. return tga_pixel_intersection;
  94. }
  95. void tga_clear_pixel_intersection(void)
  96. {
  97. tga_pixel_intersection = 0;
  98. }
  99. void tga_write_byte(FILE *fp, uint8_t byte)
  100. {
  101. fputc(byte, fp);
  102. }
  103. void tga_write_word(FILE *fp, uint16_t word)
  104. {
  105. tga_write_byte(fp, word&255);
  106. tga_write_byte(fp, word>>8);
  107. }
  108. void tga_save(const char *name)
  109. {
  110. FILE *fp;
  111. fp = fopen(name, "wb");
  112. if ( fp != NULL )
  113. {
  114. tga_write_byte(fp, 0); /* no ID */
  115. tga_write_byte(fp, 0); /* no color map */
  116. tga_write_byte(fp, 2); /* uncompressed true color */
  117. tga_write_word(fp, 0);
  118. tga_write_word(fp, 0);
  119. tga_write_byte(fp, 0);
  120. tga_write_word(fp, 0); /* x origin */
  121. tga_write_word(fp, 0); /* y origin */
  122. tga_write_word(fp, tga_width); /* width */
  123. tga_write_word(fp, tga_used_height+1); /* height */
  124. tga_write_byte(fp, 24); /* color depth */
  125. tga_write_byte(fp, 0);
  126. fwrite(tga_data + (tga_height - (tga_used_height+1))*tga_width*3 , tga_width*3, tga_used_height+1, fp);
  127. tga_write_word(fp, 0);
  128. tga_write_word(fp, 0);
  129. tga_write_word(fp, 0);
  130. tga_write_word(fp, 0);
  131. fwrite("TRUEVISION-XFILE.", 18, 1, fp);
  132. fclose(fp);
  133. }
  134. }
  135. /*
  136. font data:
  137. offset bytes description
  138. 0 1 glyph_cnt number of glyphs
  139. 1 1 bbx_mode 0: proportional, 1: common height, 2: monospace, 3: multiple of 8
  140. 2 1 bits_per_0 glyph rle parameter
  141. 3 1 bits_per_1 glyph rle parameter
  142. 4 1 bits_per_char_width glyph rle parameter
  143. 5 1 bits_per_char_height glyph rle parameter
  144. 6 1 bits_per_char_x glyph rle parameter
  145. 7 1 bits_per_char_y glyph rle parameter
  146. 8 1 bits_per_delta_x glyph rle parameter
  147. 9 1 max_char_width
  148. 10 1 max_char_height
  149. 11 1 x offset
  150. 12 1 y offset (descent)
  151. 13 1 ascent (capital A)
  152. 14 1 descent (lower g)
  153. 15 1 ascent '('
  154. 16 1 descent ')'
  155. 17 1 start pos 'A' high byte
  156. 18 1 start pos 'A' low byte
  157. 19 1 start pos 'a' high byte
  158. 20 1 start pos 'a' low byte
  159. 21 1 start pos unicode high byte
  160. 22 1 start pos unicode low byte
  161. */
  162. void tga_set_font(uint8_t *font)
  163. {
  164. glyph_cnt = *font++;
  165. font++; /* bbx mode */
  166. bits_per_0 = *font++;
  167. bits_per_1 = *font++;
  168. bits_per_char_width = *font++;
  169. bits_per_char_height = *font++;
  170. bits_per_char_x = *font++;
  171. bits_per_char_y = *font++;
  172. bits_per_delta_x = *font++;
  173. char_width = *font++;
  174. char_height = *font++;
  175. font++; /* x offset */
  176. char_descent = *(int8_t *)font;
  177. font++;
  178. font++;
  179. font++;
  180. font++;
  181. font++;
  182. font++;
  183. font++;
  184. font++;
  185. font++;
  186. unicode_start_pos = *font++;
  187. unicode_start_pos <<= 8;
  188. unicode_start_pos |= *font++;
  189. tga_font = font;
  190. }
  191. uint8_t *tga_get_glyph_data(uint16_t encoding)
  192. {
  193. uint8_t *font = tga_font;
  194. if ( encoding <= 255 )
  195. {
  196. for(;;)
  197. {
  198. if ( font[1] == 0 )
  199. break;
  200. if ( font[0] == encoding )
  201. {
  202. return font;
  203. }
  204. font += font[1];
  205. }
  206. }
  207. else
  208. {
  209. uint16_t e;
  210. uint8_t *unicode_lookup_table;
  211. font += unicode_start_pos;
  212. unicode_lookup_table = font;
  213. /* search for the glyph start in the unicode lookup table */
  214. do
  215. {
  216. font += ((unicode_lookup_table[0]<<8)|unicode_lookup_table[1]);
  217. unicode_lookup_table+=2;
  218. e = (unicode_lookup_table[0]<<8)|unicode_lookup_table[1];
  219. unicode_lookup_table+=2;
  220. } while( e < encoding );
  221. /* continue with the search in the font */
  222. for(;;)
  223. {
  224. e = ((font[0]<<8)|font[1]);
  225. if ( e == 0 )
  226. break;
  227. if ( e == encoding )
  228. {
  229. return font;
  230. }
  231. font += font[2];
  232. }
  233. }
  234. return NULL;
  235. }
  236. /* font decode */
  237. struct tga_fd_struct
  238. {
  239. unsigned target_x;
  240. unsigned target_y;
  241. unsigned is_transparent;
  242. unsigned x; /* local coordinates, (0,0) is upper left */
  243. unsigned y;
  244. unsigned glyph_width;
  245. unsigned glyph_height;
  246. const uint8_t *decode_ptr; /* pointer to the compressed data */
  247. unsigned decode_bit_pos; /* bitpos inside a byte of the compressed data */
  248. uint8_t bbx_x_max_bit_size;
  249. uint8_t bbx_y_max_bit_size;
  250. uint8_t bbx_w_max_bit_size;
  251. uint8_t bbx_h_max_bit_size;
  252. uint8_t dx_max_bit_size;
  253. };
  254. typedef struct tga_fd_struct tga_fd_t;
  255. /* increment x and consider line wrap (inc y)*/
  256. /* old procedure */
  257. void tga_fd_inc(tga_fd_t *f)
  258. {
  259. unsigned x = f->x;
  260. x++;
  261. if ( x == f->glyph_width )
  262. {
  263. x = 0;
  264. f->y++;
  265. }
  266. f->x = x;
  267. }
  268. unsigned tga_fd_get_unsigned_bits(tga_fd_t *f, unsigned cnt)
  269. {
  270. unsigned val;
  271. unsigned bit_pos = f->decode_bit_pos;
  272. val = *(f->decode_ptr);
  273. val >>= bit_pos;
  274. if ( bit_pos + cnt >= 8 )
  275. {
  276. f->decode_ptr++;
  277. val |= *(f->decode_ptr) << (8-bit_pos);
  278. bit_pos -= 8;
  279. }
  280. val &= (1U<<cnt)-1;
  281. bit_pos += cnt;
  282. f->decode_bit_pos = bit_pos;
  283. return val;
  284. }
  285. /*
  286. 2 bit --> cnt = 2
  287. -2,-1,0. 1
  288. 3 bit --> cnt = 3
  289. -2,-1,0. 1
  290. -4,-3,-2,-1,0,1,2,3
  291. if ( x < 0 )
  292. r = bits(x-1)+1;
  293. else
  294. r = bits(x)+1;
  295. */
  296. int tga_fd_get_signed_bits(tga_fd_t *t, int cnt)
  297. {
  298. return (int)tga_fd_get_unsigned_bits(t, cnt) - ((1<<cnt)>>1);
  299. }
  300. void tga_fd_draw_fg_pixel(tga_fd_t *f, unsigned cnt)
  301. {
  302. //printf("%d ", cnt);
  303. /* cnt can be zero */
  304. while( cnt > 0 )
  305. {
  306. cnt--;
  307. tga_set_pixel(f->target_x+f->x+cnt, f->target_y+f->y, 0,0,0);
  308. }
  309. }
  310. void tga_fd_draw_bg_pixel(tga_fd_t *f, unsigned cnt)
  311. {
  312. //printf("%d ", cnt);
  313. /* cnt can be zero */
  314. while( cnt > 0 )
  315. {
  316. cnt--;
  317. if ( f->is_transparent == 0 )
  318. tga_set_pixel(f->target_x+f->x+cnt, f->target_y+f->y, 0x0e8,0x0e8,0x0e8);
  319. }
  320. }
  321. void tga_draw_hline(unsigned x,unsigned y, unsigned cnt, unsigned is_foreground)
  322. {
  323. while( cnt > 0 )
  324. {
  325. cnt--;
  326. if ( is_foreground == 0 )
  327. tga_set_pixel(x+cnt, y, 0x0e8,0x0e8,0x0e8);
  328. else
  329. tga_set_pixel(x+cnt, y, 255,0,0);
  330. }
  331. }
  332. void tga_fd_draw_pixel(tga_fd_t *f, unsigned cnt, unsigned is_foreground)
  333. {
  334. if ( is_foreground )
  335. {
  336. tga_fd_draw_fg_pixel(f, cnt);
  337. }
  338. else
  339. {
  340. tga_fd_draw_bg_pixel(f, cnt);
  341. }
  342. }
  343. void tga_fd_decode_len(tga_fd_t *f, unsigned len, unsigned is_foreground)
  344. {
  345. unsigned cnt, rem;
  346. cnt = len;
  347. for(;;)
  348. {
  349. rem = f->glyph_width;
  350. rem -= f->x;
  351. if ( cnt < rem )
  352. break;
  353. tga_fd_draw_pixel(f,rem, is_foreground);
  354. cnt -= rem;
  355. f->x = 0;
  356. f->y++;
  357. }
  358. tga_fd_draw_pixel(f, cnt, is_foreground);
  359. f->x += cnt;
  360. }
  361. unsigned tga_fd_decode(tga_fd_t *f, uint8_t *glyph_data, int is_unicode)
  362. {
  363. unsigned a, b;
  364. //unsigned cnt, rem;
  365. int x, y;
  366. unsigned d = 0;
  367. f->decode_ptr = glyph_data;
  368. f->decode_bit_pos = 0;
  369. f->decode_ptr += 1;
  370. f->decode_ptr += 1;
  371. if ( is_unicode != 0 )
  372. f->decode_ptr += 1;
  373. f->glyph_width = tga_fd_get_unsigned_bits(f, bits_per_char_width);
  374. f->glyph_height = tga_fd_get_unsigned_bits(f, bits_per_char_height);
  375. x = tga_fd_get_signed_bits(f, bits_per_char_x);
  376. y = tga_fd_get_signed_bits(f, bits_per_char_y);
  377. d = tga_fd_get_signed_bits(f, bits_per_delta_x);
  378. if ( f->glyph_width > 0 )
  379. {
  380. f->target_x += x;
  381. f->target_y -= f->glyph_height ;
  382. f->target_y -=y ;
  383. /* reset local x/y position */
  384. f->x = 0;
  385. f->y = 0;
  386. /* decode glyph */
  387. for(;;)
  388. {
  389. a = tga_fd_get_unsigned_bits(f, bits_per_0);
  390. b = tga_fd_get_unsigned_bits(f, bits_per_1);
  391. do
  392. {
  393. tga_fd_decode_len(f, a, 0);
  394. tga_fd_decode_len(f, b, 1);
  395. } while( tga_fd_get_unsigned_bits(f, 1) != 0 );
  396. if ( f->y >= f->glyph_height )
  397. break;
  398. }
  399. }
  400. return d;
  401. }
  402. unsigned tga_draw_glyph(unsigned x, unsigned y, uint16_t encoding, int is_hints)
  403. {
  404. unsigned dx = 0;
  405. tga_fd_t f;
  406. f.target_x = x;
  407. f.target_y = y;
  408. f.is_transparent = !is_hints;
  409. uint8_t *glyph_data = tga_get_glyph_data(encoding); /* better skip the first 2 or 3 bytes */
  410. if ( glyph_data != NULL )
  411. {
  412. dx = tga_fd_decode(&f, glyph_data, encoding > 255 ? 1 : 0); /* 20 Sep 2025: >= changed to > */
  413. if ( is_hints )
  414. {
  415. tga_set_pixel(x+dx, y, 28,133,240); /* orange: reference point */
  416. tga_set_pixel(x, y, 255,164,0); /* blue: delta x (width) for this glyph */
  417. }
  418. }
  419. return dx;
  420. }
  421. unsigned tga_draw_string(unsigned x, unsigned y, const char *s, int is_hints, unsigned max_dx)
  422. {
  423. unsigned dx = 0;
  424. while( *s != '\0' )
  425. {
  426. dx += tga_draw_glyph(x+dx,y,*s, is_hints);
  427. if ( max_dx > 0 )
  428. if ( dx > max_dx )
  429. break;
  430. s++;
  431. }
  432. return dx;
  433. }