diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/lcd-h100.c | 355 | ||||
-rw-r--r-- | firmware/drivers/lcd-recorder.c | 360 |
2 files changed, 373 insertions, 342 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! */ |
212 | void lcd_blit(const unsigned char* p_data, int x, int y, int width, | 212 | void 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. */ |
247 | void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); | 247 | void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); |
248 | void lcd_update_rect(int x_start, int y, int width, int height) | 248 | void 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 | ||
336 | lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, | 336 | lcd_pixelfunc_type* pixelfunc[8] = { |
337 | nopixel, clearpixel, nopixel, clearpixel}; | 337 | flippixel, nopixel, setpixel, setpixel, |
338 | nopixel, clearpixel, nopixel, clearpixel | ||
339 | }; | ||
338 | 340 | ||
339 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | 341 | static 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 | ||
359 | lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; | 361 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) |
362 | { | ||
363 | *address ^= (~bits & mask); | ||
364 | } | ||
365 | |||
366 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
367 | { | ||
368 | *address &= ~(bits & mask); | ||
369 | } | ||
370 | |||
371 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
372 | { | ||
373 | *address |= (~bits & mask); | ||
374 | } | ||
375 | |||
376 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
377 | { | ||
378 | *address = (*address & ~mask) | (~bits & mask); | ||
379 | } | ||
380 | |||
381 | lcd_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() */ | ||
551 | static 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 */ |
561 | void lcd_fillrect(int x, int y, int width, int height) | 567 | void 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 */ | 645 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, |
637 | void 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"))); |
639 | void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, | 648 | void 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 */ | ||
753 | void 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 */ |
725 | static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) | 759 | static 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! */ |
269 | void lcd_blit(const unsigned char* p_data, int x, int y, int width, | 269 | void 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. */ |
304 | void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); | 304 | void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); |
305 | void lcd_update_rect(int x_start, int y, int width, int height) | 305 | void 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 | ||
393 | lcd_pixelfunc_type* pixelfunc[8] = {flippixel, nopixel, setpixel, setpixel, | 395 | lcd_pixelfunc_type* pixelfunc[8] = { |
394 | nopixel, clearpixel, nopixel, clearpixel}; | 396 | flippixel, nopixel, setpixel, setpixel, |
397 | nopixel, clearpixel, nopixel, clearpixel | ||
398 | }; | ||
395 | 399 | ||
396 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | 400 | static 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 | ||
416 | lcd_blockfunc_type* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock}; | 420 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) |
421 | { | ||
422 | *address ^= (~bits & mask); | ||
423 | } | ||
424 | |||
425 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
426 | { | ||
427 | *address &= ~(bits & mask); | ||
428 | } | ||
429 | |||
430 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
431 | { | ||
432 | *address |= (~bits & mask); | ||
433 | } | ||
434 | |||
435 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
436 | { | ||
437 | *address = (*address & ~mask) | (~bits & mask); | ||
438 | } | ||
439 | |||
440 | lcd_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() */ | ||
608 | static 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 */ |
618 | void lcd_fillrect(int x, int y, int width, int height) | 626 | void 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 */ | 704 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, |
694 | void 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"))); |
696 | void lcd_bitmap(const unsigned char *src, int x, int y, int nx, int ny, | 707 | void 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 */ | ||
812 | void 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 */ |
782 | static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) | 818 | static 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 */ |
836 | void lcd_putsxy(int x, int y, const unsigned char *str) | 852 | void lcd_putsxy(int x, int y, const unsigned char *str) |
837 | { | 853 | { |