PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/bmp.c

https://bitbucket.org/alins/magic-lantern-for-500d/
C | 910 lines | 610 code | 118 blank | 182 comment | 142 complexity | 7515c9dc550876a2209d5dcc1612f150 MD5 | raw file
Possible License(s): GPL-2.0
  1. /** \file
  2. * Drawing routines.
  3. *
  4. * These are Magic Lantern routines to draw into the BMP LVRAM.
  5. * They are not derived from DryOS routines.
  6. */
  7. /*
  8. * Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the
  22. * Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor,
  24. * Boston, MA 02110-1301, USA.
  25. */
  26. #include "dryos.h"
  27. #include "bmp.h"
  28. #include "font.h"
  29. #include <stdarg.h>
  30. //~ int bmp_enabled = 1;
  31. #define USE_LUT
  32. extern int LV_EX_X;
  33. extern int LV_EX_Y;
  34. extern int ext_monitor_rca;
  35. extern int ext_monitor_hdmi;
  36. extern int recording;
  37. void calc_ov_loc_size(bmp_ov_loc_size_t *os)
  38. {
  39. int ov_x, ov_y;
  40. os->lv_ex_x = LV_EX_X;
  41. os->lv_ex_y = LV_EX_Y;
  42. if (ext_monitor_hdmi || ext_monitor_rca) {
  43. // Parameters of challenge
  44. // HDMI output is 1920x1080 (16:9) / 640x480 (4:3)
  45. // BMP overlay 960x540 (4:3) / 720x480 (4:3)
  46. // LV centered with aspect ratio of 3:2
  47. int disp_x, disp_y;
  48. if(recording || ext_monitor_rca) {
  49. disp_x=640;
  50. disp_y=480;
  51. ov_x=720;
  52. ov_y=480;
  53. if(ext_monitor_rca) {
  54. os->lv_ex_y = 394;
  55. }
  56. os->lv_ex_x = 570; // we have different live view dimensions than reported (3:2 -> 4:3)
  57. } else {
  58. disp_x=1920;
  59. disp_y=1080;
  60. ov_x=960;
  61. ov_y=540;
  62. }
  63. os->bmp_ex_x=os->lv_ex_x*ov_x/disp_x;
  64. os->bmp_ex_y=os->lv_ex_y*ov_y/disp_y;
  65. os->bmp_of_y=(recording||ext_monitor_rca||os->lv_ex_y==880)?24:0; //screen layout differs beween rec mode and standby
  66. os->bmp_of_x=ext_monitor_rca?(ov_x-os->bmp_ex_x)/3:((ov_x-os->bmp_ex_x)>>1);
  67. } else {
  68. ov_x = os->bmp_ex_x=720;
  69. ov_y = os->bmp_ex_y=480;
  70. os->bmp_of_x=0;
  71. os->bmp_of_y=0;
  72. }
  73. os->bmp_sz_x = ov_x;
  74. os->bmp_sz_y = ov_y;
  75. // bmp_printf( FONT_MED, 10, 40, "calc_ov_loc_size: %d %d %d %d %d %d %d %d", os->bmp_sz_x, os->bmp_sz_y, os->bmp_ex_x, os->bmp_ex_y, os->bmp_of_x, os->bmp_of_y, os->lv_pitch, os->lv_height);
  76. }
  77. static void
  78. _draw_char(
  79. unsigned fontspec,
  80. uint8_t * bmp_vram_row,
  81. char c
  82. )
  83. {
  84. //~ if (!bmp_enabled) return;
  85. unsigned i,j;
  86. const struct font * const font = fontspec_font( fontspec );
  87. uint32_t fg_color = fontspec_fg( fontspec ) << 24;
  88. uint32_t bg_color = fontspec_bg( fontspec ) << 24;
  89. // Special case -- fg=bg=0 => white on black
  90. if( fg_color == 0 && bg_color == 0 )
  91. {
  92. fg_color = COLOR_WHITE << 24;
  93. bg_color = COLOR_BLACK << 24;
  94. }
  95. const uint32_t pitch = BMPPITCH / 4;
  96. uint32_t * front_row = (uint32_t *) bmp_vram_row;
  97. //uint32_t flags = cli();
  98. for( i=0 ; i<font->height ; i++ )
  99. {
  100. // Start this scanline
  101. uint32_t * row = front_row;
  102. // move to the next scanline
  103. front_row += pitch;
  104. uint32_t pixels = font->bitmap[ c + (i << 7) ];
  105. uint8_t pixel;
  106. for( j=0 ; j<font->width/4 ; j++ )
  107. {
  108. uint32_t bmp_pixels = 0;
  109. for( pixel=0 ; pixel<4 ; pixel++, pixels <<=1 )
  110. {
  111. bmp_pixels >>= 8;
  112. bmp_pixels |= (pixels & 0x80000000) ? fg_color : bg_color;
  113. }
  114. *(row++) = bmp_pixels;
  115. // handle characters wider than 32 bits
  116. if( j == 28/4 )
  117. pixels = font->bitmap[ c + ((i+128) << 7) ];
  118. }
  119. }
  120. //sei( flags );
  121. }
  122. void
  123. bmp_puts(
  124. unsigned fontspec,
  125. unsigned * x,
  126. unsigned * y,
  127. const char * s
  128. )
  129. {
  130. const uint32_t pitch = BMPPITCH;
  131. uint8_t * vram = bmp_vram();
  132. if( !vram || ((uintptr_t)vram & 1) == 1 )
  133. return;
  134. const unsigned initial_x = *x;
  135. uint8_t * first_row = vram + (*y) * pitch + (*x);
  136. uint8_t * row = first_row;
  137. char c;
  138. const struct font * const font = fontspec_font( fontspec );
  139. while( (c = *s++) )
  140. {
  141. if( c == '\n' )
  142. {
  143. row = first_row += pitch * font->height;
  144. (*y) += font->height;
  145. (*x) = initial_x;
  146. continue;
  147. }
  148. _draw_char( fontspec, row, c );
  149. row += font->width;
  150. (*x) += font->width;
  151. }
  152. }
  153. void
  154. bmp_puts_w(
  155. unsigned fontspec,
  156. int * x,
  157. int * y,
  158. int max_chars_per_line,
  159. const char * s
  160. )
  161. {
  162. const uint32_t pitch = BMPPITCH;
  163. uint8_t * vram = bmp_vram();
  164. if( !vram || ((uintptr_t)vram & 1) == 1 )
  165. return;
  166. const int initial_x = *x;
  167. uint8_t * first_row = vram + (*y) * pitch + (*x);
  168. uint8_t * row = first_row;
  169. char c;
  170. const struct font * const font = fontspec_font( fontspec );
  171. int i = 0;
  172. while( (c = *s++) )
  173. {
  174. if( c == '\n' || i >= max_chars_per_line)
  175. {
  176. row = first_row += pitch * font->height;
  177. (*y) += font->height;
  178. (*x) = initial_x;
  179. i = 0;
  180. if (lv_drawn()) msleep(1);
  181. if (c == '\n') continue;
  182. }
  183. _draw_char( fontspec, row, c );
  184. row += font->width;
  185. (*x) += font->width;
  186. i++;
  187. }
  188. }
  189. void
  190. bmp_printf(
  191. unsigned fontspec,
  192. unsigned x,
  193. unsigned y,
  194. const char * fmt,
  195. ...
  196. )
  197. {
  198. va_list ap;
  199. char buf[ 256 ];
  200. va_start( ap, fmt );
  201. vsnprintf( buf, sizeof(buf), fmt, ap );
  202. va_end( ap );
  203. bmp_puts( fontspec, &x, &y, buf );
  204. }
  205. void
  206. con_printf(
  207. unsigned fontspec,
  208. const char * fmt,
  209. ...
  210. )
  211. {
  212. va_list ap;
  213. char buf[ 256 ];
  214. static int x = 0;
  215. static int y = 32;
  216. va_start( ap, fmt );
  217. vsnprintf( buf, sizeof(buf), fmt, ap );
  218. va_end( ap );
  219. const uint32_t pitch = BMPPITCH;
  220. uint8_t * vram = bmp_vram();
  221. if( !vram )
  222. return;
  223. uint8_t * first_row = vram + y * pitch + x;
  224. uint8_t * row = first_row;
  225. char * s = buf;
  226. char c;
  227. const struct font * const font = fontspec_font( fontspec );
  228. while( (c = *s++) )
  229. {
  230. if( c == '\n' )
  231. {
  232. row = first_row += pitch * font->height;
  233. y += font->height;
  234. x = 0;
  235. bmp_fill( 0, 0, y, 720, font->height );
  236. } else {
  237. _draw_char( fontspec, row, c );
  238. row += font->width;
  239. x += font->width;
  240. }
  241. if( x > 720 )
  242. {
  243. y += font->height;
  244. x = 0;
  245. bmp_fill( 0, 0, y, 720, font->height );
  246. }
  247. if( y > 480 )
  248. {
  249. x = 0;
  250. y = 32;
  251. bmp_fill( 0, 0, y, 720, font->height );
  252. }
  253. }
  254. }
  255. void
  256. bmp_hexdump(
  257. unsigned fontspec,
  258. unsigned x,
  259. unsigned y,
  260. const void * buf,
  261. size_t len
  262. )
  263. {
  264. if( len == 0 )
  265. return;
  266. // Round up
  267. len = (len + 15) & ~15;
  268. const uint32_t * d = (uint32_t*) buf;
  269. do {
  270. bmp_printf(
  271. fontspec,
  272. x,
  273. y,
  274. "%08x: %08x %08x %08x %08x %08x %08x %08x %08x ",
  275. (unsigned) d,
  276. len > 0 ? (unsigned) d[ 0/4] : 0,
  277. len > 4 ? (unsigned) d[ 4/4] : 0,
  278. len > 8 ? (unsigned) d[ 8/4] : 0,
  279. len > 12 ? (unsigned) d[12/4] : 0,
  280. len > 16 ? (unsigned) d[16/4] : 0,
  281. len > 20 ? (unsigned) d[20/4] : 0,
  282. len > 24 ? (unsigned) d[24/4] : 0,
  283. len > 28 ? (unsigned) d[28/4] : 0
  284. );
  285. y += fontspec_height( fontspec );
  286. d += 8;
  287. len -= 32;
  288. } while(len);
  289. }
  290. /** Fill a section of bitmap memory with solid color
  291. * Only has a four-pixel resolution in X.
  292. */
  293. void
  294. bmp_fill(
  295. uint8_t color,
  296. uint32_t x,
  297. uint32_t y,
  298. uint32_t w,
  299. uint32_t h
  300. )
  301. {
  302. //~ if (!bmp_enabled) return;
  303. bmp_ov_loc_size_t os;
  304. calc_ov_loc_size(&os);
  305. const uint32_t start = x;
  306. const uint32_t width = os.bmp_sz_x;
  307. const uint32_t pitch = BMPPITCH;
  308. const uint32_t height = os.bmp_sz_y;
  309. // Convert to words and limit to the width of the LCD
  310. if( start + w > width )
  311. w = width - start;
  312. const uint32_t word = 0
  313. | (color << 24)
  314. | (color << 16)
  315. | (color << 8)
  316. | (color << 0);
  317. if( y > height )
  318. y = height;
  319. uint16_t y_end = y + h;
  320. if( y_end > height )
  321. y_end = height;
  322. if( w == 0 || h == 0 )
  323. return;
  324. uint8_t * const vram = bmp_vram();
  325. uint32_t * row = (void*)( vram + y * pitch + start );
  326. if( !vram || ( 1 & (uintptr_t) vram ) )
  327. {
  328. //sei( flags );
  329. return;
  330. }
  331. for( ; y<y_end ; y++, row += pitch/4 )
  332. {
  333. uint32_t x;
  334. for( x=0 ; x<w/4 ; x++ )
  335. {
  336. row[ x ] = word;
  337. //~ asm( "nop" );
  338. //~ asm( "nop" );
  339. //~ asm( "nop" );
  340. //~ asm( "nop" );
  341. }
  342. }
  343. }
  344. /** Draw a picture of the BMP color palette. */
  345. void
  346. bmp_draw_palette( void )
  347. {
  348. uint32_t x, y, msb, lsb;
  349. const uint32_t height = 30;
  350. const uint32_t width = 45;
  351. for( msb=0 ; msb<16; msb++ )
  352. {
  353. for( y=0 ; y<height; y++ )
  354. {
  355. uint8_t * const row = bmp_vram() + (y + height*msb) * BMPPITCH;
  356. for( lsb=0 ; lsb<16 ; lsb++ )
  357. {
  358. for( x=0 ; x<width ; x++ )
  359. row[x+width*lsb] = (msb << 4) | lsb;
  360. }
  361. }
  362. }
  363. static int written;
  364. if( !written )
  365. dispcheck();
  366. written = 1;
  367. msleep(2000);
  368. }
  369. int retry_count = 0;
  370. size_t
  371. read_file(
  372. const char * filename,
  373. void * buf,
  374. size_t size
  375. )
  376. {
  377. FILE * file = FIO_Open( filename, O_RDONLY | O_SYNC );
  378. if( file == INVALID_PTR )
  379. return -1;
  380. unsigned rc = FIO_ReadFile( file, buf, size );
  381. FIO_CloseFile( file );
  382. if( rc == size )
  383. return size;
  384. DebugMsg( DM_MAGIC, 3, "%s: size=%d rc=%d", filename, size, rc );
  385. return -1;
  386. }
  387. /** Load a BMP file into memory so that it can be drawn onscreen */
  388. struct bmp_file_t *
  389. bmp_load(
  390. const char * filename
  391. )
  392. {
  393. DebugMsg( DM_MAGIC, 3, "bmp_load(%s)", filename);
  394. unsigned size;
  395. if( FIO_GetFileSize( filename, &size ) != 0 )
  396. goto getfilesize_fail;
  397. DebugMsg( DM_MAGIC, 3, "File '%s' size %d bytes",
  398. filename,
  399. size
  400. );
  401. uint8_t * buf = alloc_dma_memory( size );
  402. if( !buf )
  403. {
  404. DebugMsg( DM_MAGIC, 3, "%s: alloc_dma_memory failed", filename );
  405. goto malloc_fail;
  406. }
  407. size_t i;
  408. for( i=0 ; i<size; i++ )
  409. buf[i] = 'A' + i;
  410. size_t rc = read_file( filename, buf, size );
  411. if( rc != size )
  412. goto read_fail;
  413. struct bmp_file_t * bmp = (struct bmp_file_t *) buf;
  414. if( bmp->signature != 0x4D42 )
  415. {
  416. DebugMsg( DM_MAGIC, 3, "%s: signature %04x", filename, bmp->signature );
  417. int i;
  418. for( i=0 ; i<64; i += 16 )
  419. DebugMsg( DM_MAGIC, 3,
  420. "%08x: %08x %08x %08x %08x",
  421. buf + i,
  422. ((uint32_t*)(buf + i))[0],
  423. ((uint32_t*)(buf + i))[1],
  424. ((uint32_t*)(buf + i))[2],
  425. ((uint32_t*)(buf + i))[3]
  426. );
  427. goto signature_fail;
  428. }
  429. // Update the offset pointer to point to the image data
  430. // if it is within bounds
  431. const unsigned image_offset = (unsigned) bmp->image;
  432. if( image_offset > size )
  433. {
  434. DebugMsg( DM_MAGIC, 3, "%s: size too large: %x > %x", filename, image_offset, size );
  435. goto offsetsize_fail;
  436. }
  437. // Since the read was into uncacheable memory, it will
  438. // be very slow to access. Copy it into a cached buffer
  439. // and release the uncacheable space.
  440. uint8_t * fast_buf = AllocateMemory( size + 32);
  441. if( !fast_buf )
  442. goto fail_buf_copy;
  443. memcpy(fast_buf, buf, size);
  444. bmp = (struct bmp_file_t *) fast_buf;
  445. bmp->image = fast_buf + image_offset;
  446. free_dma_memory( buf );
  447. return bmp;
  448. fail_buf_copy:
  449. offsetsize_fail:
  450. signature_fail:
  451. read_fail:
  452. free_dma_memory( buf );
  453. malloc_fail:
  454. getfilesize_fail:
  455. DebugMsg( DM_MAGIC, 3, "bmp_load failed");
  456. return NULL;
  457. }
  458. void clrscr()
  459. {
  460. bmp_fill( 0x0, 0, 0, 960, 540 );
  461. }
  462. // mirror can be NULL
  463. void bmp_draw(struct bmp_file_t * bmp, int x0, int y0, uint8_t* const mirror, int clear)
  464. {
  465. if (!bmp) return;
  466. //~ if (!bmp_enabled) return;
  467. uint8_t * const bvram = bmp_vram();
  468. if (!bvram) return;
  469. x0 = COERCE(x0, 0, 960 - (int)bmp->width);
  470. y0 = COERCE(y0, 0, 540 - (int)bmp->height);
  471. if (x0 < 0) return;
  472. if (x0 + bmp->width > 960) return;
  473. if (y0 < 0) return;
  474. if (y0 + bmp->height > 960) return;
  475. int bmppitch = BMPPITCH;
  476. uint32_t x,y;
  477. for( y=0 ; y < bmp->height; y++ )
  478. {
  479. uint8_t * const b_row = (uint8_t*)( bvram + (y + y0) * bmppitch );
  480. uint8_t * const m_row = (uint8_t*)( mirror+ (y + y0) * bmppitch );
  481. for( x=0 ; x < bmp->width ; x++ )
  482. {
  483. if (clear)
  484. {
  485. uint8_t p = b_row[ x + x0 ];
  486. uint8_t pix = bmp->image[ x + bmp->width * (bmp->height - y - 1) ];
  487. if (pix && p == pix)
  488. b_row[x + x0] = 0;
  489. }
  490. else
  491. {
  492. if (mirror)
  493. {
  494. uint8_t p = b_row[ x + x0 ];
  495. uint8_t m = m_row[ x + x0 ];
  496. if (p != 0 && p != 0x14 && p != 0x3 && p != m) continue;
  497. }
  498. uint8_t pix = bmp->image[ x + bmp->width * (bmp->height - y - 1) ];
  499. b_row[x + x0] = pix;
  500. }
  501. }
  502. }
  503. }
  504. /*
  505. void bmp_draw_scaled(struct bmp_file_t * bmp, int x0, int y0, int xmax, int ymax)
  506. {
  507. if (!bmp) return;
  508. uint8_t * const bvram = bmp_vram();
  509. if (!bvram) return;
  510. int bmppitch = BMPPITCH;
  511. int x,y; // those sweep the original bmp
  512. int xs,ys; // those sweep the BMP VRAM (and are scaled)
  513. #ifdef USE_LUT
  514. // we better don't use AllocateMemory for LUT (Err 70)
  515. static int16_t lut[960];
  516. for (xs = x0; xs < (x0 + xmax); xs++)
  517. {
  518. lut[xs] = (xs-x0) * bmp->width/xmax;
  519. }
  520. #endif
  521. for( ys = y0 ; ys < (y0 + ymax); ys++ )
  522. {
  523. y = (ys-y0)*bmp->height/ymax;
  524. uint8_t * const b_row = bvram + ys * bmppitch;
  525. for (xs = x0; xs < (x0 + xmax); xs++)
  526. {
  527. #ifdef USE_LUT
  528. x = lut[xs];
  529. #else
  530. x = (xs-x0)*bmp->width/xmax;
  531. #endif
  532. uint8_t pix = bmp->image[ x + bmp->width * (bmp->height - y - 1) ];
  533. b_row[ xs ] = pix;
  534. }
  535. }
  536. }*/
  537. // this is slow, but is good for a small number of pixels :)
  538. uint8_t bmp_getpixel(int x, int y)
  539. {
  540. uint8_t * const bvram = bmp_vram();
  541. if (!bvram) return 0;
  542. int bmppitch = BMPPITCH;
  543. uint8_t * const b_row = bvram + y * bmppitch;
  544. return b_row[x];
  545. }
  546. void bmp_putpixel(int x, int y, uint8_t color)
  547. {
  548. //~ if (!bmp_enabled) return;
  549. uint8_t * const bvram = bmp_vram();
  550. if (!bvram) return;
  551. int bmppitch = BMPPITCH;
  552. x = COERCE(x, 0, 960);
  553. y = COERCE(y, 0, 540);
  554. uint8_t * const b_row = bvram + y * bmppitch;
  555. b_row[x] = color;
  556. }
  557. void bmp_draw_rect(uint8_t color, int x0, int y0, int w, int h)
  558. {
  559. //~ if (!bmp_enabled) return;
  560. uint8_t * const bvram = bmp_vram();
  561. if (!bvram) return;
  562. int x, y;
  563. #define P(X,Y) bvram[COERCE(X, 0, 960) + COERCE(Y, 0, 540) * BMPPITCH]
  564. for (x = x0; x <= x0 + w; x++)
  565. P(x, y0) = P(x, y0+h) = color;
  566. for (y = y0; y <= y0 + h; y++)
  567. P(x0, y) = P(x0+w, y) = color;
  568. #undef P
  569. }
  570. void bmp_draw_scaled_ex(struct bmp_file_t * bmp, int x0, int y0, int xmax, int ymax, uint8_t* const mirror, int clear)
  571. {
  572. if (!bmp) return;
  573. //~ if (!bmp_enabled) return;
  574. uint8_t * const bvram = bmp_vram();
  575. if (!bvram) return;
  576. int bmppitch = BMPPITCH;
  577. int x,y; // those sweep the original bmp
  578. int xs,ys; // those sweep the BMP VRAM (and are scaled)
  579. #ifdef USE_LUT
  580. // we better don't use AllocateMemory for LUT (Err 70)
  581. static int16_t lut[960];
  582. for (xs = x0; xs < (x0 + xmax); xs++)
  583. {
  584. lut[xs] = (xs-x0) * bmp->width/xmax;
  585. }
  586. #endif
  587. for( ys = y0 ; ys < (y0 + ymax); ys++ )
  588. {
  589. y = (ys-y0)*bmp->height/ymax;
  590. uint8_t * const b_row = bvram + ys * bmppitch;
  591. uint8_t * const m_row = (uint8_t*)( mirror+ (y + y0) * bmppitch );
  592. for (xs = x0; xs < (x0 + xmax); xs++)
  593. {
  594. #ifdef USE_LUT
  595. x = lut[xs];
  596. #else
  597. x = (xs-x0)*bmp->width/xmax;
  598. #endif
  599. if (clear)
  600. {
  601. uint8_t p = b_row[ xs ];
  602. uint8_t pix = bmp->image[ x + bmp->width * (bmp->height - y - 1) ];
  603. if (pix && p == pix)
  604. b_row[xs] = 0;
  605. }
  606. else
  607. {
  608. uint8_t pix = bmp->image[ x + bmp->width * (bmp->height - y - 1) ];
  609. if (mirror)
  610. {
  611. uint8_t p = b_row[ xs ];
  612. uint8_t m = m_row[ xs ];
  613. if (p != 0 && p != 0x14 && p != 0x3 && p != m) continue;
  614. if ((p == 0x14 || p == 0x3) && pix == 0) continue;
  615. }
  616. b_row[ xs ] = pix;
  617. }
  618. }
  619. }
  620. }
  621. // built-in fonts found by Pel
  622. // http://groups.google.com/group/ml-devel/browse_thread/thread/aec4c80eef1cdd6a
  623. // http://chdk.setepontos.com/index.php?topic=6204.0
  624. #define BFNT_CHAR_CODES 0xFF661AA4
  625. #define BFNT_BITMAP_OFFSET 0xFF663F84
  626. #define BFNT_BITMAP_DATA 0xFF666464
  627. // quick sanity test
  628. int bfnt_ok()
  629. {
  630. int* codes = (int *) BFNT_CHAR_CODES;
  631. int i;
  632. for (i = 0; i < 20; i++)
  633. if (codes[i] != 0x20+i) return 0;
  634. int* off = (int *) BFNT_BITMAP_OFFSET;
  635. if (off[0] != 0) return 0;
  636. for (i = 1; i < 20; i++)
  637. if (off[i] <= off[i-1]) return 0;
  638. return 1;
  639. }
  640. // are all char codes in ascending order, for binary search?
  641. uint8_t* bfnt_find_char(int code)
  642. {
  643. int n = (BFNT_BITMAP_OFFSET - BFNT_CHAR_CODES) / 4;
  644. int* codes = (int *) BFNT_CHAR_CODES;
  645. int* off = (int *) BFNT_BITMAP_OFFSET;
  646. if (code <= 'z') return (uint8_t*) (BFNT_BITMAP_DATA + off[code - 0x20]);
  647. int i;
  648. for (i = 0; i < n; i++)
  649. if (codes[i] == code)
  650. return (uint8_t*) (BFNT_BITMAP_DATA + off[i]);
  651. return 0;
  652. }
  653. // returns width
  654. int bfnt_draw_char(int c, int px, int py, int fg, int bg)
  655. {
  656. if (!bfnt_ok())
  657. {
  658. bmp_printf(FONT_SMALL, 0, 0, "font addr bad");
  659. return 0;
  660. }
  661. uint16_t* chardata = (uint16_t*) bfnt_find_char(c);
  662. if (!chardata) return 0;
  663. uint8_t* buff = (uint8_t*) (chardata + 5);
  664. int ptr = 0;
  665. int cw = chardata[0]; // the stored bitmap width
  666. int ch = chardata[1]; // the stored bitmap height
  667. int crw = chardata[2]; // the displayed character width
  668. int xo = chardata[3]; // X offset for displaying the bitmap
  669. int yo = chardata[4]; // Y offset for displaying the bitmap
  670. int bb = cw / 8 + (cw % 8 == 0 ? 0 : 1); // calculate the byte number per line
  671. //~ bmp_printf(FONT_SMALL, 0, 0, "%x %d %d %d %d %d %d", chardata, cw, ch, crw, xo, yo, bb);
  672. if (crw+xo > 50) return 0;
  673. if (ch+yo > 50) return 0;
  674. bmp_fill(bg, px, py, crw+xo+3, 40);
  675. int i,j,k;
  676. for (i = 0; i < ch; i++)
  677. {
  678. for (j = 0; j < bb; j++)
  679. {
  680. for (k = 0; k < 8; k++)
  681. {
  682. if (j*8 + k < cw)
  683. {
  684. if ((buff[ptr+j] & (1 << (7-k))))
  685. bmp_putpixel(px+j*8+k+xo, py+i+yo, fg);
  686. }
  687. }
  688. }
  689. ptr += bb;
  690. }
  691. return crw;
  692. }
  693. /*
  694. int bfnt_draw_char_half(int c, int px, int py, int fg, int bg, int g1, int g2)
  695. {
  696. if (!bfnt_ok())
  697. {
  698. bmp_printf(FONT_SMALL, 0, 0, "font addr bad");
  699. return 0;
  700. }
  701. uint16_t* chardata = bfnt_find_char(c);
  702. if (!chardata) return 0;
  703. uint8_t* buff = chardata + 5;
  704. int ptr = 0;
  705. unsigned int cw = chardata[0]; // the stored bitmap width
  706. unsigned int ch = chardata[1]; // the stored bitmap height
  707. unsigned int crw = chardata[2]; // the displayed character width
  708. unsigned int xo = chardata[3]; // X offset for displaying the bitmap
  709. unsigned int yo = chardata[4]; // Y offset for displaying the bitmap
  710. unsigned int bb = cw / 8 + (cw % 8 == 0 ? 0 : 1); // calculate the byte number per line
  711. //~ bmp_printf(FONT_SMALL, 0, 0, "%x %d %d %d %d %d %d", chardata, cw, ch, crw, xo, yo, bb);
  712. if (cw > 100) return 0;
  713. if (ch > 50) return 0;
  714. static uint8_t tmp[50][25];
  715. int i,j,k;
  716. for (i = 0; i < 50; i++)
  717. for (j = 0; j < 25; j++)
  718. tmp[i][j] = 0;
  719. for (i = 0; i < ch; i++)
  720. {
  721. for (j = 0; j < bb; j++)
  722. {
  723. for (k = 0; k < 8; k++)
  724. {
  725. if (j*8 + k < cw)
  726. {
  727. if ((buff[ptr+j] & (1 << (7-k))))
  728. tmp[COERCE((j*8+k)>>1, 0, 49)][COERCE(i>>1, 0, 24)] ++;
  729. }
  730. }
  731. }
  732. ptr += bb;
  733. }
  734. bmp_fill(bg, px+3, py, crw/2+xo/2+3, 20);
  735. for (i = 0; i <= cw/2; i++)
  736. {
  737. for (j = 0; j <= ch/2; j++)
  738. {
  739. int c = COLOR_RED;
  740. switch (tmp[i][j])
  741. {
  742. case 0:
  743. case 1:
  744. case 2:
  745. case 3:
  746. c = bg;
  747. break;
  748. case 4:
  749. c = fg;
  750. break;
  751. }
  752. if (c != bg) bmp_putpixel(px+xo/2+i, py+yo/2+j, c);
  753. }
  754. }
  755. return crw>>1;
  756. }*/
  757. void bfnt_puts(char* s, int x, int y, int fg, int bg)
  758. {
  759. while (*s)
  760. {
  761. x += bfnt_draw_char(*s, x, y, fg, bg);
  762. s++;
  763. }
  764. }
  765. void bfnt_puts_utf8(int* s, int x, int y, int fg, int bg)
  766. {
  767. while (*s)
  768. {
  769. x += bfnt_draw_char(*s, x, y, fg, bg);
  770. s++;
  771. }
  772. }
  773. static void bmp_init()
  774. {
  775. bmp_sem = create_named_semaphore("bmp_sem", 1);
  776. }
  777. INIT_FUNC(__FILE__, bmp_init);