summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/drivers/lcd-h100.c355
-rw-r--r--firmware/drivers/lcd-recorder.c360
-rw-r--r--firmware/export/lcd.h9
3 files changed, 378 insertions, 346 deletions
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 15cb351195..616a8521b0 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -208,19 +208,19 @@ void lcd_init(void)
208/*** update functions ***/ 208/*** update functions ***/
209 209
210/* Performance function that works with an external buffer 210/* Performance function that works with an external buffer
211 note that y and height are in 8-pixel units! */ 211 note that by and bheight are in 8-pixel units! */
212void lcd_blit(const unsigned char* p_data, int x, int y, int width, 212void lcd_blit(const unsigned char* data, int x, int by, int width,
213 int height, int stride) 213 int bheight, int stride)
214{ 214{
215 /* Copy display bitmap to hardware */ 215 /* Copy display bitmap to hardware */
216 while (height--) 216 while (bheight--)
217 { 217 {
218 lcd_write_command_ex(LCD_CNTL_PAGE, y++ & 0xf, -1); 218 lcd_write_command_ex(LCD_CNTL_PAGE, by++ & 0xf, -1);
219 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1); 219 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
220 220
221 lcd_write_command(LCD_CNTL_DATA_WRITE); 221 lcd_write_command(LCD_CNTL_DATA_WRITE);
222 lcd_write_data(p_data, width); 222 lcd_write_data(data, width);
223 p_data += stride; 223 data += stride;
224 } 224 }
225} 225}
226 226
@@ -245,16 +245,16 @@ void lcd_update(void)
245 245
246/* Update a fraction of the display. */ 246/* Update a fraction of the display. */
247void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); 247void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode")));
248void lcd_update_rect(int x_start, int y, int width, int height) 248void lcd_update_rect(int x, int y, int width, int height)
249{ 249{
250 int ymax; 250 int ymax;
251 251
252 /* The Y coordinates have to work on even 8 pixel rows */ 252 /* The Y coordinates have to work on even 8 pixel rows */
253 ymax = (y + height-1)/8; 253 ymax = (y + height-1) >> 3;
254 y /= 8; 254 y >>= 3;
255 255
256 if(x_start + width > LCD_WIDTH) 256 if(x + width > LCD_WIDTH)
257 width = LCD_WIDTH - x_start; 257 width = LCD_WIDTH - x;
258 if (width <= 0) 258 if (width <= 0)
259 return; /* nothing left to do, 0 is harmful to lcd_write_data() */ 259 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
260 if(ymax >= LCD_HEIGHT/8) 260 if(ymax >= LCD_HEIGHT/8)
@@ -264,10 +264,10 @@ void lcd_update_rect(int x_start, int y, int width, int height)
264 for (; y <= ymax; y++) 264 for (; y <= ymax; y++)
265 { 265 {
266 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1); 266 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
267 lcd_write_command_ex(LCD_CNTL_COLUMN, x_start, -1); 267 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
268 268
269 lcd_write_command(LCD_CNTL_DATA_WRITE); 269 lcd_write_command(LCD_CNTL_DATA_WRITE);
270 lcd_write_data (&lcd_framebuffer[y][x_start], width); 270 lcd_write_data (&lcd_framebuffer[y][x], width);
271 } 271 }
272} 272}
273#endif /* !SIMULATOR */ 273#endif /* !SIMULATOR */
@@ -333,8 +333,10 @@ static void nopixel(int x, int y)
333 (void)y; 333 (void)y;
334} 334}
335 335
336lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, 336lcd_pixelfunc_type* pixelfunc[8] = {
337 nopixel, clearpixel, nopixel, clearpixel}; 337 flippixel, nopixel, setpixel, setpixel,
338 nopixel, clearpixel, nopixel, clearpixel
339};
338 340
339static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 341static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
340{ 342{
@@ -356,7 +358,30 @@ static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
356 *address = (*address & ~mask) | (bits & mask); 358 *address = (*address & ~mask) | (bits & mask);
357} 359}
358 360
359lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; 361static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
362{
363 *address ^= (~bits & mask);
364}
365
366static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
367{
368 *address &= ~(bits & mask);
369}
370
371static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
372{
373 *address |= (~bits & mask);
374}
375
376static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
377{
378 *address = (*address & ~mask) | (~bits & mask);
379}
380
381lcd_blockfunc_type* blockfunc[8] = {
382 flipblock, bgblock, fgblock, solidblock,
383 flipinvblock, bginvblock, fginvblock, solidinvblock
384};
360 385
361/*** drawing functions ***/ 386/*** drawing functions ***/
362 387
@@ -452,7 +477,7 @@ void lcd_hline(int x1, int x2, int y)
452{ 477{
453 int x; 478 int x;
454 unsigned char *dst; 479 unsigned char *dst;
455 unsigned char mask, bits; 480 unsigned mask;
456 lcd_blockfunc_type *bfunc; 481 lcd_blockfunc_type *bfunc;
457 482
458 /* direction flip */ 483 /* direction flip */
@@ -473,13 +498,12 @@ void lcd_hline(int x1, int x2, int y)
473 if (x2 >= LCD_WIDTH) 498 if (x2 >= LCD_WIDTH)
474 x2 = LCD_WIDTH-1; 499 x2 = LCD_WIDTH-1;
475 500
476 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 501 bfunc = blockfunc[drawmode];
477 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 502 dst = &lcd_framebuffer[y>>3][x1];
478 dst = &lcd_framebuffer[y/8][x1];
479 mask = 1 << (y & 7); 503 mask = 1 << (y & 7);
480 504
481 for (x = x1; x <= x2; x++) 505 for (x = x1; x <= x2; x++)
482 bfunc(dst++, mask, bits); 506 bfunc(dst++, mask, 0xFFu);
483} 507}
484 508
485/* Draw a vertical line (optimised) */ 509/* Draw a vertical line (optimised) */
@@ -487,7 +511,7 @@ void lcd_vline(int x, int y1, int y2)
487{ 511{
488 int ny; 512 int ny;
489 unsigned char *dst; 513 unsigned char *dst;
490 unsigned char mask_top, mask_bottom, bits; 514 unsigned mask, mask_bottom;
491 lcd_blockfunc_type *bfunc; 515 lcd_blockfunc_type *bfunc;
492 516
493 /* direction flip */ 517 /* direction flip */
@@ -508,28 +532,20 @@ void lcd_vline(int x, int y1, int y2)
508 if (y2 >= LCD_HEIGHT) 532 if (y2 >= LCD_HEIGHT)
509 y2 = LCD_HEIGHT-1; 533 y2 = LCD_HEIGHT-1;
510 534
511 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 535 bfunc = blockfunc[drawmode];
512 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 536 dst = &lcd_framebuffer[y1>>3][x];
513 dst = &lcd_framebuffer[y1/8][x];
514 ny = y2 - (y1 & ~7); 537 ny = y2 - (y1 & ~7);
515 mask_top = 0xFFu << (y1 & 7); 538 mask = 0xFFu << (y1 & 7);
516 mask_bottom = 0xFFu >> (7 - (ny & 7)); 539 mask_bottom = 0xFFu >> (7 - (ny & 7));
517 540
518 if (ny >= 8) 541 for (; ny >= 8; ny -= 8)
519 { 542 {
520 bfunc(dst, mask_top, bits); 543 bfunc(dst, mask, 0xFFu);
521 dst += LCD_WIDTH; 544 dst += LCD_WIDTH;
522 545 mask = 0xFFu;
523 for (; ny > 15; ny -= 8)
524 {
525 bfunc(dst, 0xFFu, bits);
526 dst += LCD_WIDTH;
527 }
528 } 546 }
529 else 547 mask_bottom &= mask;
530 mask_bottom &= mask_top; 548 bfunc(dst, mask_bottom, 0xFFu);
531
532 bfunc(dst, mask_bottom, bits);
533} 549}
534 550
535/* Draw a rectangular box */ 551/* Draw a rectangular box */
@@ -547,29 +563,19 @@ void lcd_drawrect(int x, int y, int width, int height)
547 lcd_hline(x, x2, y2); 563 lcd_hline(x, x2, y2);
548} 564}
549 565
550/* helper function for lcd_fillrect() */
551static void fillrow(lcd_blockfunc_type *bfunc, unsigned char *address,
552 int width, unsigned mask, unsigned bits)
553{
554 int i;
555
556 for (i = 0; i < width; i++)
557 bfunc(address++, mask, bits);
558}
559
560/* Fill a rectangular area */ 566/* Fill a rectangular area */
561void lcd_fillrect(int x, int y, int width, int height) 567void lcd_fillrect(int x, int y, int width, int height)
562{ 568{
563 int ny; 569 int ny, i;
564 unsigned char *dst; 570 unsigned char *dst;
565 unsigned char mask_top, mask_bottom, bits; 571 unsigned mask, mask_bottom;
572 unsigned bits = 0xFFu;
566 lcd_blockfunc_type *bfunc; 573 lcd_blockfunc_type *bfunc;
567 bool fillopt = (drawmode & DRMODE_INVERSEVID) ? 574 bool fillopt;
568 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
569 575
570 /* nothing to draw? */ 576 /* nothing to draw? */
571 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 577 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
572 || (x + width < 0) || (y + height < 0)) 578 || (x + width <= 0) || (y + height <= 0))
573 return; 579 return;
574 580
575 /* clipping */ 581 /* clipping */
@@ -587,38 +593,41 @@ void lcd_fillrect(int x, int y, int width, int height)
587 width = LCD_WIDTH - x; 593 width = LCD_WIDTH - x;
588 if (y + height > LCD_HEIGHT) 594 if (y + height > LCD_HEIGHT)
589 height = LCD_HEIGHT - y; 595 height = LCD_HEIGHT - y;
590 596
591 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 597 fillopt = (drawmode & DRMODE_INVERSEVID) ?
592 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 598 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
593 dst = &lcd_framebuffer[y/8][x]; 599 if (fillopt &&(drawmode & DRMODE_INVERSEVID))
600 bits = 0;
601 bfunc = blockfunc[drawmode];
602 dst = &lcd_framebuffer[y>>3][x];
594 ny = height - 1 + (y & 7); 603 ny = height - 1 + (y & 7);
595 mask_top = 0xFFu << (y & 7); 604 mask = 0xFFu << (y & 7);
596 mask_bottom = 0xFFu >> (7 - (ny & 7)); 605 mask_bottom = 0xFFu >> (7 - (ny & 7));
597 606
598 if (ny >= 8) 607 for (; ny >= 8; ny -= 8)
599 { 608 {
600 if (fillopt && mask_top == 0xFF) 609 if (fillopt && (mask == 0xFFu))
601 memset(dst, bits, width); 610 memset(dst, bits, width);
602 else 611 else
603 fillrow(bfunc, dst, width, mask_top, bits);
604 dst += LCD_WIDTH;
605
606 for (; ny > 15; ny -= 8)
607 { 612 {
608 if (fillopt) 613 unsigned char *dst_row = dst;
609 memset(dst, bits, width); 614
610 else 615 for (i = width; i > 0; i--)
611 fillrow(bfunc, dst, width, 0xFFu, bits); 616 bfunc(dst_row++, mask, 0xFFu);
612 dst += LCD_WIDTH;
613 } 617 }
618
619 dst += LCD_WIDTH;
620 mask = 0xFFu;
614 } 621 }
615 else 622 mask_bottom &= mask;
616 mask_bottom &= mask_top; 623
617 624 if (fillopt && (mask_bottom == 0xFFu))
618 if (fillopt && mask_bottom == 0xFF)
619 memset(dst, bits, width); 625 memset(dst, bits, width);
620 else 626 else
621 fillrow(bfunc, dst, width, mask_bottom, bits); 627 {
628 for (i = width; i > 0; i--)
629 bfunc(dst++, mask_bottom, 0xFFu);
630 }
622} 631}
623 632
624/* About Rockbox' internal bitmap format: 633/* About Rockbox' internal bitmap format:
@@ -632,95 +641,120 @@ void lcd_fillrect(int x, int y, int width, int height)
632 * 641 *
633 * This is the same as the internal lcd hw format. */ 642 * This is the same as the internal lcd hw format. */
634 643
635/* Draw a bitmap at (x, y), size (nx, ny) 644/* Draw a partial bitmap */
636 if 'clear' is true, clear destination area first */ 645void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
637void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 646 int stride, int x, int y, int width, int height)
638 bool clear) __attribute__ ((section (".icode"))); 647 __attribute__ ((section(".icode")));
639void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 648void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
640 bool clear) 649 int stride, int x, int y, int width, int height)
641{ 650{
642 const unsigned char *src_col; 651 int shift, ny, i;
643 unsigned char *dst, *dst_col; 652 unsigned char *dst;
644 unsigned int data, mask1, mask2, mask3, mask4; 653 unsigned mask, mask_bottom;
645 int stride, shift; 654 lcd_blockfunc_type *bfunc;
646 655
647 if (((unsigned) x >= LCD_WIDTH) || ((unsigned) y >= LCD_HEIGHT)) 656 /* nothing to draw? */
657 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
658 || (x + width <= 0) || (y + height <= 0))
648 return; 659 return;
660
661 /* clipping */
662 if (x < 0)
663 {
664 width += x;
665 src_x -= x;
666 x = 0;
667 }
668 if (y < 0)
669 {
670 height += y;
671 src_y -= y;
672 y = 0;
673 }
674 if (x + width > LCD_WIDTH)
675 width = LCD_WIDTH - x;
676 if (y + height > LCD_HEIGHT)
677 height = LCD_HEIGHT - y;
649 678
650 stride = nx; /* otherwise right-clipping will destroy the image */ 679 src += stride * (src_y >> 3) + src_x; /* move starting point */
680 src_y &= 7;
681 y -= src_y;
682 dst = &lcd_framebuffer[y>>3][x];
683 shift = y & 7;
684 ny = height - 1 + shift + src_y;
651 685
652 if (((unsigned) (x + nx)) >= LCD_WIDTH) 686 bfunc = blockfunc[drawmode];
653 nx = LCD_WIDTH - x; 687 mask = 0xFFu << (shift + src_y);
654 if (((unsigned) (y + ny)) >= LCD_HEIGHT) 688 mask_bottom = 0xFFu >> (7 - (ny & 7));
655 ny = LCD_HEIGHT - y;
656
657 dst = &lcd_framebuffer[y >> 3][x];
658 shift = y & 7;
659 689
660 if (!shift && clear) /* shortcut for byte aligned match with clear */ 690 if (shift == 0)
661 { 691 {
662 while (ny >= 8) /* all full rows */ 692 bool copyopt = (drawmode == DRMODE_SOLID);
693
694 for (; ny >= 8; ny -= 8)
663 { 695 {
664 memcpy(dst, src, nx); 696 if (copyopt && (mask == 0xFFu))
697 memcpy(dst, src, width);
698 else
699 {
700 const unsigned char *src_row = src;
701 unsigned char *dst_row = dst;
702
703 for (i = width; i > 0; i--)
704 bfunc(dst_row++, mask, *src_row++);
705 }
706
665 src += stride; 707 src += stride;
666 dst += LCD_WIDTH; 708 dst += LCD_WIDTH;
667 ny -= 8; 709 mask = 0xFFu;
668 } 710 }
669 if (ny == 0) /* nothing left to do? */ 711 mask_bottom &= mask;
670 return;
671 /* last partial row to do by default routine */
672 }
673
674 ny += shift;
675 712
676 /* Calculate bit masks */ 713 if (copyopt && (mask_bottom == 0xFFu))
677 mask4 = ~(0xfe << ((ny-1) & 7)); /* data mask for last partial row */ 714 memcpy(dst, src, width);
678 if (clear) 715 else
679 { 716 {
680 mask1 = ~(0xff << shift); /* clearing of first partial row */ 717 for (i = width; i > 0; i--)
681 mask2 = 0; /* clearing of intermediate (full) rows */ 718 bfunc(dst++, mask_bottom, *src++);
682 mask3 = ~mask4; /* clearing of last partial row */ 719 }
683 if (ny <= 8)
684 mask3 |= mask1;
685 } 720 }
686 else 721 else
687 mask1 = mask2 = mask3 = 0xff;
688
689 /* Loop for each column */
690 for (x = 0; x < nx; x++)
691 { 722 {
692 src_col = src++; 723 for (x = 0; x < width; x++)
693 dst_col = dst++;
694 data = 0;
695 y = 0;
696
697 if (ny > 8)
698 { 724 {
699 /* First partial row */ 725 const unsigned char *src_col = src++;
700 data = *src_col << shift; 726 unsigned char *dst_col = dst++;
701 *dst_col = (*dst_col & mask1) | data; 727 unsigned mask_col = mask;
702 src_col += stride; 728 unsigned data = 0;
703 dst_col += LCD_WIDTH; 729
704 data >>= 8; 730 for (y = ny; y >= 8; y -= 8)
705
706 /* Intermediate rows */
707 for (y = 8; y < ny-8; y += 8)
708 { 731 {
709 data |= *src_col << shift; 732 data |= *src_col << shift;
710 *dst_col = (*dst_col & mask2) | data; 733
734 if (mask_col & 0xFFu)
735 {
736 bfunc(dst_col, mask_col, data);
737 mask_col = 0xFFu;
738 }
739 else
740 mask_col >>= 8;
741
711 src_col += stride; 742 src_col += stride;
712 dst_col += LCD_WIDTH; 743 dst_col += LCD_WIDTH;
713 data >>= 8; 744 data >>= 8;
714 } 745 }
715 }
716
717 /* Last partial row */
718 if (y + shift < ny)
719 data |= *src_col << shift; 746 data |= *src_col << shift;
720 *dst_col = (*dst_col & mask3) | (data & mask4); 747 bfunc(dst_col, mask_col & mask_bottom, data);
748 }
721 } 749 }
722} 750}
723 751
752/* Draw a full bitmap */
753void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
754{
755 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
756}
757
724/* put a string at a given pixel position, skipping first ofs pixel columns */ 758/* put a string at a given pixel position, skipping first ofs pixel columns */
725static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 759static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
726{ 760{
@@ -729,7 +763,8 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
729 763
730 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 764 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
731 { 765 {
732 int gwidth, width; 766 int width;
767 const unsigned char *bits;
733 768
734 /* check input range */ 769 /* check input range */
735 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 770 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
@@ -737,40 +772,20 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
737 ch -= pf->firstchar; 772 ch -= pf->firstchar;
738 773
739 /* get proportional width and glyph bits */ 774 /* get proportional width and glyph bits */
740 gwidth = pf->width ? pf->width[ch] : pf->maxwidth; 775 width = pf->width ? pf->width[ch] : pf->maxwidth;
741 width = MIN (gwidth, LCD_WIDTH - x);
742 776
743 if (ofs != 0) 777 if (ofs > width)
744 { 778 {
745 if (ofs > width) 779 ofs -= width;
746 { 780 continue;
747 ofs -= width;
748 continue;
749 }
750 width -= ofs;
751 } 781 }
782
783 bits = pf->bits + (pf->offset ?
784 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
752 785
753 if (width > 0) 786 lcd_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
754 { 787
755 unsigned int i; 788 x += width - ofs;
756 const unsigned char* bits = pf->bits +
757 (pf->offset ? pf->offset[ch]
758 : ((pf->height + 7) / 8 * pf->maxwidth * ch));
759
760 if (ofs != 0)
761 {
762 for (i = 0; i < pf->height; i += 8)
763 {
764 lcd_bitmap (bits + ofs, x, y + i, width,
765 MIN(8, pf->height - i), true);
766 bits += gwidth;
767 }
768 }
769 else
770 lcd_bitmap ((unsigned char*) bits, x, y, gwidth,
771 pf->height, true);
772 x += width;
773 }
774 ofs = 0; 789 ofs = 0;
775 } 790 }
776} 791}
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index d464e30f0a..9513c26380 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -265,20 +265,20 @@ void lcd_init(void)
265/*** Update functions ***/ 265/*** Update functions ***/
266 266
267/* Performance function that works with an external buffer 267/* Performance function that works with an external buffer
268 note that y and height are in 8-pixel units! */ 268 note that by and bheight are in 8-pixel units! */
269void lcd_blit(const unsigned char* p_data, int x, int y, int width, 269void lcd_blit(const unsigned char* data, int x, int by, int width,
270 int height, int stride) 270 int bheight, int stride)
271{ 271{
272 /* Copy display bitmap to hardware */ 272 /* Copy display bitmap to hardware */
273 while (height--) 273 while (bheight--)
274 { 274 {
275 lcd_write_command (LCD_CNTL_PAGE | (y++ & 0xf)); 275 lcd_write_command (LCD_CNTL_PAGE | (by++ & 0xf));
276 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf)); 276 lcd_write_command (LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf));
277 lcd_write_command (LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf)); 277 lcd_write_command (LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf));
278 278
279 lcd_write_data(p_data, width); 279 lcd_write_data(data, width);
280 p_data += stride; 280 data += stride;
281 } 281 }
282} 282}
283 283
284 284
@@ -302,29 +302,31 @@ void lcd_update(void)
302 302
303/* Update a fraction of the display. */ 303/* Update a fraction of the display. */
304void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); 304void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode")));
305void lcd_update_rect(int x_start, int y, int width, int height) 305void lcd_update_rect(int x, int y, int width, int height)
306{ 306{
307 int ymax; 307 int ymax;
308 308
309 /* The Y coordinates have to work on even 8 pixel rows */ 309 /* The Y coordinates have to work on even 8 pixel rows */
310 ymax = (y + height-1)/8; 310 ymax = (y + height-1) >> 3;
311 y /= 8; 311 y >>= 3;
312 312
313 if(x_start + width > LCD_WIDTH) 313 if(x + width > LCD_WIDTH)
314 width = LCD_WIDTH - x_start; 314 width = LCD_WIDTH - x;
315 if (width <= 0) 315 if (width <= 0)
316 return; /* nothing left to do, 0 is harmful to lcd_write_data() */ 316 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
317 if(ymax >= LCD_HEIGHT/8) 317 if(ymax >= LCD_HEIGHT/8)
318 ymax = LCD_HEIGHT/8-1; 318 ymax = LCD_HEIGHT/8-1;
319
320 x += xoffset;
319 321
320 /* Copy specified rectange bitmap to hardware */ 322 /* Copy specified rectange bitmap to hardware */
321 for (; y <= ymax; y++) 323 for (; y <= ymax; y++)
322 { 324 {
323 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf)); 325 lcd_write_command (LCD_CNTL_PAGE | (y & 0xf));
324 lcd_write_command (LCD_CNTL_HIGHCOL | (((x_start+xoffset)>>4) & 0xf)); 326 lcd_write_command (LCD_CNTL_HIGHCOL | ((x >> 4) & 0xf));
325 lcd_write_command (LCD_CNTL_LOWCOL | ((x_start+xoffset) & 0xf)); 327 lcd_write_command (LCD_CNTL_LOWCOL | (x & 0xf));
326 328
327 lcd_write_data (&lcd_framebuffer[y][x_start], width); 329 lcd_write_data (&lcd_framebuffer[y][x], width);
328 } 330 }
329} 331}
330#endif /* !SIMULATOR */ 332#endif /* !SIMULATOR */
@@ -390,8 +392,10 @@ static void nopixel(int x, int y)
390 (void)y; 392 (void)y;
391} 393}
392 394
393lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, 395lcd_pixelfunc_type* pixelfunc[8] = {
394 nopixel, clearpixel, nopixel, clearpixel}; 396 flippixel, nopixel, setpixel, setpixel,
397 nopixel, clearpixel, nopixel, clearpixel
398};
395 399
396static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 400static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
397{ 401{
@@ -413,7 +417,30 @@ static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
413 *address = (*address & ~mask) | (bits & mask); 417 *address = (*address & ~mask) | (bits & mask);
414} 418}
415 419
416lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; 420static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
421{
422 *address ^= (~bits & mask);
423}
424
425static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
426{
427 *address &= ~(bits & mask);
428}
429
430static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
431{
432 *address |= (~bits & mask);
433}
434
435static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
436{
437 *address = (*address & ~mask) | (~bits & mask);
438}
439
440lcd_blockfunc_type* blockfunc[8] = {
441 flipblock, bgblock, fgblock, solidblock,
442 flipinvblock, bginvblock, fginvblock, solidinvblock
443};
417 444
418/*** drawing functions ***/ 445/*** drawing functions ***/
419 446
@@ -509,7 +536,7 @@ void lcd_hline(int x1, int x2, int y)
509{ 536{
510 int x; 537 int x;
511 unsigned char *dst; 538 unsigned char *dst;
512 unsigned char mask, bits; 539 unsigned mask;
513 lcd_blockfunc_type *bfunc; 540 lcd_blockfunc_type *bfunc;
514 541
515 /* direction flip */ 542 /* direction flip */
@@ -530,13 +557,12 @@ void lcd_hline(int x1, int x2, int y)
530 if (x2 >= LCD_WIDTH) 557 if (x2 >= LCD_WIDTH)
531 x2 = LCD_WIDTH-1; 558 x2 = LCD_WIDTH-1;
532 559
533 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 560 bfunc = blockfunc[drawmode];
534 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 561 dst = &lcd_framebuffer[y>>3][x1];
535 dst = &lcd_framebuffer[y/8][x1];
536 mask = 1 << (y & 7); 562 mask = 1 << (y & 7);
537 563
538 for (x = x1; x <= x2; x++) 564 for (x = x1; x <= x2; x++)
539 bfunc(dst++, mask, bits); 565 bfunc(dst++, mask, 0xFFu);
540} 566}
541 567
542/* Draw a vertical line (optimised) */ 568/* Draw a vertical line (optimised) */
@@ -544,7 +570,7 @@ void lcd_vline(int x, int y1, int y2)
544{ 570{
545 int ny; 571 int ny;
546 unsigned char *dst; 572 unsigned char *dst;
547 unsigned char mask_top, mask_bottom, bits; 573 unsigned mask, mask_bottom;
548 lcd_blockfunc_type *bfunc; 574 lcd_blockfunc_type *bfunc;
549 575
550 /* direction flip */ 576 /* direction flip */
@@ -565,28 +591,20 @@ void lcd_vline(int x, int y1, int y2)
565 if (y2 >= LCD_HEIGHT) 591 if (y2 >= LCD_HEIGHT)
566 y2 = LCD_HEIGHT-1; 592 y2 = LCD_HEIGHT-1;
567 593
568 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 594 bfunc = blockfunc[drawmode];
569 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 595 dst = &lcd_framebuffer[y1>>3][x];
570 dst = &lcd_framebuffer[y1/8][x];
571 ny = y2 - (y1 & ~7); 596 ny = y2 - (y1 & ~7);
572 mask_top = 0xFFu << (y1 & 7); 597 mask = 0xFFu << (y1 & 7);
573 mask_bottom = 0xFFu >> (7 - (ny & 7)); 598 mask_bottom = 0xFFu >> (7 - (ny & 7));
574 599
575 if (ny >= 8) 600 for (; ny >= 8; ny -= 8)
576 { 601 {
577 bfunc(dst, mask_top, bits); 602 bfunc(dst, mask, 0xFFu);
578 dst += LCD_WIDTH; 603 dst += LCD_WIDTH;
579 604 mask = 0xFFu;
580 for (; ny > 15; ny -= 8)
581 {
582 bfunc(dst, 0xFFu, bits);
583 dst += LCD_WIDTH;
584 }
585 } 605 }
586 else 606 mask_bottom &= mask;
587 mask_bottom &= mask_top; 607 bfunc(dst, mask_bottom, 0xFFu);
588
589 bfunc(dst, mask_bottom, bits);
590} 608}
591 609
592/* Draw a rectangular box */ 610/* Draw a rectangular box */
@@ -604,29 +622,19 @@ void lcd_drawrect(int x, int y, int width, int height)
604 lcd_hline(x, x2, y2); 622 lcd_hline(x, x2, y2);
605} 623}
606 624
607/* helper function for lcd_fillrect() */
608static void fillrow(lcd_blockfunc_type *bfunc, unsigned char *address,
609 int width, unsigned mask, unsigned bits)
610{
611 int i;
612
613 for (i = 0; i < width; i++)
614 bfunc(address++, mask, bits);
615}
616
617/* Fill a rectangular area */ 625/* Fill a rectangular area */
618void lcd_fillrect(int x, int y, int width, int height) 626void lcd_fillrect(int x, int y, int width, int height)
619{ 627{
620 int ny; 628 int ny, i;
621 unsigned char *dst; 629 unsigned char *dst;
622 unsigned char mask_top, mask_bottom, bits; 630 unsigned mask, mask_bottom;
631 unsigned bits = 0xFFu;
623 lcd_blockfunc_type *bfunc; 632 lcd_blockfunc_type *bfunc;
624 bool fillopt = (drawmode & DRMODE_INVERSEVID) ? 633 bool fillopt;
625 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
626 634
627 /* nothing to draw? */ 635 /* nothing to draw? */
628 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) 636 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
629 || (x + width < 0) || (y + height < 0)) 637 || (x + width <= 0) || (y + height <= 0))
630 return; 638 return;
631 639
632 /* clipping */ 640 /* clipping */
@@ -644,38 +652,41 @@ void lcd_fillrect(int x, int y, int width, int height)
644 width = LCD_WIDTH - x; 652 width = LCD_WIDTH - x;
645 if (y + height > LCD_HEIGHT) 653 if (y + height > LCD_HEIGHT)
646 height = LCD_HEIGHT - y; 654 height = LCD_HEIGHT - y;
647 655
648 bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID]; 656 fillopt = (drawmode & DRMODE_INVERSEVID) ?
649 bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu; 657 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
650 dst = &lcd_framebuffer[y/8][x]; 658 if (fillopt &&(drawmode & DRMODE_INVERSEVID))
659 bits = 0;
660 bfunc = blockfunc[drawmode];
661 dst = &lcd_framebuffer[y>>3][x];
651 ny = height - 1 + (y & 7); 662 ny = height - 1 + (y & 7);
652 mask_top = 0xFFu << (y & 7); 663 mask = 0xFFu << (y & 7);
653 mask_bottom = 0xFFu >> (7 - (ny & 7)); 664 mask_bottom = 0xFFu >> (7 - (ny & 7));
654 665
655 if (ny >= 8) 666 for (; ny >= 8; ny -= 8)
656 { 667 {
657 if (fillopt && mask_top == 0xFF) 668 if (fillopt && (mask == 0xFFu))
658 memset(dst, bits, width); 669 memset(dst, bits, width);
659 else 670 else
660 fillrow(bfunc, dst, width, mask_top, bits);
661 dst += LCD_WIDTH;
662
663 for (; ny > 15; ny -= 8)
664 { 671 {
665 if (fillopt) 672 unsigned char *dst_row = dst;
666 memset(dst, bits, width); 673
667 else 674 for (i = width; i > 0; i--)
668 fillrow(bfunc, dst, width, 0xFFu, bits); 675 bfunc(dst_row++, mask, 0xFFu);
669 dst += LCD_WIDTH;
670 } 676 }
677
678 dst += LCD_WIDTH;
679 mask = 0xFFu;
671 } 680 }
672 else 681 mask_bottom &= mask;
673 mask_bottom &= mask_top; 682
674 683 if (fillopt && (mask_bottom == 0xFFu))
675 if (fillopt && mask_bottom == 0xFF)
676 memset(dst, bits, width); 684 memset(dst, bits, width);
677 else 685 else
678 fillrow(bfunc, dst, width, mask_bottom, bits); 686 {
687 for (i = width; i > 0; i--)
688 bfunc(dst++, mask_bottom, 0xFFu);
689 }
679} 690}
680 691
681/* About Rockbox' internal bitmap format: 692/* About Rockbox' internal bitmap format:
@@ -689,95 +700,120 @@ void lcd_fillrect(int x, int y, int width, int height)
689 * 700 *
690 * This is the same as the internal lcd hw format. */ 701 * This is the same as the internal lcd hw format. */
691 702
692/* Draw a bitmap at (x, y), size (nx, ny) 703/* Draw a partial bitmap */
693 if 'clear' is true, clear destination area first */ 704void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
694void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 705 int stride, int x, int y, int width, int height)
695 bool clear) __attribute__ ((section (".icode"))); 706 __attribute__ ((section(".icode")));
696void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 707void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
697 bool clear) 708 int stride, int x, int y, int width, int height)
698{ 709{
699 const unsigned char *src_col; 710 int shift, ny, i;
700 unsigned char *dst, *dst_col; 711 unsigned char *dst;
701 unsigned int data, mask1, mask2, mask3, mask4; 712 unsigned mask, mask_bottom;
702 int stride, shift; 713 lcd_blockfunc_type *bfunc;
703 714
704 if (((unsigned) x >= LCD_WIDTH) || ((unsigned) y >= LCD_HEIGHT)) 715 /* nothing to draw? */
716 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
717 || (x + width <= 0) || (y + height <= 0))
705 return; 718 return;
719
720 /* clipping */
721 if (x < 0)
722 {
723 width += x;
724 src_x -= x;
725 x = 0;
726 }
727 if (y < 0)
728 {
729 height += y;
730 src_y -= y;
731 y = 0;
732 }
733 if (x + width > LCD_WIDTH)
734 width = LCD_WIDTH - x;
735 if (y + height > LCD_HEIGHT)
736 height = LCD_HEIGHT - y;
706 737
707 stride = nx; /* otherwise right-clipping will destroy the image */ 738 src += stride * (src_y >> 3) + src_x; /* move starting point */
739 src_y &= 7;
740 y -= src_y;
741 dst = &lcd_framebuffer[y>>3][x];
742 shift = y & 7;
743 ny = height - 1 + shift + src_y;
708 744
709 if (((unsigned) (x + nx)) >= LCD_WIDTH) 745 bfunc = blockfunc[drawmode];
710 nx = LCD_WIDTH - x; 746 mask = 0xFFu << (shift + src_y);
711 if (((unsigned) (y + ny)) >= LCD_HEIGHT) 747 mask_bottom = 0xFFu >> (7 - (ny & 7));
712 ny = LCD_HEIGHT - y;
713
714 dst = &lcd_framebuffer[y >> 3][x];
715 shift = y & 7;
716 748
717 if (!shift && clear) /* shortcut for byte aligned match with clear */ 749 if (shift == 0)
718 { 750 {
719 while (ny >= 8) /* all full rows */ 751 bool copyopt = (drawmode == DRMODE_SOLID);
752
753 for (; ny >= 8; ny -= 8)
720 { 754 {
721 memcpy(dst, src, nx); 755 if (copyopt && (mask == 0xFFu))
756 memcpy(dst, src, width);
757 else
758 {
759 const unsigned char *src_row = src;
760 unsigned char *dst_row = dst;
761
762 for (i = width; i > 0; i--)
763 bfunc(dst_row++, mask, *src_row++);
764 }
765
722 src += stride; 766 src += stride;
723 dst += LCD_WIDTH; 767 dst += LCD_WIDTH;
724 ny -= 8; 768 mask = 0xFFu;
725 } 769 }
726 if (ny == 0) /* nothing left to do? */ 770 mask_bottom &= mask;
727 return;
728 /* last partial row to do by default routine */
729 }
730
731 ny += shift;
732 771
733 /* Calculate bit masks */ 772 if (copyopt && (mask_bottom == 0xFFu))
734 mask4 = ~(0xfe << ((ny-1) & 7)); /* data mask for last partial row */ 773 memcpy(dst, src, width);
735 if (clear) 774 else
736 { 775 {
737 mask1 = ~(0xff << shift); /* clearing of first partial row */ 776 for (i = width; i > 0; i--)
738 mask2 = 0; /* clearing of intermediate (full) rows */ 777 bfunc(dst++, mask_bottom, *src++);
739 mask3 = ~mask4; /* clearing of last partial row */ 778 }
740 if (ny <= 8)
741 mask3 |= mask1;
742 } 779 }
743 else 780 else
744 mask1 = mask2 = mask3 = 0xff;
745
746 /* Loop for each column */
747 for (x = 0; x < nx; x++)
748 { 781 {
749 src_col = src++; 782 for (x = 0; x < width; x++)
750 dst_col = dst++;
751 data = 0;
752 y = 0;
753
754 if (ny > 8)
755 { 783 {
756 /* First partial row */ 784 const unsigned char *src_col = src++;
757 data = *src_col << shift; 785 unsigned char *dst_col = dst++;
758 *dst_col = (*dst_col & mask1) | data; 786 unsigned mask_col = mask;
759 src_col += stride; 787 unsigned data = 0;
760 dst_col += LCD_WIDTH; 788
761 data >>= 8; 789 for (y = ny; y >= 8; y -= 8)
762
763 /* Intermediate rows */
764 for (y = 8; y < ny-8; y += 8)
765 { 790 {
766 data |= *src_col << shift; 791 data |= *src_col << shift;
767 *dst_col = (*dst_col & mask2) | data; 792
793 if (mask_col & 0xFFu)
794 {
795 bfunc(dst_col, mask_col, data);
796 mask_col = 0xFFu;
797 }
798 else
799 mask_col >>= 8;
800
768 src_col += stride; 801 src_col += stride;
769 dst_col += LCD_WIDTH; 802 dst_col += LCD_WIDTH;
770 data >>= 8; 803 data >>= 8;
771 } 804 }
772 }
773
774 /* Last partial row */
775 if (y + shift < ny)
776 data |= *src_col << shift; 805 data |= *src_col << shift;
777 *dst_col = (*dst_col & mask3) | (data & mask4); 806 bfunc(dst_col, mask_col & mask_bottom, data);
807 }
778 } 808 }
779} 809}
780 810
811/* Draw a full bitmap */
812void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
813{
814 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
815}
816
781/* put a string at a given pixel position, skipping first ofs pixel columns */ 817/* put a string at a given pixel position, skipping first ofs pixel columns */
782static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 818static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
783{ 819{
@@ -786,7 +822,8 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
786 822
787 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 823 while ((ch = *str++) != '\0' && x < LCD_WIDTH)
788 { 824 {
789 int gwidth, width; 825 int width;
826 const unsigned char *bits;
790 827
791 /* check input range */ 828 /* check input range */
792 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) 829 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
@@ -794,44 +831,23 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
794 ch -= pf->firstchar; 831 ch -= pf->firstchar;
795 832
796 /* get proportional width and glyph bits */ 833 /* get proportional width and glyph bits */
797 gwidth = pf->width ? pf->width[ch] : pf->maxwidth; 834 width = pf->width ? pf->width[ch] : pf->maxwidth;
798 width = MIN (gwidth, LCD_WIDTH - x);
799 835
800 if (ofs != 0) 836 if (ofs > width)
801 { 837 {
802 if (ofs > width) 838 ofs -= width;
803 { 839 continue;
804 ofs -= width;
805 continue;
806 }
807 width -= ofs;
808 } 840 }
809 841
810 if (width > 0) 842 bits = pf->bits + (pf->offset ?
811 { 843 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
812 unsigned int i;
813 const unsigned char* bits = pf->bits +
814 (pf->offset ? pf->offset[ch]
815 : ((pf->height + 7) / 8 * pf->maxwidth * ch));
816 844
817 if (ofs != 0) 845 lcd_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
818 { 846
819 for (i = 0; i < pf->height; i += 8) 847 x += width - ofs;
820 {
821 lcd_bitmap (bits + ofs, x, y + i, width,
822 MIN(8, pf->height - i), true);
823 bits += gwidth;
824 }
825 }
826 else
827 lcd_bitmap ((unsigned char*) bits, x, y, gwidth,
828 pf->height, true);
829 x += width;
830 }
831 ofs = 0; 848 ofs = 0;
832 } 849 }
833} 850}
834
835/* put a string at a given pixel position */ 851/* put a string at a given pixel position */
836void lcd_putsxy(int x, int y, const unsigned char *str) 852void lcd_putsxy(int x, int y, const unsigned char *str)
837{ 853{
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index 7456aa77a9..6a6a8e8697 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -57,8 +57,8 @@ extern void lcd_icon(int icon, bool enable);
57 57
58#if defined(SIMULATOR) || defined(HAVE_LCD_BITMAP) 58#if defined(SIMULATOR) || defined(HAVE_LCD_BITMAP)
59/* performance function */ 59/* performance function */
60extern void lcd_blit(const unsigned char* p_data, int x, int y, int width, 60extern void lcd_blit(const unsigned char* data, int x, int by, int width,
61 int height, int stride); 61 int bheight, int stride);
62 62
63extern void lcd_update(void); 63extern void lcd_update(void);
64/* update a fraction of the screen */ 64/* update a fraction of the screen */
@@ -150,8 +150,9 @@ extern void lcd_hline(int x1, int x2, int y);
150extern void lcd_vline(int x, int y1, int y2); 150extern void lcd_vline(int x, int y1, int y2);
151extern void lcd_drawrect(int x, int y, int width, int height); 151extern void lcd_drawrect(int x, int y, int width, int height);
152extern void lcd_fillrect(int x, int y, int width, int height); 152extern void lcd_fillrect(int x, int y, int width, int height);
153extern void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, 153extern void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
154 bool clear); 154 int stride, int x, int y, int width, int height);
155extern void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny);
155extern void lcd_putsxy(int x, int y, const unsigned char *string); 156extern void lcd_putsxy(int x, int y, const unsigned char *string);
156 157
157extern void lcd_invertscroll(int x, int y); 158extern void lcd_invertscroll(int x, int y);