summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-recorder.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-recorder.c')
-rw-r--r--firmware/drivers/lcd-recorder.c374
1 files changed, 238 insertions, 136 deletions
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index 52455a1ff5..16a47f28bf 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -77,6 +77,7 @@
77 77
78unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH]; 78unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH];
79 79
80static int drawmode = DRMODE_SOLID;
80static int xmargin = 0; 81static int xmargin = 0;
81static int ymargin = 0; 82static int ymargin = 0;
82static int curfont = FONT_SYSFIXED; 83static int curfont = FONT_SYSFIXED;
@@ -84,11 +85,6 @@ static int curfont = FONT_SYSFIXED;
84static int xoffset; /* needed for flip */ 85static int xoffset; /* needed for flip */
85#endif 86#endif
86 87
87/* All zeros and ones bitmaps for area filling */
88static const unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
89static const unsigned char ones[8] = { 0xff, 0xff, 0xff, 0xff,
90 0xff, 0xff, 0xff, 0xff};
91
92/* scrolling */ 88/* scrolling */
93static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ 89static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
94static void scroll_thread(void); 90static void scroll_thread(void);
@@ -335,6 +331,16 @@ void lcd_update_rect(int x_start, int y, int width, int height)
335 331
336/*** parameter handling ***/ 332/*** parameter handling ***/
337 333
334void lcd_set_drawmode(int mode)
335{
336 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
337}
338
339int lcd_get_drawmode(void)
340{
341 return drawmode;
342}
343
338void lcd_setmargins(int x, int y) 344void lcd_setmargins(int x, int y)
339{ 345{
340 xmargin = x; 346 xmargin = x;
@@ -361,103 +367,75 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
361 return font_getstringsize(str, w, h, curfont); 367 return font_getstringsize(str, w, h, curfont);
362} 368}
363 369
364/*** drawing functions ***/ 370/*** low-level drawing functions ***/
365 371
366void lcd_clear_display(void) 372static void setpixel(int x, int y)
367{ 373{
368 memset (lcd_framebuffer, 0, sizeof lcd_framebuffer); 374 lcd_framebuffer[y/8][x] |= 1 << (y & 7);
369 scrolling_lines = 0;
370} 375}
371 376
372/* Set a single pixel */ 377static void clearpixel(int x, int y)
373void lcd_drawpixel(int x, int y)
374{ 378{
375 DRAW_PIXEL(x,y); 379 lcd_framebuffer[y/8][x] &= ~(1 << (y & 7));
376} 380}
377 381
378/* Clear a single pixel */ 382static void flippixel(int x, int y)
379void lcd_clearpixel(int x, int y)
380{ 383{
381 CLEAR_PIXEL(x,y); 384 lcd_framebuffer[y/8][x] ^= 1 << (y & 7);
382} 385}
383 386
384/* Invert a single pixel */ 387static void nopixel(int x, int y)
385void lcd_invertpixel(int x, int y)
386{ 388{
387 INVERT_PIXEL(x,y); 389 (void)x;
390 (void)y;
388} 391}
389 392
390void lcd_drawline(int x1, int y1, int x2, int y2) 393tLCDPixelFunc* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel,
394 nopixel, clearpixel, nopixel, clearpixel};
395
396static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
391{ 397{
392 int numpixels; 398 *address ^= (bits & mask);
393 int i; 399}
394 int deltax, deltay;
395 int d, dinc1, dinc2;
396 int x, xinc1, xinc2;
397 int y, yinc1, yinc2;
398 400
399 deltax = abs(x2 - x1); 401static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
400 deltay = abs(y2 - y1); 402{
403 *address &= (bits | ~mask);
404}
401 405
402 if(deltax >= deltay) 406static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
403 { 407{
404 numpixels = deltax; 408 *address |= (bits & mask);
405 d = 2 * deltay - deltax; 409}
406 dinc1 = deltay * 2;
407 dinc2 = (deltay - deltax) * 2;
408 xinc1 = 1;
409 xinc2 = 1;
410 yinc1 = 0;
411 yinc2 = 1;
412 }
413 else
414 {
415 numpixels = deltay;
416 d = 2 * deltax - deltay;
417 dinc1 = deltax * 2;
418 dinc2 = (deltax - deltay) * 2;
419 xinc1 = 0;
420 xinc2 = 1;
421 yinc1 = 1;
422 yinc2 = 1;
423 }
424 numpixels++; /* include endpoints */
425 410
426 if(x1 > x2) 411static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
427 { 412{
428 xinc1 = -xinc1; 413 *address = (*address & ~mask) | (bits & mask);
429 xinc2 = -xinc2; 414}
430 }
431 415
432 if(y1 > y2) 416tLCDBlockFunc* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock};
433 {
434 yinc1 = -yinc1;
435 yinc2 = -yinc2;
436 }
437 417
438 x = x1; 418/*** drawing functions ***/
439 y = y1;
440 419
441 for(i=0; i<numpixels; i++) 420/* Clear the whole display */
442 { 421void lcd_clear_display(void)
443 DRAW_PIXEL(x,y); 422{
423 if (drawmode & DRMODE_INVERSEVID)
424 memset (lcd_framebuffer, 0xFF, sizeof lcd_framebuffer);
425 else
426 memset (lcd_framebuffer, 0, sizeof lcd_framebuffer);
427 scrolling_lines = 0;
428}
444 429
445 if(d < 0) 430/* Set a single pixel */
446 { 431void lcd_drawpixel(int x, int y)
447 d += dinc1; 432{
448 x += xinc1; 433 if (((unsigned)x < LCD_WIDTH) || ((unsigned)y < LCD_HEIGHT))
449 y += yinc1; 434 pixelfunc[drawmode](x, y);
450 }
451 else
452 {
453 d += dinc2;
454 x += xinc2;
455 y += yinc2;
456 }
457 }
458} 435}
459 436
460void lcd_clearline(int x1, int y1, int x2, int y2) 437/* Draw a line */
438void lcd_drawline(int x1, int y1, int x2, int y2)
461{ 439{
462 int numpixels; 440 int numpixels;
463 int i; 441 int i;
@@ -465,20 +443,21 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
465 int d, dinc1, dinc2; 443 int d, dinc1, dinc2;
466 int x, xinc1, xinc2; 444 int x, xinc1, xinc2;
467 int y, yinc1, yinc2; 445 int y, yinc1, yinc2;
446 tLCDPixelFunc *pfunc = pixelfunc[drawmode];
468 447
469 deltax = abs(x2 - x1); 448 deltax = abs(x2 - x1);
470 deltay = abs(y2 - y1); 449 deltay = abs(y2 - y1);
450 xinc2 = 1;
451 yinc2 = 1;
471 452
472 if(deltax >= deltay) 453 if (deltax >= deltay)
473 { 454 {
474 numpixels = deltax; 455 numpixels = deltax;
475 d = 2 * deltay - deltax; 456 d = 2 * deltay - deltax;
476 dinc1 = deltay * 2; 457 dinc1 = deltay * 2;
477 dinc2 = (deltay - deltax) * 2; 458 dinc2 = (deltay - deltax) * 2;
478 xinc1 = 1; 459 xinc1 = 1;
479 xinc2 = 1;
480 yinc1 = 0; 460 yinc1 = 0;
481 yinc2 = 1;
482 } 461 }
483 else 462 else
484 { 463 {
@@ -487,19 +466,17 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
487 dinc1 = deltax * 2; 466 dinc1 = deltax * 2;
488 dinc2 = (deltax - deltay) * 2; 467 dinc2 = (deltax - deltay) * 2;
489 xinc1 = 0; 468 xinc1 = 0;
490 xinc2 = 1;
491 yinc1 = 1; 469 yinc1 = 1;
492 yinc2 = 1;
493 } 470 }
494 numpixels++; /* include endpoints */ 471 numpixels++; /* include endpoints */
495 472
496 if(x1 > x2) 473 if (x1 > x2)
497 { 474 {
498 xinc1 = -xinc1; 475 xinc1 = -xinc1;
499 xinc2 = -xinc2; 476 xinc2 = -xinc2;
500 } 477 }
501 478
502 if(y1 > y2) 479 if (y1 > y2)
503 { 480 {
504 yinc1 = -yinc1; 481 yinc1 = -yinc1;
505 yinc2 = -yinc2; 482 yinc2 = -yinc2;
@@ -508,11 +485,12 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
508 x = x1; 485 x = x1;
509 y = y1; 486 y = y1;
510 487
511 for(i=0; i<numpixels; i++) 488 for (i = 0; i < numpixels; i++)
512 { 489 {
513 CLEAR_PIXEL(x,y); 490 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
491 pfunc(x, y);
514 492
515 if(d < 0) 493 if (d < 0)
516 { 494 {
517 d += dinc1; 495 d += dinc1;
518 x += xinc1; 496 x += xinc1;
@@ -527,68 +505,178 @@ void lcd_clearline(int x1, int y1, int x2, int y2)
527 } 505 }
528} 506}
529 507
530/* Draw a rectangle with upper left corner at (x, y) and size (nx, ny) */ 508/* Draw a horizontal line (optimised) */
531void lcd_drawrect(int x, int y, int nx, int ny) 509void lcd_hline(int x1, int x2, int y)
532{ 510{
533 int i; 511 int x;
512 unsigned char *dst;
513 unsigned char mask, bits;
514 tLCDBlockFunc *bfunc;
534 515
535 if (x > LCD_WIDTH) 516 /* direction flip */
536 return; 517 if (x2 < x1)
537 if (y > LCD_HEIGHT) 518 {
538 return; 519 x = x1;
520 x1 = x2;
521 x2 = x;
522 }
523
524 /* nothing to draw? */
525 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
526 return;
527
528 /* clipping */
529 if (x1 < 0)
530 x1 = 0;
531 if (x2 >= LCD_WIDTH)
532 x2 = LCD_WIDTH-1;
533
534 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
535 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
536 dst = &lcd_framebuffer[y/8][x1];
537 mask = 1 << (y & 7);
539 538
540 if (x + nx > LCD_WIDTH) 539 for (x = x1; x <= x2; x++)
541 nx = LCD_WIDTH - x; 540 bfunc(dst++, mask, bits);
542 if (y + ny > LCD_HEIGHT) 541}
543 ny = LCD_HEIGHT - y; 542
543/* Draw a vertical line (optimised) */
544void lcd_vline(int x, int y1, int y2)
545{
546 int ny;
547 unsigned char *dst;
548 unsigned char mask_top, mask_bottom, bits;
549 tLCDBlockFunc *bfunc;
544 550
545 /* vertical lines */ 551 /* direction flip */
546 for (i = 0; i < ny; i++) { 552 if (y2 < y1)
547 DRAW_PIXEL(x, (y + i)); 553 {
548 DRAW_PIXEL((x + nx - 1), (y + i)); 554 ny = y1;
555 y1 = y2;
556 y2 = ny;
549 } 557 }
550 558
551 /* horizontal lines */ 559 /* nothing to draw? */
552 for (i = 0; i < nx; i++) { 560 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
553 DRAW_PIXEL((x + i),y); 561 return;
554 DRAW_PIXEL((x + i),(y + ny - 1)); 562
563 /* clipping */
564 if (y1 < 0)
565 y1 = 0;
566 if (y2 >= LCD_HEIGHT)
567 y2 = LCD_HEIGHT-1;
568
569 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
570 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
571 dst = &lcd_framebuffer[y1/8][x];
572 ny = y2 - (y1 & ~7);
573 mask_top = 0xFFu << (y1 & 7);
574 mask_bottom = 0xFFu >> (7 - (ny & 7));
575
576 if (ny >= 8)
577 {
578 bfunc(dst, mask_top, bits);
579 dst += LCD_WIDTH;
580
581 for (; ny > 15; ny -= 8)
582 {
583 bfunc(dst, 0xFFu, bits);
584 dst += LCD_WIDTH;
585 }
555 } 586 }
587 else
588 mask_bottom &= mask_top;
589
590 bfunc(dst, mask_bottom, bits);
556} 591}
557 592
558/* Clear a rectangular area at (x, y), size (nx, ny) */ 593/* Draw a rectangular box */
559void lcd_clearrect(int x, int y, int nx, int ny) 594void lcd_drawrect(int x, int y, int width, int height)
560{ 595{
561 int i; 596 if ((width <= 0) || (height <= 0))
562 for (i = 0; i < nx; i++) 597 return;
563 lcd_bitmap(zeros, x+i, y, 1, ny, true); 598
599 int x2 = x + width - 1;
600 int y2 = y + height - 1;
601
602 lcd_vline(x, y, y2);
603 lcd_vline(x2, y, y2);
604 lcd_hline(x, x2, y);
605 lcd_hline(x, x2, y2);
564} 606}
565 607
566/* Fill a rectangular area at (x, y), size (nx, ny) */ 608/* helper function for lcd_fillrect() */
567void lcd_fillrect(int x, int y, int nx, int ny) 609static void fillrow(tLCDBlockFunc *bfunc, unsigned char *address,
610 int width, unsigned mask, unsigned bits)
568{ 611{
569 int i; 612 int i;
570 for (i = 0; i < nx; i++) 613
571 lcd_bitmap(ones, x+i, y, 1, ny, true); 614 for (i = 0; i < width; i++)
615 bfunc(address++, mask, bits);
572} 616}
573 617
574/* Invert a rectangular area at (x, y), size (nx, ny) */ 618/* Fill a rectangular area */
575void lcd_invertrect(int x, int y, int nx, int ny) 619void lcd_fillrect(int x, int y, int width, int height)
576{ 620{
577 int i, j; 621 int ny;
578 622 unsigned char *dst;
579 if (x > LCD_WIDTH) 623 unsigned char mask_top, mask_bottom, bits;
580 return; 624 tLCDBlockFunc *bfunc;
581 if (y > LCD_HEIGHT) 625 bool fillopt = (drawmode & DRMODE_INVERSEVID) ?
626 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
627
628 /* nothing to draw? */
629 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
630 || (x + width < 0) || (y + height < 0))
582 return; 631 return;
583 632
584 if (x + nx > LCD_WIDTH) 633 /* clipping */
585 nx = LCD_WIDTH - x; 634 if (x < 0)
586 if (y + ny > LCD_HEIGHT) 635 {
587 ny = LCD_HEIGHT - y; 636 width += x;
588 637 x = 0;
589 for (i = 0; i < nx; i++) 638 }
590 for (j = 0; j < ny; j++) 639 if (y < 0)
591 INVERT_PIXEL((x + i), (y + j)); 640 {
641 height += y;
642 y = 0;
643 }
644 if (x + width > LCD_WIDTH)
645 width = LCD_WIDTH - x;
646 if (y + height > LCD_HEIGHT)
647 height = LCD_HEIGHT - y;
648
649 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
650 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
651 dst = &lcd_framebuffer[y/8][x];
652 ny = height - 1 + (y & 7);
653 mask_top = 0xFFu << (y & 7);
654 mask_bottom = 0xFFu >> (7 - (ny & 7));
655
656 if (ny >= 8)
657 {
658 if (fillopt && mask_top == 0xFF)
659 memset(dst, bits, width);
660 else
661 fillrow(bfunc, dst, width, mask_top, bits);
662 dst += LCD_WIDTH;
663
664 for (; ny > 15; ny -= 8)
665 {
666 if (fillopt)
667 memset(dst, bits, width);
668 else
669 fillrow(bfunc, dst, width, 0xFFu, bits);
670 dst += LCD_WIDTH;
671 }
672 }
673 else
674 mask_bottom &= mask_top;
675
676 if (fillopt && mask_bottom == 0xFF)
677 memset(dst, bits, width);
678 else
679 fillrow(bfunc, dst, width, mask_bottom, bits);
592} 680}
593 681
594/* About Rockbox' internal bitmap format: 682/* About Rockbox' internal bitmap format:
@@ -756,6 +844,7 @@ void lcd_putsxy(int x, int y, const unsigned char *str)
756void lcd_puts_style(int x, int y, const unsigned char *str, int style) 844void lcd_puts_style(int x, int y, const unsigned char *str, int style)
757{ 845{
758 int xpos,ypos,w,h; 846 int xpos,ypos,w,h;
847 int lastmode = lcd_get_drawmode();
759 848
760 /* make sure scrolling is turned off on the line we are updating */ 849 /* make sure scrolling is turned off on the line we are updating */
761 scrolling_lines &= ~(1 << y); 850 scrolling_lines &= ~(1 << y);
@@ -767,9 +856,14 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
767 xpos = xmargin + x*w / strlen(str); 856 xpos = xmargin + x*w / strlen(str);
768 ypos = ymargin + y*h; 857 ypos = ymargin + y*h;
769 lcd_putsxy(xpos, ypos, str); 858 lcd_putsxy(xpos, ypos, str);
770 lcd_clearrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); 859 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
860 lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h);
771 if (style & STYLE_INVERT) 861 if (style & STYLE_INVERT)
772 lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, h); 862 {
863 lcd_set_drawmode(DRMODE_COMPLEMENT);
864 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h);
865 }
866 lcd_set_drawmode(lastmode);
773} 867}
774 868
775/* put a string at a given char position */ 869/* put a string at a given char position */
@@ -885,6 +979,7 @@ static void scroll_thread(void)
885 struct scrollinfo* s; 979 struct scrollinfo* s;
886 int index; 980 int index;
887 int xpos, ypos; 981 int xpos, ypos;
982 int lastmode;
888 983
889 /* initialize scroll struct array */ 984 /* initialize scroll struct array */
890 scrolling_lines = 0; 985 scrolling_lines = 0;
@@ -930,10 +1025,17 @@ static void scroll_thread(void)
930 s->offset %= s->width; 1025 s->offset %= s->width;
931 } 1026 }
932 1027
933 lcd_clearrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1028 lastmode = lcd_get_drawmode();
1029 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1030 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1031 lcd_set_drawmode(DRMODE_SOLID);
934 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 1032 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
935 if (s->invert) 1033 if (s->invert)
936 lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1034 {
1035 lcd_set_drawmode(DRMODE_COMPLEMENT);
1036 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1037 }
1038 lcd_set_drawmode(lastmode);
937 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1039 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
938 } 1040 }
939 1041