root/core/gui_draw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. draw_pixel_std
  2. set_transparent
  3. color_to_rawpx
  4. draw_dblpixel_raw
  5. color_to_rawpx
  6. draw_dblpixel_raw
  7. set_transparent
  8. draw_pixel_proc_rotated
  9. draw_set_draw_proc
  10. update_draw_proc
  11. draw_pixel_simple_start
  12. draw_1pixel_simple
  13. draw_2pixels_simple
  14. draw_hline_simple
  15. draw_set_guard
  16. draw_test_guard
  17. draw_set_guard
  18. draw_test_guard
  19. draw_init
  20. draw_suspend
  21. draw_is_suspended
  22. draw_restore
  23. draw_pixel
  24. draw_pixel_unrotated
  25. draw_get_pixel
  26. draw_get_pixel_unrotated
  27. draw_line
  28. draw_line_x2
  29. draw_hline
  30. draw_vline
  31. draw_rectangle
  32. get_cdata
  33. draw_char
  34. draw_char
  35. draw_char_unscaled
  36. draw_char_scaled
  37. draw_char_scaled
  38. draw_string_clipped
  39. draw_string
  40. draw_string_justified
  41. text_dimensions
  42. draw_text_justified
  43. draw_string_scaled
  44. draw_string_scaled
  45. draw_osd_string
  46. draw_osd_string
  47. draw_txt_string
  48. draw_ellipse
  49. draw_button
  50. draw_icon_cmds
  51. set_palette
  52. get_script_color
  53. chdkColorToCanonColor
  54. user_color

   1 #include "platform.h"
   2 #include "touchscreen.h"
   3 #include "conf.h"
   4 #include "font.h"
   5 #include "lang.h"
   6 #include "gui_draw.h"
   7 
   8 #define GET_FONT_COMPRESSION_MODE 1
   9 #include "../lib/font/font_8x16_uni_packed.h"
  10 #undef  GET_FONT_COMPRESSION_MODE
  11 
  12 #ifdef THUMB_FW
  13 // macros for computing palette from a single byte color value
  14 #define CALC_YUV_LUMA_OPACITY_FOR_COLOR(color,luma,opacity) \
  15     { \
  16         luma = ((color-1)^0xffffffff)&0xf0; \
  17         opacity = (color&0xf)?255:color; \
  18     }
  19 
  20 #define CALC_YUV_CHROMA_FOR_COLOR(color,u,v) \
  21     { \
  22         v = color; \
  23         u = (v+1); \
  24         if (!(u&2)) \
  25         { \
  26             u = 128; \
  27             v = 128; \
  28         } \
  29         else \
  30         { \
  31             u *= 3; \
  32             v <<= 3; \
  33         } \
  34     }
  35 
  36 extern volatile char *opacity_buffer[];
  37 
  38 #endif
  39 //-------------------------------------------------------------------
  40 // used to prevent draw_restore from being called until tick reached
  41 // to avoid crashes on video out change
  42 int draw_restore_suspend_tick;
  43 
  44 void            (*draw_pixel_proc)(unsigned int offset, color cl);
  45 void            (*draw_pixel_proc_norm)(unsigned int offset, color cl);
  46 
  47 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
  48 extern char* bitmap_buffer[];
  49 extern int active_bitmap_buffer;
  50 #else
  51 static char* frame_buffer[2];
  52 #endif
  53 //-------------------------------------------------------------------
  54 
  55 static void draw_pixel_std(unsigned int offset, color cl)
  56 {
  57 #ifndef THUMB_FW
  58     // drawing on 8bpp paletted overlay
  59 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
  60         bitmap_buffer[active_bitmap_buffer][offset] = cl;
  61 #else
  62         frame_buffer[0][offset] = frame_buffer[1][offset] = cl;
  63 #endif
  64 #else
  65     // DIGIC 6, drawing on 16bpp YUV overlay
  66 
  67 #ifndef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
  68 #error DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY is required for DIGIC 6 ports
  69 #endif
  70 
  71     int active_buffer_index =  active_bitmap_buffer & 1;
  72     unsigned char *obu = (unsigned char *)(&opacity_buffer[active_buffer_index][0]);
  73     unsigned char *bbu = (unsigned char *)(&bitmap_buffer[active_buffer_index][0]);
  74     unsigned int y;
  75     unsigned int o;
  76     CALC_YUV_LUMA_OPACITY_FOR_COLOR(cl,y,o);
  77     obu[offset] = o;
  78     register unsigned int offs2 = (offset>>1)<<2;
  79     if (offset&1) // x is odd
  80     {
  81         bbu[offs2+3] = y; // Y
  82     }
  83     else // x is even
  84     {
  85         bbu[offs2+1] = y; // Y
  86     }
  87     unsigned int u;
  88     unsigned int v;
  89     CALC_YUV_CHROMA_FOR_COLOR(cl,u,v);
  90     bbu[offs2+0] = u; // U?
  91     bbu[offs2+2] = v; // V?
  92 #endif
  93 }
  94 //-------------------------------------------------------------------
  95 #ifdef THUMB_FW
  96 // direct drawing functions for YUV overlay, currently used by the zebra module
  97 // ATTENTION: these functions do not support guard pixels or rotation
  98 
  99 // function for setting part of the overlay transparent (DIGIC 6 only), used in zebra module
 100 // n_pixel is the number of pixels to set
 101 // offst is the byte offset in bitmap_buffer, 2 bytes per pixel
 102 void set_transparent(unsigned int offst, int n_pixel)
 103 {
 104     extern void _bzero(char *s, int n);
 105     extern void _memset32(char *s, int n, unsigned int pattern);
 106     //offset is the byte (same as pixel) offset in the opacity buffer
 107     unsigned int offset = offst>>2;
 108     unsigned int w_pattern = 0x00800080;
 109 
 110     int active_buffer_index = active_bitmap_buffer & 1;
 111 
 112     _memset32(&bitmap_buffer[active_buffer_index][offst], n_pixel<<1, w_pattern);
 113     _bzero((char*)&opacity_buffer[active_buffer_index][offset], n_pixel);
 114 
 115 }
 116 
 117 // translate single byte CHDK color to a whole yuv unit (2 pixels)
 118 // opacity is returned via the second argument
 119 unsigned int color_to_rawpx(color cl, unsigned int *op)
 120 {
 121     unsigned int y,u,v,o;
 122     CALC_YUV_CHROMA_FOR_COLOR(cl,u,v);
 123     CALC_YUV_LUMA_OPACITY_FOR_COLOR(cl,y,o);
 124     if (op) *op = o;
 125     return (u&255)+((y&255)<<8)+((v&255)<<16)+(y<<24);
 126 }
 127 
 128 // function for drawing a whole yuv unit (2 pixels, aligned)
 129 // opacity is a single byte, used for both pixels
 130 // drawing offset is pixel offset, calculated by caller
 131 void draw_dblpixel_raw(unsigned int offset, unsigned int px, unsigned int op)
 132 {
 133     int active_buffer_index =  active_bitmap_buffer & 1;
 134     offset >>= 2;
 135     unsigned short * opbuf = (unsigned short*)(opacity_buffer[active_buffer_index]);
 136     unsigned int * bmbuf = (unsigned int*)(bitmap_buffer[active_buffer_index]);
 137     bmbuf[offset] = px;
 138     opbuf[offset] = op | (op<<8);
 139 }
 140 
 141 #else // !THUMB_FW
 142 // not implemented for earlier DIGICs
 143 unsigned int color_to_rawpx(__attribute__ ((unused))color cl, __attribute__ ((unused))unsigned int *op)
 144 {
 145     return 0;
 146 }
 147 void draw_dblpixel_raw(__attribute__ ((unused))unsigned int offset, __attribute__ ((unused))unsigned int px, __attribute__ ((unused))unsigned int op)
 148 {
 149 }
 150 void set_transparent(__attribute__ ((unused))unsigned int offst, __attribute__ ((unused))int n_pixel)
 151 {
 152 }
 153 #endif // THUMB_FW
 154 
 155 //-------------------------------------------------------------------
 156 unsigned int rotate_base;
 157 
 158 void draw_pixel_proc_rotated(unsigned int offset, color cl)
 159 {
 160     draw_pixel_proc_norm(rotate_base - offset, cl);
 161 }
 162 
 163 void draw_set_draw_proc(void (*pixel_proc)(unsigned int offset, color cl))
 164 {
 165     draw_pixel_proc_norm = (pixel_proc)?pixel_proc:draw_pixel_std;
 166     if (conf.rotate_osd)
 167     {
 168         rotate_base = (camera_screen.height - 1) * camera_screen.buffer_width + ASPECT_XCORRECTION(camera_screen.width) - 1;
 169         draw_pixel_proc = draw_pixel_proc_rotated;
 170     }
 171     else
 172     {
 173         draw_pixel_proc = draw_pixel_proc_norm;
 174     }
 175 }
 176 
 177 void update_draw_proc()
 178 {
 179     draw_set_draw_proc(draw_pixel_proc_norm);
 180 }
 181 
 182 //-------------------------------------------------------------------
 183 #ifdef THUMB_FW
 184 // pixel drawing functions for YUV, meant to be optimized for greater speed
 185 // drawing is done directly, drawing function replacement is not supported
 186 // OSD rotation is respected
 187 
 188 static unsigned char *current_opacity_buf;
 189 static unsigned char *current_bitmap_buf;
 190 static unsigned char yuvclr[8]; // order of bytes: background u,y,v,opacity; foreground u,y,v,opacity
 191 
 192 // sets up decoded colors and buffer addresses for the following drawing operation
 193 static void draw_pixel_simple_start(twoColors tc)
 194 {
 195     color cl;
 196     int active_buffer_index =  active_bitmap_buffer & 1;
 197     current_opacity_buf = (unsigned char *)(&opacity_buffer[active_buffer_index][0]);
 198     current_bitmap_buf = (unsigned char *)(&bitmap_buffer[active_buffer_index][0]);
 199     cl = BG_COLOR(tc);
 200     CALC_YUV_LUMA_OPACITY_FOR_COLOR(cl,yuvclr[1],yuvclr[3]);
 201     CALC_YUV_CHROMA_FOR_COLOR(cl,yuvclr[0],yuvclr[2]);
 202     cl = FG_COLOR(tc);
 203     CALC_YUV_LUMA_OPACITY_FOR_COLOR(cl,yuvclr[5],yuvclr[7]);
 204     CALC_YUV_CHROMA_FOR_COLOR(cl,yuvclr[4],yuvclr[6]);
 205 }
 206 
 207 // px: bit0 unset for background, set for foreground
 208 static void draw_1pixel_simple(coord x, coord y, int px, int vrepeat)
 209 {
 210     if ((x < 0) || (y < 0) || (x >= camera_screen.width) || (y+vrepeat >= camera_screen.height)/* || ((x == 0) && (y == 0))*/) return;
 211     unsigned char *obu = current_opacity_buf;
 212     unsigned char *bbu = current_bitmap_buf;
 213     unsigned int offset = y * camera_screen.buffer_width + x;
 214     int plus = camera_screen.buffer_width;
 215     if (conf.rotate_osd)
 216     {
 217         offset = rotate_base - offset;
 218         plus = -plus;
 219     }
 220 
 221     if (!offset) return; // skip guard pixel
 222 
 223     int fg = px<<2;
 224     register unsigned int offs2 = (offset>>1)<<2;
 225     
 226     if (offset&1) // x is odd
 227     {
 228         while (1)
 229         {
 230             obu[offset] = yuvclr[fg+3];
 231             bbu[offs2+3] = yuvclr[fg+1]; // Y
 232             if (!vrepeat) return;
 233             vrepeat--;
 234             offset += plus;
 235             offs2 += (plus<<1);
 236         }
 237     }
 238     else // x is even
 239     {
 240         while (1)
 241         {
 242             obu[offset] = yuvclr[fg+3];
 243             bbu[offs2+1] = yuvclr[fg+1]; // Y
 244             bbu[offs2+0] = yuvclr[fg]; // U
 245             bbu[offs2+2] = yuvclr[fg+2]; // V
 246             if (!vrepeat) return;
 247             vrepeat--;
 248             offset += plus;
 249             offs2 += (plus<<1);
 250         }
 251     }
 252 
 253 }
 254 
 255 // px: 2 bits, describing 2 pixels (foreground when set, background when not), LSB is the second pixel
 256 // first pixel specifies chroma
 257 static void draw_2pixels_simple(coord x, coord y, int px, int vrepeat)
 258 {
 259     if ((x < 0) || (y < 0) || (x+1 >= camera_screen.width) || (y+vrepeat >= camera_screen.height)/* || ((x == 0) && (y == 0))*/) return;
 260     unsigned int y1, y2;
 261     unsigned int offset = (y * camera_screen.buffer_width + x)>>1;
 262     int plus;
 263     unsigned short co;
 264     unsigned int yuv;
 265     if (conf.rotate_osd)
 266     {
 267         offset = (rotate_base>>1) - offset;
 268         plus = -(camera_screen.buffer_width>>1);
 269         y1 = px&1?4:0;
 270         y2 = px&2?4+1:0+1;
 271     }
 272     else
 273     {
 274         plus = camera_screen.buffer_width>>1;
 275         y1 = px&2?4:0;
 276         y2 = px&1?4+1:0+1;
 277     }
 278 
 279     if (!offset) return; // skip guard pixel
 280 
 281     co = yuvclr[y1+3]+(yuvclr[y1+3]<<8);
 282     yuv = (*(unsigned int*)(&yuvclr[y1]) & 0xffffff) + (yuvclr[y2]<<24);
 283     unsigned short *obu = (unsigned short *)current_opacity_buf;
 284     unsigned int *bbu = (unsigned int *)current_bitmap_buf;
 285     while (1)
 286     {
 287         obu[offset] = co;
 288         bbu[offset] = yuv;
 289         if (!vrepeat) return;
 290         vrepeat--;
 291         offset += plus;
 292     }
 293 
 294 }
 295 
 296 void draw_hline_simple(coord x, coord y, int len, int px)
 297 {
 298     if ((y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height)) return;
 299     if (x < 0) { len += x; x = 0; }
 300     if ((x + len) > camera_screen.width) len = camera_screen.width - x;
 301     /*if ((x == 0) && (y == 0)) { x++; len--; }   // Skip guard pixel*/
 302 
 303     register unsigned int offset = y * camera_screen.buffer_width + (x);
 304     if (conf.rotate_osd)
 305     {
 306         offset = rotate_base - offset - len;
 307     }
 308 
 309     // Skip guard pixel
 310     if (!offset)
 311     {
 312         offset++;
 313         len--;
 314     }
 315 
 316     int fg = px<<2;
 317     if (offset & 1)
 318     {
 319         unsigned char *obu = current_opacity_buf;
 320         unsigned char *bbu = current_bitmap_buf;
 321         register unsigned int offs2 = (offset>>1)<<2;
 322         obu[offset] = yuvclr[fg+3];
 323         bbu[offs2+3] = yuvclr[fg+1]; // Y
 324         offset++;
 325         len--;
 326     }
 327     unsigned short co = yuvclr[fg+3]+(yuvclr[fg+3]<<8);
 328     unsigned int yuv = (*(unsigned int*)(&yuvclr[fg]) & 0xffffff) + (yuvclr[fg+1]<<24);
 329     unsigned short *obud = (unsigned short *)current_opacity_buf;
 330     unsigned int *bbud = (unsigned int *)current_bitmap_buf;
 331     for (; len>0; len-=2, offset+=2)
 332     {
 333         obud[offset>>1] = co;
 334         bbud[offset>>1] = yuv;
 335     }
 336     if (len == -1)
 337     {
 338         offset--;
 339         unsigned char *obu = current_opacity_buf;
 340         unsigned char *bbu = current_bitmap_buf;
 341         register unsigned int offs2 = (offset>>1)<<2;
 342         obu[offset] = yuvclr[fg+3];
 343         bbu[offs2+3] = yuvclr[fg+1]; // Y
 344     }
 345 }
 346 
 347 
 348 #endif // THUMB_FW
 349 //-------------------------------------------------------------------
 350 #ifndef THUMB_FW
 351 
 352 #define GUARD_VAL   COLOR_GREY_DK
 353 
 354 void draw_set_guard()
 355 {
 356 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 357     *((unsigned char*)(bitmap_buffer[0])) = GUARD_VAL;
 358     *((unsigned char*)(bitmap_buffer[1])) = GUARD_VAL;
 359 #else
 360     *((unsigned char*)(frame_buffer[0])) = GUARD_VAL;
 361     *((unsigned char*)(frame_buffer[1])) = GUARD_VAL;
 362 #endif
 363 }
 364 
 365 int draw_test_guard()
 366 {
 367 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 368     if (*((unsigned char*)(bitmap_buffer[active_bitmap_buffer])) != GUARD_VAL) return 0;
 369 #else
 370     if (*((unsigned char*)(frame_buffer[0])) != GUARD_VAL) return 0;
 371     if (*((unsigned char*)(frame_buffer[1])) != GUARD_VAL) return 0;
 372 #endif
 373     return 1;
 374 }
 375 
 376 #else // DIGIC 6
 377 
 378 void draw_set_guard()
 379 {
 380     opacity_buffer[active_bitmap_buffer][0] = 0x42;
 381 }
 382 
 383 int draw_test_guard()
 384 {
 385     if (opacity_buffer[active_bitmap_buffer][0] != 0x42) return 0;
 386     return 1;
 387 }
 388 
 389 #endif
 390 //-------------------------------------------------------------------
 391 void draw_init()
 392 {
 393 #ifndef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 394     frame_buffer[0] = vid_get_bitmap_fb();
 395     frame_buffer[1] = frame_buffer[0] + camera_screen.buffer_size;
 396 #endif
 397     draw_set_draw_proc(NULL);
 398 
 399     draw_set_guard();
 400 }
 401 
 402 // disable draw_restore for the ms milliseconds
 403 void draw_suspend(int ms)
 404 {
 405     int t=get_tick_count() + ms;
 406     // only change if not already suspended to a later time
 407     if(t > draw_restore_suspend_tick) {
 408         draw_restore_suspend_tick = t;
 409     }
 410 }
 411 // disable draw_restore for the ms milliseconds
 412 int draw_is_suspended(void)
 413 {
 414     return (draw_restore_suspend_tick > get_tick_count());
 415 }
 416 // Restore CANON_OSD
 417 //-------------------------------------------------------------------
 418 void draw_restore()
 419 {
 420     if(draw_is_suspended()) {
 421         return;
 422     }
 423     vid_bitmap_refresh();
 424 
 425     draw_set_guard();
 426 #ifdef CAM_TOUCHSCREEN_UI
 427     redraw_buttons = 1;
 428 #endif
 429 }
 430 
 431 //-------------------------------------------------------------------
 432 void draw_pixel(coord x, coord y, color cl)
 433 {
 434     // Make sure pixel is on screen. Skip top left pixel if screen erase detection is on to avoid triggering the detector.
 435     if ((x < 0) || (y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height) || ((x == 0) && (y == 0))) return;
 436     else
 437     {
 438         register unsigned int offset = y * camera_screen.buffer_width + ASPECT_XCORRECTION(x);
 439         draw_pixel_proc(offset,   cl);
 440 #if CAM_USES_ASPECT_CORRECTION
 441         draw_pixel_proc(offset+1, cl);  // Draw second pixel if screen scaling is needed
 442 #endif
 443    }
 444 }
 445 
 446 void draw_pixel_unrotated(coord x, coord y, color cl)
 447 {
 448     // Make sure pixel is on screen. Skip top left pixel if screen erase detection is on to avoid triggering the detector.
 449     if ((x < 0) || (y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height) || ((x == 0) && (y == 0))) return;
 450     else
 451     {
 452         register unsigned int offset = y * camera_screen.buffer_width + ASPECT_XCORRECTION(x);
 453         draw_pixel_proc_norm(offset,   cl);
 454 #if CAM_USES_ASPECT_CORRECTION
 455         draw_pixel_proc_norm(offset+1, cl);  // Draw second pixel if screen scaling is needed
 456 #endif
 457    }
 458 }
 459 
 460 //-------------------------------------------------------------------
 461 color draw_get_pixel(coord x, coord y)
 462 {
 463 #ifndef THUMB_FW
 464     if ((x < 0) || (y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height)) return 0;
 465     if (conf.rotate_osd)
 466     {
 467 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 468         return bitmap_buffer[0][rotate_base - (y * camera_screen.buffer_width + ASPECT_XCORRECTION(x))];
 469 #else
 470         return frame_buffer[0][rotate_base - (y * camera_screen.buffer_width + ASPECT_XCORRECTION(x))];
 471 #endif
 472     }
 473     else
 474     {
 475 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 476         return bitmap_buffer[0][y * camera_screen.buffer_width + ASPECT_XCORRECTION(x)];
 477 #else
 478         return frame_buffer[0][y * camera_screen.buffer_width + ASPECT_XCORRECTION(x)];
 479 #endif
 480     }
 481 #else
 482     // DIGIC 6 not supported
 483     (void)x; (void)y;
 484     return 0;
 485 #endif
 486 }
 487 
 488 color draw_get_pixel_unrotated(coord x, coord y)
 489 {
 490 #ifndef THUMB_FW
 491     if ((x < 0) || (y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height)) return 0;
 492 #ifdef DRAW_ON_ACTIVE_BITMAP_BUFFER_ONLY
 493     return bitmap_buffer[0][y * camera_screen.buffer_width + ASPECT_XCORRECTION(x)];
 494 #else
 495     return frame_buffer[0][y * camera_screen.buffer_width + ASPECT_XCORRECTION(x)];
 496 #endif
 497 #else
 498     // DIGIC 6 not supported
 499     (void)x; (void)y;
 500     return 0;
 501 #endif
 502 }
 503 
 504 //-------------------------------------------------------------------
 505 #define swap(v1, v2)   {v1^=v2; v2^=v1; v1^=v2;}
 506 //-------------------------------------------------------------------
 507 void draw_line(coord x1, coord y1, coord x2, coord y2, color cl)
 508 {
 509      unsigned char steep = abs(y2 - y1) > abs(x2 - x1);
 510      if (steep)
 511      {
 512          swap(x1, y1);
 513          swap(x2, y2);
 514      }
 515      if (x1 > x2)
 516      {
 517          swap(x1, x2);
 518          swap(y1, y2);
 519      }
 520      int deltax = x2 - x1;
 521      int deltay = abs(y2 - y1);
 522      int error = 0;
 523      int y = y1;
 524      int ystep = (y1 < y2)?1:-1;
 525      int x;
 526      for (x=x1; x<=x2; ++x)
 527      {
 528          if (steep) draw_pixel(y, x, cl);
 529          else draw_pixel(x, y, cl);
 530          error += deltay;
 531          if ((error<<1) >= deltax)
 532          {
 533              y += ystep;
 534              error -= deltax;
 535          }
 536      }
 537 }
 538 
 539 #ifdef THUMB_FW
 540 // Draw line scaled x2 in both X and Y co-ords. Used for drawing icons on high res screens
 541 void draw_line_x2(coord x1, coord y1, coord x2, coord y2, color cl)
 542 {
 543     unsigned char steep = abs(y2 - y1) > abs(x2 - x1);
 544     if (steep)
 545     {
 546         swap(x1, y1);
 547         swap(x2, y2);
 548     }
 549     if (x1 > x2)
 550     {
 551         swap(x1, x2);
 552         swap(y1, y2);
 553     }
 554     int deltax = x2 - x1;
 555     int deltay = abs(y2 - y1);
 556     int error = 0;
 557     int y = y1;
 558     int ystep = (y1 < y2)?2:-2;
 559     int x;
 560     for (x=x1; x<=x2; x+=2)
 561     {
 562         if (steep) {
 563             draw_pixel(y, x, cl);
 564             draw_pixel(y+1, x, cl);
 565             draw_pixel(y, x+1, cl);
 566             draw_pixel(y+1, x+1, cl);
 567         } else {
 568             draw_pixel(x, y, cl);
 569             draw_pixel(x+1, y, cl);
 570             draw_pixel(x, y+1, cl);
 571             draw_pixel(x+1, y+1, cl);
 572         }
 573         error += deltay;
 574         if ((error<<1) >= deltax)
 575         {
 576             y += ystep;
 577             error -= deltax;
 578         }
 579     }
 580 }
 581 #endif
 582 
 583 //-------------------------------------------------------------------
 584 void draw_hline(coord x, coord y, int len, color cl)
 585 {
 586     if ((y < 0) || (x >= camera_screen.width) || (y >= camera_screen.height)) return;
 587     if (x < 0) { len += x; x = 0; }
 588     if ((x + len) > camera_screen.width) len = camera_screen.width - x;
 589     if (conf.rotate_osd)
 590     {
 591         if ((y == camera_screen.height-1) && ((x+len) >= camera_screen.width-1)) { x--; len--; }   // Skip guard pixel
 592     }
 593     else
 594     {
 595         if ((y == 0) && (x == 0)) { x++; len--; }   // Skip guard pixel
 596     }
 597     register unsigned int offset = y * camera_screen.buffer_width + ASPECT_XCORRECTION(x);
 598     len = ASPECT_XCORRECTION(len);      // Scale the line length if needed
 599     for (; len>0; len--, offset++)
 600         draw_pixel_proc(offset, cl);
 601 }
 602 
 603 void draw_vline(coord x, coord y, int len, color cl)
 604 {
 605     if ((x < 0) || (x >= camera_screen.width) || (y >= camera_screen.height)) return;
 606     if (y < 0) { len += y; y = 0; }
 607     if ((y + len) > camera_screen.height) len = camera_screen.height - y;
 608     for (; len>0; len--, y++)
 609         draw_pixel(x, y, cl);
 610 }
 611 
 612 //-------------------------------------------------------------------
 613 // Generic rectangle
 614 // 'flags' defines type - filled, round corners, shadow and border thickness
 615 void draw_rectangle(coord x1, coord y1, coord x2, coord y2, twoColors cl, int flags)
 616 {
 617     // Normalise values
 618     if (x1 > x2)
 619         swap(x1, x2);
 620     if (y1 > y2)
 621         swap(y1, y2);
 622 
 623     // Check if completely off screen
 624     if ((x2 < 0) || (y2 < 0) || (x1 >= camera_screen.width) || (y1 >= camera_screen.height))
 625         return;
 626 
 627     int round = (flags & RECT_ROUND_CORNERS) ? 1 : 0;
 628     int thickness;
 629     int i;
 630 
 631     // Shadow (do this first, as edge draw shrinks rectangle for fill)
 632     if (flags & RECT_SHADOW_MASK)
 633     {
 634         thickness = ((flags & RECT_SHADOW_MASK) >> 4);
 635         for (i=1; i<=thickness; i++)
 636         {
 637             draw_vline(x2+i, y1+1, y2 - y1, COLOR_BLACK);
 638             draw_hline(x1+1, y2+i, x2 - x1 + thickness, COLOR_BLACK);
 639         }
 640     }
 641 
 642     // Edge
 643     thickness = flags & RECT_BORDER_MASK;
 644     for (i=0; i<thickness; i++)
 645     {
 646         // Clipping done in draw_hline and draw_vline
 647         draw_vline(x1, y1 + round * 2, y2 - y1 - round * 4 + 1, FG_COLOR(cl));
 648         draw_vline(x2, y1 + round * 2, y2 - y1 - round * 4 + 1, FG_COLOR(cl));
 649         draw_hline(x1 + 1 + round, y1, x2 - x1 - round * 2 - 1, FG_COLOR(cl));
 650         draw_hline(x1 + 1 + round, y2, x2 - x1 - round * 2 - 1, FG_COLOR(cl));
 651 
 652         x1++; x2--;
 653         y1++; y2--;
 654 
 655         round = 0;
 656     }
 657 
 658     // Fill
 659     if (flags & DRAW_FILLED)
 660     {
 661         // Clip values
 662         if (x1 < 0) x1 = 0;
 663         if (y1 < 0) y1 = 0;
 664         if (x2 >= camera_screen.width)  x2 = camera_screen.width - 1;
 665         if (y2 >= camera_screen.height) y2 = camera_screen.height - 1;
 666 
 667         coord y;
 668         for (y = y1; y <= y2; ++y)
 669             draw_hline(x1, y, x2 - x1 + 1, BG_COLOR(cl));
 670     }
 671 }
 672 
 673 //-------------------------------------------------------------------
 674 #pragma pack(1)
 675 // Format of header block for each character in the 'font_data' array
 676 // This is immediately followed by '16 - top - bottom' bytes of character data.
 677 typedef struct {
 678     unsigned char skips;    // Top and Bottom skip counts for blank rows (4 bits each - ((top << 4) | bottom))
 679 } FontData;
 680 #pragma pack()
 681 
 682 static unsigned char* get_cdata(unsigned int *offset, unsigned int *size, const char ch)
 683 {
 684     FontData *f = (FontData*)get_current_font_data(ch);
 685 
 686     *offset = f->skips >> 4;            // # of blank lines at top
 687     *size = 16 - (f->skips & 0xF);      // last line of non-blank data
 688     if (*size == *offset)               // special case for blank char (top == 15 && bottom == 1)
 689         *offset += 1;
 690 
 691     return (unsigned char*)f + sizeof(FontData) - *offset;
 692 }
 693 
 694 #ifndef THUMB_FW
 695 // DIGIC II...5
 696 void draw_char(coord x, coord y, const char ch, twoColors cl)
 697 {
 698     unsigned i, ii;
 699 
 700     unsigned int offset, size;
 701     unsigned char *sym = get_cdata(&offset, &size, ch);
 702 
 703     // First draw blank lines at top
 704     for (i=0; i<offset; i++)
 705         draw_hline(x, y+i, FONT_WIDTH, BG_COLOR(cl));
 706 
 707     // Now draw character data
 708 
 709     unsigned j;
 710     for (j=i; i<size;)
 711     {
 712         unsigned int dsym;
 713         int rep;
 714 #ifdef BUILTIN_FONT_RLE_COMPRESSED
 715         dsym = fontdata_lookup[sym[j] & 0x7f];
 716         rep = sym[j] & 0x80;
 717 #else
 718         dsym = sym[j];
 719         rep = 0;
 720 #endif
 721         for (ii=0; ii<FONT_WIDTH; ii++)
 722         {
 723             draw_pixel(x+ii, y+i, (dsym & (0x80>>ii))? FG_COLOR(cl) : BG_COLOR(cl));
 724         }
 725         if (rep)
 726         {
 727             i++;
 728             for (ii=0; ii<FONT_WIDTH; ii++)
 729             {
 730                 draw_pixel(x+ii, y+i, (dsym & (0x80>>ii))? FG_COLOR(cl) : BG_COLOR(cl));
 731             }
 732         }
 733         i++;
 734         j++;
 735     }
 736 
 737     // Last draw blank lines at bottom
 738     for (; i<FONT_HEIGHT; i++)
 739         draw_hline(x, y+i, FONT_WIDTH, BG_COLOR(cl));
 740 }
 741 #endif
 742 
 743 #ifdef THUMB_FW
 744 // DIGIC 6: "optimizations" to improve speed
 745 void draw_char(coord x, coord y, const char ch, twoColors cl)
 746 {
 747     unsigned i, ii;
 748 
 749     unsigned int offset, size;
 750     unsigned char *sym = get_cdata(&offset, &size, ch);
 751 //     color fg = FG_COLOR(cl);
 752 //     color bg = BG_COLOR(cl);
 753     unsigned int fw = FONT_WIDTH;
 754 
 755     draw_pixel_simple_start(cl);
 756 
 757     // First draw blank lines at top
 758     for (i=0; i<offset; i++)
 759     {
 760         int j;
 761         j = i<<1;
 762         draw_hline_simple(x, y+j, fw, 0);
 763         draw_hline_simple(x, y+j+1, fw, 0);
 764     }
 765 
 766     // Now draw character data
 767 
 768     unsigned j;
 769     for (j=i; i<size;)
 770     {
 771         unsigned int dsym;
 772         int rep;
 773 #ifdef BUILTIN_FONT_RLE_COMPRESSED
 774         dsym = fontdata_lookup[sym[j] & 0x7f];
 775         rep = sym[j] & 0x80;
 776 #else
 777         dsym = sym[j];
 778         rep = 0;
 779 #endif
 780         {
 781             // upscaling 8 pixels to 14
 782             ii = 0;
 783             ii += (dsym&1)?3:0;
 784             ii += (dsym&2)?4:0;
 785             ii += (dsym&4)?0x18:0;
 786             ii += (dsym&8)?0x60:0;
 787             ii += (dsym&16)?0x180:0;
 788             ii += (dsym&32)?0x600:0;
 789             ii += (dsym&64)?0x1800:0;
 790             ii += (dsym&128)?0x2000:0;
 791             dsym = ii;
 792         }
 793 
 794         while (rep >= 0)
 795         {
 796             unsigned int px;
 797             unsigned int yt = y+(i<<1);
 798             ii = 0;
 799             if (x&1)
 800             {
 801                 draw_1pixel_simple(x+ii, yt, dsym>>(fw-1), 1);
 802                 ii++;
 803             }
 804             for (; ii<fw; ii+=2)
 805             {
 806                 px = (dsym & ((3<<(fw-2))>>ii))>>(fw-2-ii);
 807                 draw_2pixels_simple(x+ii, yt, px, 1);
 808             }
 809             if (x&1)
 810             {
 811                 draw_1pixel_simple(x+ii-1, yt, dsym&1, 1);
 812             }
 813             rep -= 0x80;
 814             i++;
 815         }
 816 
 817         j++;
 818     }
 819 
 820     // Last draw blank lines at bottom
 821     for (; i<FONT_REAL_HEIGHT; i++)
 822     {
 823         int j;
 824         j = i<<1;
 825         draw_hline_simple(x, y+j, fw, 0);
 826         draw_hline_simple(x, y+j+1, fw, 0);
 827     }
 828 }
 829 
 830 void draw_char_unscaled(coord x, coord y, const char ch, twoColors cl)
 831 {
 832     unsigned i, ii;
 833 
 834     unsigned int offset, size;
 835     unsigned char *sym = get_cdata(&offset, &size, ch);
 836 //     color fg = FG_COLOR(cl);
 837 //     color bg = BG_COLOR(cl);
 838     unsigned int fw = FONT_REAL_WIDTH;
 839 
 840     draw_pixel_simple_start(cl);
 841 
 842     // First draw blank lines at top
 843     for (i=0; i<offset; i++)
 844     {
 845         draw_hline_simple(x, y+i, fw, 0);
 846     }
 847 
 848     // Now draw character data
 849 
 850     unsigned j;
 851     for (j=i; i<size;)
 852     {
 853         unsigned int dsym;
 854         int rep;
 855 #ifdef BUILTIN_FONT_RLE_COMPRESSED
 856         dsym = fontdata_lookup[sym[j] & 0x7f];
 857         rep = sym[j] & 0x80;
 858 #else
 859         dsym = sym[j];
 860         rep = 0;
 861 #endif
 862 
 863         while (rep >= 0)
 864         {
 865             unsigned int px;
 866             unsigned int yt = y+(i);
 867             ii = 0;
 868             if (x&1)
 869             {
 870                 draw_1pixel_simple(x+ii, yt, dsym>>(fw-1), 0);
 871                 ii++;
 872             }
 873             for (; ii<fw; ii+=2)
 874             {
 875                 px = (dsym & ((3<<(fw-2))>>ii))>>(fw-2-ii);
 876                 draw_2pixels_simple(x+ii, yt, px, 0);
 877             }
 878             if (x&1)
 879             {
 880                 draw_1pixel_simple(x+ii-1, yt, dsym&1, 0);
 881             }
 882             rep -= 0x80;
 883             i++;
 884         }
 885 
 886         j++;
 887     }
 888 
 889     // Last draw blank lines at bottom
 890     for (; i<FONT_REAL_HEIGHT; i++)
 891     {
 892         draw_hline_simple(x, y+i, fw, 0);
 893     }
 894 }
 895 
 896 #endif // THUMB_FW
 897 
 898 #ifndef THUMB_FW
 899 void draw_char_scaled(coord x, coord y, const char ch, twoColors cl, int xsize, int ysize)
 900 {
 901     unsigned i, ii;
 902 
 903     twoColors clf = MAKE_COLOR(FG_COLOR(cl),FG_COLOR(cl));
 904     twoColors clb = MAKE_COLOR(BG_COLOR(cl),BG_COLOR(cl));
 905 
 906     unsigned int offset, size;
 907     unsigned char *sym = get_cdata(&offset, &size, ch);
 908 
 909     // First draw blank lines at top
 910     if (offset > 0)
 911         draw_rectangle(x,y,x+FONT_WIDTH*xsize-1,y+offset*ysize+ysize-1,clb,RECT_BORDER0|DRAW_FILLED);
 912 
 913     // Now draw character data
 914     unsigned j;
 915     for (j=i=offset; i<size;)
 916     {
 917         unsigned int dsym;
 918         int rep;
 919         unsigned int last;
 920         int len;
 921 #ifdef BUILTIN_FONT_RLE_COMPRESSED
 922         dsym = fontdata_lookup[sym[j] & 0x7f];
 923         rep = sym[j] & 0x80;
 924 #else
 925         dsym = sym[j];
 926         rep = 0;
 927 #endif
 928         while (rep >= 0)
 929         {
 930             last = dsym & 0x80;
 931             len = 1;
 932             for (ii=1; ii<FONT_WIDTH; ii++)
 933             {
 934                 if (((dsym << ii) & 0x80) != last)
 935                 {
 936                     draw_rectangle(x+(ii-len)*xsize,y+i*ysize,x+ii*xsize-1,y+i*ysize+ysize-1,(last)?clf:clb,RECT_BORDER0|DRAW_FILLED);
 937                     last = (dsym << ii) & 0x80;
 938                     len = 1;
 939                 }
 940                 else
 941                 {
 942                     len++;
 943                 }
 944             }
 945             draw_rectangle(x+(ii-len)*xsize,y+i*ysize,x+ii*xsize-1,y+i*ysize+ysize-1,(last)?clf:clb,RECT_BORDER0|DRAW_FILLED);
 946             i++;
 947             rep -= 0x80;
 948         }
 949         j++;
 950     }
 951 
 952     // Last draw blank lines at bottom
 953     if (i < FONT_HEIGHT)
 954         draw_rectangle(x,y+i*ysize,x+FONT_WIDTH*xsize-1,y+FONT_HEIGHT*ysize+ysize-1,clb,RECT_BORDER0|DRAW_FILLED);
 955 }
 956 #endif // !THUMB_FW
 957 
 958 #ifdef THUMB_FW
 959 void draw_char_scaled(coord x, coord y, const char ch, twoColors cl, int xsize, int ysize)
 960 {
 961     unsigned i, ii;
 962 
 963     twoColors clf = MAKE_COLOR(FG_COLOR(cl),FG_COLOR(cl));
 964     twoColors clb = MAKE_COLOR(BG_COLOR(cl),BG_COLOR(cl));
 965 
 966     unsigned int offset, size;
 967     unsigned char *sym = get_cdata(&offset, &size, ch);
 968 
 969     ysize <<= 1;
 970 
 971     // First draw blank lines at top
 972     if (offset > 0)
 973         draw_rectangle(x,y,x+FONT_WIDTH*xsize-1,y+offset*ysize+ysize-1,clb,RECT_BORDER0|DRAW_FILLED);
 974 
 975     // Now draw character data
 976     unsigned j;
 977     for (j=i=offset; i<size;)
 978     {
 979         unsigned int dsym;
 980         int rep;
 981         unsigned int last;
 982         int len;
 983         unsigned int lastmask = 1 << (FONT_WIDTH-1);
 984 #ifdef BUILTIN_FONT_RLE_COMPRESSED
 985         dsym = fontdata_lookup[sym[j] & 0x7f];
 986         rep = sym[j] & 0x80;
 987 #else
 988         dsym = sym[j];
 989         rep = 0;
 990 #endif
 991         {
 992             // upscaling 8 pixels to 14
 993             ii = 0;
 994             ii += (dsym&1)?3:0;
 995             ii += (dsym&2)?4:0;
 996             ii += (dsym&4)?0x18:0;
 997             ii += (dsym&8)?0x60:0;
 998             ii += (dsym&16)?0x180:0;
 999             ii += (dsym&32)?0x600:0;
1000             ii += (dsym&64)?0x1800:0;
1001             ii += (dsym&128)?0x2000:0;
1002             dsym = ii;
1003         }
1004         while (rep >= 0)
1005         {
1006             last = dsym & lastmask;
1007             len = 1;
1008             for (ii=1; ii<FONT_WIDTH; ii++)
1009             {
1010                 if (((dsym << ii) & lastmask) != last)
1011                 {
1012                     draw_rectangle(x+(ii-len)*xsize,y+i*ysize,x+ii*xsize-1,y+i*ysize+ysize-1,(last)?clf:clb,RECT_BORDER0|DRAW_FILLED);
1013                     last = (dsym << ii) & lastmask;
1014                     len = 1;
1015                 }
1016                 else
1017                 {
1018                     len++;
1019                 }
1020             }
1021             draw_rectangle(x+(ii-len)*xsize,y+i*ysize,x+ii*xsize-1,y+i*ysize+ysize-1,(last)?clf:clb,RECT_BORDER0|DRAW_FILLED);
1022             i++;
1023             rep -= 0x80;
1024         }
1025         j++;
1026     }
1027 
1028     // Last draw blank lines at bottom
1029     if (i < FONT_REAL_HEIGHT)
1030         draw_rectangle(x,y+i*ysize,x+FONT_WIDTH*xsize-1,y+FONT_REAL_HEIGHT*ysize+ysize-1,clb,RECT_BORDER0|DRAW_FILLED);
1031 }
1032 #endif // THUMB_FW
1033 //-------------------------------------------------------------------
1034 // String & text functions
1035 
1036 // Draw a single line string up to a maximum pixel width
1037 int draw_string_clipped(coord x, coord y, const char *s, twoColors cl, int max_width)
1038 {
1039     while (*s && (*s != '\n') && (max_width >= FONT_WIDTH))
1040     {
1041             draw_char(x, y, *s, cl);
1042             s++;
1043         max_width -= FONT_WIDTH;
1044             x += FONT_WIDTH;
1045             if ((x>=camera_screen.width) && (*s))
1046         {
1047                 draw_char(x-FONT_WIDTH,y, '>', cl);
1048                 break;
1049             }
1050     }
1051     return x;
1052 }
1053 
1054 // Draw a single line string
1055 int draw_string(coord x, coord y, const char *s, twoColors cl)
1056 {
1057     return draw_string_clipped(x, y, s, cl, camera_screen.width);
1058 }
1059 
1060 // Draw a single line string:
1061 //      - xo = left offset to start text (only applies to left justified text)
1062 //      - max_width = maximum pixel width to use (staring from x)
1063 //      - justification = left, center or right justified, also controls if unused area to be filled with background color
1064 // Returns x position of first character drawn
1065 int draw_string_justified(coord x, coord y, const char *s, twoColors cl, int xo, int max_width, int justification)
1066 {
1067     // Get length in pixels
1068     const char *e = strchr(s, '\n');
1069     int l;
1070     if (e)
1071         l = (e - s) * FONT_WIDTH;
1072     else
1073         l = strlen(s) * FONT_WIDTH;
1074     if (l > max_width) l = max_width;
1075 
1076     // Calculate justification offset
1077     switch (justification & 0xF)
1078     {
1079     case TEXT_RIGHT:
1080         xo = (max_width - l);
1081         break;
1082     case TEXT_CENTER:
1083         xo = ((max_width - l) >> 1);
1084         break;
1085     }
1086 
1087     // Fill left side
1088     if ((justification & TEXT_FILL) && (xo > 0))
1089         draw_rectangle(x, y, x+xo-1, y+FONT_HEIGHT-1, cl, RECT_BORDER0|DRAW_FILLED);
1090 
1091     // Draw string (get length drawn in pixels)
1092     l = draw_string_clipped(x+xo, y, s, cl, max_width - xo) - x;
1093 
1094     // Fill right side
1095     if ((justification & TEXT_FILL) && (l < max_width))
1096         draw_rectangle(x+l, y, x+max_width-1, y+FONT_HEIGHT-1, cl, RECT_BORDER0|DRAW_FILLED);
1097 
1098     // Return start of first character
1099     return x+xo;
1100 }
1101 
1102 // Calculate the max line length and number of lines of a multi line string
1103 // Lines are separated by newline '\n' characters
1104 // Returns:
1105 //      - max line length (return value)
1106 //      - number of lines (in *max_lines)
1107 int text_dimensions(const char *s, int width, int max_chars, int *max_lines)
1108 {
1109     int l = 0, n;
1110     while (s && *s && (l < *max_lines))
1111     {
1112         const char *e = strchr(s, '\n');
1113         if (e)
1114         {
1115             n = e - s;
1116             e++;
1117         }
1118         else
1119         {
1120             n = strlen(s);
1121         }
1122 
1123         if (n > width) width = n;
1124 
1125         s = e;
1126         l++;
1127     }
1128     *max_lines = l;
1129     if (width > max_chars) width = max_chars;
1130     return width;
1131 }
1132 
1133 // Draw multi-line text string:
1134 //      - max_chars = max # of chars to draw
1135 //      - max_lines = max # of lines to draw
1136 //      - justification = left, center or right justified, with optional fill of unused space
1137 // Returns x position of first character on last line
1138 int draw_text_justified(coord x, coord y, const char *s, twoColors cl, int max_chars, int max_lines, int justification)
1139 {
1140     int rx = 0;
1141     while (s && *s && (max_lines > 0))
1142     {
1143         const char *e = strchr(s, '\n');
1144         if (e) e++;
1145 
1146         rx = draw_string_justified(x, y, s, cl, 0, max_chars*FONT_WIDTH, justification);
1147 
1148         s = e;
1149         y += FONT_HEIGHT;
1150         max_lines--;
1151     }
1152     return rx;
1153 }
1154 
1155 // Draw single line string, with optiona X and Y scaling
1156 #ifndef THUMB_FW
1157 void draw_string_scaled(coord x, coord y, const char *s, twoColors cl, int xsize, int ysize)
1158 {
1159     while (*s && (*s != '\n'))
1160     {
1161         draw_char_scaled(x, y, *s, cl, xsize, ysize);
1162         s++;
1163         x+=FONT_WIDTH*xsize;
1164         if ((x>=camera_screen.width) && (*s))
1165         {
1166             draw_char_scaled(x-FONT_WIDTH*xsize,y, '>', cl, xsize, ysize);
1167             break;
1168         }
1169     }
1170 }
1171 #endif
1172 
1173 #ifdef THUMB_FW
1174 void draw_string_scaled(coord x, coord y, const char *s, twoColors cl, int xsize, int ysize)
1175 {
1176     if ((xsize==0) || (ysize==0))
1177     {
1178         while (*s && (*s != '\n'))
1179         {
1180             draw_char_unscaled(x, y, *s, cl);
1181             s++;
1182             x+=FONT_REAL_WIDTH;
1183             if ((x>=camera_screen.width) && (*s))
1184             {
1185                 draw_char_unscaled(x-FONT_REAL_WIDTH,y, '>', cl);
1186                 break;
1187             }
1188         }
1189     }
1190     else
1191     {
1192         while (*s && (*s != '\n'))
1193         {
1194             draw_char_scaled(x, y, *s, cl, xsize, ysize);
1195             s++;
1196             x+=FONT_WIDTH*xsize;
1197             if ((x>=camera_screen.width) && (*s))
1198             {
1199                 draw_char_scaled(x-FONT_WIDTH*xsize,y, '>', cl, xsize, ysize);
1200                 break;
1201             }
1202         }
1203     }
1204 }
1205 #endif
1206 
1207 // Draw CHDK OSD string at user defined position and scale
1208 #ifndef THUMB_FW
1209 void draw_osd_string(OSD_pos pos, int xo, int yo, char *s, twoColors c, OSD_scale scale)
1210 {
1211     if ((scale.x == 0) || (scale.y == 0) || ((scale.x == 1) && (scale.y == 1)))
1212         draw_string(pos.x+xo, pos.y+yo, s, c);
1213     else
1214         draw_string_scaled(pos.x+(xo*scale.x), pos.y+(yo*scale.y), s, c, scale.x, scale.y);
1215 }
1216 #endif
1217 
1218 #ifdef THUMB_FW
1219 void draw_osd_string(OSD_pos pos, int xo, int yo, char *s, twoColors c, OSD_scale scale)
1220 {
1221     if ((scale.x == 1) && (scale.y == 1))
1222     {
1223         draw_string(pos.x+xo, pos.y+yo, s, c);
1224     }
1225     else if ((scale.x == 0) || (scale.y == 0))
1226     {
1227         draw_string_scaled(pos.x+(xo>>1), pos.y+(yo>>1), s, c, scale.x, scale.y);
1228     }
1229     else
1230     {
1231         draw_string_scaled(pos.x+(xo*scale.x), pos.y+(yo*scale.y), s, c, scale.x, scale.y);
1232     }
1233 }
1234 #endif
1235 
1236 //-------------------------------------------------------------------
1237 // Draw single line string at 'character' screen position (row, col)
1238 // Pixel co-ordinate conversion --> x = col * FONT_WIDTH, y = row * FONT_HEIGHT
1239 void draw_txt_string(coord col, coord row, const char *str, twoColors cl)
1240 {
1241     draw_string(col*FONT_WIDTH, row*FONT_HEIGHT, str, cl);
1242 }
1243 
1244 //-------------------------------------------------------------------
1245 // *** Not used ***
1246 //void draw_circle(coord x, coord y, const unsigned int r, color cl)
1247 //{
1248 //    int dx = 0;
1249 //    int dy = r;
1250 //    int p=(3-(r<<1));
1251 //
1252 //    do {
1253 //        draw_pixel((x+dx),(y+dy),cl);
1254 //        draw_pixel((x+dy),(y+dx),cl);
1255 //        draw_pixel((x+dy),(y-dx),cl);
1256 //        draw_pixel((x+dx),(y-dy),cl);
1257 //        draw_pixel((x-dx),(y-dy),cl);
1258 //        draw_pixel((x-dy),(y-dx),cl);
1259 //        draw_pixel((x-dy),(y+dx),cl);
1260 //        draw_pixel((x-dx),(y+dy),cl);
1261 //
1262 //        ++dx;
1263 //
1264 //        if (p<0)
1265 //            p += ((dx<<2)+6);
1266 //        else {
1267 //            --dy;
1268 //            p += (((dx-dy)<<2)+10);
1269 //        }
1270 //    } while (dx<=dy);
1271 //}
1272 
1273 //-------------------------------------------------------------------
1274 void draw_ellipse(coord CX, coord CY, unsigned int XRadius, unsigned int YRadius, color cl, int flags)
1275 {
1276     // Bresenham fast ellipse algorithm - http://homepage.smc.edu/kennedy_john/BELIPSE.PDF
1277     int X, Y;
1278     int XChange, YChange;
1279     int EllipseError;
1280     int TwoASquare, TwoBSquare;
1281     int StoppingX, StoppingY;
1282     TwoASquare = 2*XRadius*XRadius;
1283     TwoBSquare = 2*YRadius*YRadius;
1284     X = XRadius;
1285     Y = 0;
1286     XChange = YRadius*YRadius*(1-2*XRadius);
1287     YChange = XRadius*XRadius;
1288     EllipseError = 0;
1289     StoppingX = TwoBSquare*XRadius;
1290     StoppingY = 0;
1291     while ( StoppingX >= StoppingY ) 
1292     {
1293         if (flags & DRAW_FILLED)
1294         {
1295             draw_hline(CX-X,CY-Y,X*2+1,cl);
1296             draw_hline(CX-X,CY+Y,X*2+1,cl);
1297         }
1298         else
1299         {
1300             draw_pixel(CX-X,CY-Y,cl);
1301             draw_pixel(CX-X,CY+Y,cl);
1302             draw_pixel(CX+X,CY-Y,cl);
1303             draw_pixel(CX+X,CY+Y,cl);
1304         }
1305         Y++;
1306         StoppingY += TwoASquare;
1307         EllipseError += YChange;
1308         YChange += TwoASquare;
1309         if ((2*EllipseError + XChange) > 0 )
1310         {
1311             X--;
1312             StoppingX -= TwoBSquare;
1313             EllipseError += XChange;
1314             XChange += TwoBSquare;
1315         }
1316     }
1317     X = 0;
1318     Y = YRadius;
1319     XChange = YRadius*YRadius;
1320     YChange = XRadius*XRadius*(1-2*YRadius);
1321     EllipseError = 0;
1322     StoppingX = 0;
1323     StoppingY = TwoASquare*YRadius;
1324     int lastY = Y + 1;
1325     while ( StoppingX <= StoppingY )
1326     {
1327         if (flags & DRAW_FILLED)
1328         {
1329             // Only draw lines if Y has changed
1330             if (lastY != Y)
1331             {
1332                 draw_hline(CX-X,CY-Y,X*2+1,cl);
1333                 draw_hline(CX-X,CY+Y,X*2+1,cl);
1334                 lastY = Y;
1335             }
1336         }
1337         else
1338         {
1339             draw_pixel(CX-X,CY-Y,cl);
1340             draw_pixel(CX-X,CY+Y,cl);
1341             draw_pixel(CX+X,CY-Y,cl);
1342             draw_pixel(CX+X,CY+Y,cl);
1343         }
1344         X++;
1345         StoppingX += TwoBSquare;
1346         EllipseError += XChange;
1347         XChange += TwoBSquare;
1348         if ((2*EllipseError + YChange) > 0 )
1349         {
1350             Y--;
1351             StoppingY -= TwoASquare;
1352             EllipseError += YChange;
1353             YChange += TwoASquare;
1354         }
1355     }
1356 }
1357 
1358 //-------------------------------------------------------------------
1359 // Draw a button
1360 void draw_button(int x, int y, int w, int str_id, int active)
1361 {
1362     twoColors cl = MAKE_COLOR((active) ? COLOR_RED : COLOR_BLACK, COLOR_WHITE);
1363     w = w * FONT_WIDTH;
1364 
1365     draw_rectangle(x-2, y-2, x+w+2, y+FONT_HEIGHT+2, cl, RECT_BORDER1|DRAW_FILLED|RECT_SHADOW1);     // main box
1366     draw_string(x+((w-(strlen(lang_str(str_id))*FONT_WIDTH))>>1), y, lang_str(str_id), cl);
1367 }
1368 
1369 //-------------------------------------------------------------------
1370 // Draw an OSD icon from an array of actions
1371 // For THUMB_FW scale up by 2 times and draw double thickness
1372 void draw_icon_cmds(coord x, coord y, icon_cmd *cmds)
1373 {
1374     int x1, y1, x2, y2;
1375 #ifdef THUMB_FW
1376     int thickness = RECT_BORDER2;
1377 #else
1378     int thickness = RECT_BORDER1;
1379 #endif
1380     while (1)
1381     {
1382 #ifdef THUMB_FW
1383         x1 = cmds->x1<<1;
1384         y1 = cmds->y1<<1;
1385         x2 = cmds->x2<<1;
1386         y2 = cmds->y2<<1;
1387 #else
1388         x1 = cmds->x1;
1389         y1 = cmds->y1;
1390         x2 = cmds->x2;
1391         y2 = cmds->y2;
1392 #endif
1393         color cf = chdk_colors[cmds->cf];       // Convert color indexes to actual colors
1394         color cb = chdk_colors[cmds->cb];
1395         switch (cmds->action)
1396         {
1397         default:
1398         case IA_END:
1399             return;
1400         case IA_HLINE:
1401             draw_hline(x+x1, y+y1, x2, cb);
1402 #ifdef THUMB_FW
1403             draw_hline(x+x1, y+y1+1, x2, cb);
1404 #endif
1405             break;
1406         case IA_VLINE:
1407             draw_vline(x+x1, y+y1, y2, cb);
1408 #ifdef THUMB_FW
1409             draw_vline(x+x1+1, y+y1, y2, cb);
1410 #endif
1411             break;
1412         case IA_LINE:
1413 #ifdef THUMB_FW
1414             draw_line_x2(x+x1, y+y1, x+x2, y+y2, cb);
1415 #else
1416             draw_line(x+x1, y+y1, x+x2, y+y2, cb);
1417 #endif
1418             break;
1419         case IA_RECT:
1420 #ifdef THUMB_FW
1421             draw_rectangle(x+x1, y+y1, x+x2+1, y+y2+1, MAKE_COLOR(cb,cf), thickness);
1422 #else
1423             draw_rectangle(x+x1, y+y1, x+x2, y+y2, MAKE_COLOR(cb,cf), thickness);
1424 #endif
1425             break;
1426         case IA_FILLED_RECT:
1427 #ifdef THUMB_FW
1428             draw_rectangle(x+x1, y+y1, x+x2+1, y+y2+1, MAKE_COLOR(cb,cf), thickness|DRAW_FILLED);
1429 #else
1430             draw_rectangle(x+x1, y+y1, x+x2, y+y2, MAKE_COLOR(cb,cf), thickness|DRAW_FILLED);
1431 #endif
1432             break;
1433         case IA_ROUND_RECT:
1434 #ifdef THUMB_FW
1435             draw_rectangle(x+x1, y+y1, x+x2+1, y+y2+1, MAKE_COLOR(cb,cf), thickness|RECT_ROUND_CORNERS);
1436 #else
1437             draw_rectangle(x+x1, y+y1, x+x2, y+y2, MAKE_COLOR(cb,cf), thickness|RECT_ROUND_CORNERS);
1438 #endif
1439             break;
1440         case IA_FILLED_ROUND_RECT:
1441 #ifdef THUMB_FW
1442             draw_rectangle(x+x1, y+y1, x+x2+1, y+y2+1, MAKE_COLOR(cb,cf), thickness|DRAW_FILLED|RECT_ROUND_CORNERS);
1443 #else
1444             draw_rectangle(x+x1, y+y1, x+x2, y+y2, MAKE_COLOR(cb,cf), thickness|DRAW_FILLED|RECT_ROUND_CORNERS);
1445 #endif
1446             break;
1447         }
1448         cmds++;
1449     }
1450 }
1451 
1452 //-------------------------------------------------------------------
1453 
1454 extern unsigned char ply_colors[];
1455 extern unsigned char rec_colors[];
1456 
1457 unsigned char *chdk_colors = ply_colors;
1458 
1459 void set_palette()
1460 {
1461 #ifndef THUMB_FW
1462     if (camera_info.state.mode_rec)
1463         chdk_colors = rec_colors;
1464     else
1465         chdk_colors = ply_colors;
1466 #endif
1467 }
1468 
1469 color get_script_color(int cl)
1470 {
1471     if (cl < 256)
1472         return cl;
1473     else
1474         return chdk_colors[cl-256];
1475 }
1476 
1477 // Convert user adjustable color (from conf struct) to Canon colors
1478 color chdkColorToCanonColor(chdkColor col)
1479 {
1480     if (col.type)
1481         return chdk_colors[col.col];
1482     return col.col;
1483 }
1484 
1485 twoColors user_color(confColor cc)
1486 {
1487     color fg = chdkColorToCanonColor(cc.fg);
1488     color bg = chdkColorToCanonColor(cc.bg);
1489 
1490     return MAKE_COLOR(bg,fg);
1491 }
1492 
1493 //-------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */