summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd-h100.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-h100.c')
-rw-r--r--firmware/drivers/lcd-h100.c370
1 files changed, 285 insertions, 85 deletions
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index 1a40a2535c..dcc5a42e5d 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -60,8 +60,16 @@
60 60
61/*** globals ***/ 61/*** globals ***/
62 62
63unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH] IDATA_ATTR; 63unsigned char lcd_framebuffer[LCD_HEIGHT/4][LCD_WIDTH] IDATA_ATTR;
64 64
65/* should be 'const', but this causes a section type conflict */
66static unsigned char dibits[16] IDATA_ATTR = {
67 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
68 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
69};
70
71static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */
72static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */
65static int drawmode = DRMODE_SOLID; 73static int drawmode = DRMODE_SOLID;
66static int xmargin = 0; 74static int xmargin = 0;
67static int ymargin = 0; 75static int ymargin = 0;
@@ -131,14 +139,8 @@ void lcd_set_flip(bool yesno)
131 * The value must be 0 <= pixels < LCD_HEIGHT. */ 139 * The value must be 0 <= pixels < LCD_HEIGHT. */
132void lcd_roll(int lines) 140void lcd_roll(int lines)
133{ 141{
134 char data[2];
135
136 lines &= LCD_HEIGHT-1; 142 lines &= LCD_HEIGHT-1;
137 data[0] = lines & 0xff; 143 lcd_write_command_ex(LCD_CNTL_DISPLAY_START_LINE, lines, -1);
138 data[1] = lines >> 8;
139
140 lcd_write_command(LCD_CNTL_DISPLAY_START_LINE);
141 lcd_write_data(data, 2);
142} 144}
143 145
144#endif /* !SIMULATOR */ 146#endif /* !SIMULATOR */
@@ -157,15 +159,15 @@ void lcd_init(void)
157{ 159{
158 /* GPO35 is the LCD A0 pin 160 /* GPO35 is the LCD A0 pin
159 GPO46 is LCD RESET */ 161 GPO46 is LCD RESET */
160 GPIO1_OUT |= 0x00004008; 162 or_l(0x00004008, &GPIO1_OUT);
161 GPIO1_ENABLE |= 0x00004008; 163 or_l(0x00004008, &GPIO1_ENABLE);
162 GPIO1_FUNCTION |= 0x00004008; 164 or_l(0x00004008, &GPIO1_FUNCTION);
163 165
164 /* Reset LCD */ 166 /* Reset LCD */
165 sleep(1); 167 sleep(1);
166 GPIO1_OUT &= ~0x00004000; 168 and_l(~0x00004000, &GPIO1_OUT);
167 sleep(1); 169 sleep(1);
168 GPIO1_OUT |= 0x00004000; 170 or_l(0x00004000, &GPIO1_OUT);
169 sleep(1); 171 sleep(1);
170 172
171 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0); /* Normal */ 173 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0); /* Normal */
@@ -190,7 +192,7 @@ void lcd_init(void)
190 192
191 lcd_write_command_ex(LCD_CNTL_DISPLAY_START_LINE, 0, -1); 193 lcd_write_command_ex(LCD_CNTL_DISPLAY_START_LINE, 0, -1);
192 lcd_write_command_ex(LCD_CNTL_GRAY_SCALE_PATTERN, 0x42, -1); 194 lcd_write_command_ex(LCD_CNTL_GRAY_SCALE_PATTERN, 0x42, -1);
193 lcd_write_command_ex(LCD_CNTL_DISPLAY_MODE, 1, -1); /* Monochrome mode */ 195 lcd_write_command_ex(LCD_CNTL_DISPLAY_MODE, 0, -1); /* Greyscale mode */
194 lcd_write_command(LCD_CNTL_DATA_INPUT_DIR | 0); /* Column mode */ 196 lcd_write_command(LCD_CNTL_DATA_INPUT_DIR | 0); /* Column mode */
195 197
196 lcd_clear_display(); 198 lcd_clear_display();
@@ -204,7 +206,7 @@ void lcd_init(void)
204/*** update functions ***/ 206/*** update functions ***/
205 207
206/* Performance function that works with an external buffer 208/* Performance function that works with an external buffer
207 note that by and bheight are in 8-pixel units! */ 209 note that by and bheight are in 4-pixel units! */
208void lcd_blit(const unsigned char* data, int x, int by, int width, 210void lcd_blit(const unsigned char* data, int x, int by, int width,
209 int bheight, int stride) 211 int bheight, int stride)
210{ 212{
@@ -223,13 +225,13 @@ void lcd_blit(const unsigned char* data, int x, int by, int width,
223 225
224/* Update the display. 226/* Update the display.
225 This must be called after all other LCD functions that change the display. */ 227 This must be called after all other LCD functions that change the display. */
226void lcd_update(void) __attribute__ ((section (".icode"))); 228void lcd_update(void) ICODE_ATTR;
227void lcd_update(void) 229void lcd_update(void)
228{ 230{
229 int y; 231 int y;
230 232
231 /* Copy display bitmap to hardware */ 233 /* Copy display bitmap to hardware */
232 for (y = 0; y < LCD_HEIGHT/8; y++) 234 for (y = 0; y < LCD_HEIGHT/4; y++)
233 { 235 {
234 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1); 236 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
235 lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1); 237 lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1);
@@ -240,21 +242,21 @@ void lcd_update(void)
240} 242}
241 243
242/* Update a fraction of the display. */ 244/* Update a fraction of the display. */
243void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); 245void lcd_update_rect(int, int, int, int) ICODE_ATTR;
244void lcd_update_rect(int x, int y, int width, int height) 246void lcd_update_rect(int x, int y, int width, int height)
245{ 247{
246 int ymax; 248 int ymax;
247 249
248 /* The Y coordinates have to work on even 8 pixel rows */ 250 /* The Y coordinates have to work on even 8 pixel rows */
249 ymax = (y + height-1) >> 3; 251 ymax = (y + height-1) >> 2;
250 y >>= 3; 252 y >>= 2;
251 253
252 if(x + width > LCD_WIDTH) 254 if(x + width > LCD_WIDTH)
253 width = LCD_WIDTH - x; 255 width = LCD_WIDTH - x;
254 if (width <= 0) 256 if (width <= 0)
255 return; /* nothing left to do, 0 is harmful to lcd_write_data() */ 257 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
256 if(ymax >= LCD_HEIGHT/8) 258 if(ymax >= LCD_HEIGHT/4)
257 ymax = LCD_HEIGHT/8-1; 259 ymax = LCD_HEIGHT/4-1;
258 260
259 /* Copy specified rectange bitmap to hardware */ 261 /* Copy specified rectange bitmap to hardware */
260 for (; y <= ymax; y++) 262 for (; y <= ymax; y++)
@@ -280,6 +282,26 @@ int lcd_get_drawmode(void)
280 return drawmode; 282 return drawmode;
281} 283}
282 284
285void lcd_set_foreground(int brightness)
286{
287 fg_pattern = 0x55 * (~brightness & 3);
288}
289
290int lcd_get_foreground(void)
291{
292 return ~fg_pattern & 3;
293}
294
295void lcd_set_background(int brightness)
296{
297 bg_pattern = 0x55 * (~brightness & 3);
298}
299
300int lcd_get_background(void)
301{
302 return ~bg_pattern & 3;
303}
304
283void lcd_setmargins(int x, int y) 305void lcd_setmargins(int x, int y)
284{ 306{
285 xmargin = x; 307 xmargin = x;
@@ -310,17 +332,21 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
310 332
311static void setpixel(int x, int y) 333static void setpixel(int x, int y)
312{ 334{
313 DRAW_PIXEL(x, y); 335 unsigned char *data = &lcd_framebuffer[y>>2][x];
336 unsigned mask = 3 << (2 * (y & 3));
337 *data = (*data & ~mask) | (fg_pattern & mask);
314} 338}
315 339
316static void clearpixel(int x, int y) 340static void clearpixel(int x, int y)
317{ 341{
318 CLEAR_PIXEL(x, y); 342 unsigned char *data = &lcd_framebuffer[y>>2][x];
343 unsigned mask = 3 << (2 * (y & 3));
344 *data = (*data & ~mask) | (bg_pattern & mask);
319} 345}
320 346
321static void flippixel(int x, int y) 347static void flippixel(int x, int y)
322{ 348{
323 INVERT_PIXEL(x, y); 349 lcd_framebuffer[y>>2][x] ^= 3 << (2 * (y & 3));
324} 350}
325 351
326static void nopixel(int x, int y) 352static void nopixel(int x, int y)
@@ -333,61 +359,68 @@ lcd_pixelfunc_type* lcd_pixelfuncs[8] = {
333 flippixel, nopixel, setpixel, setpixel, 359 flippixel, nopixel, setpixel, setpixel,
334 nopixel, clearpixel, nopixel, clearpixel 360 nopixel, clearpixel, nopixel, clearpixel
335}; 361};
336 362
363/* 'mask' and 'bits' contain 2 bits per pixel */
337static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 364static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
338 __attribute__ ((section(".icode"))); 365 ICODE_ATTR;
339static void flipblock(unsigned char *address, unsigned mask, unsigned bits) 366static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
340{ 367{
341 *address ^= (bits & mask); 368 *address ^= bits & mask;
342} 369}
343 370
344static void bgblock(unsigned char *address, unsigned mask, unsigned bits) 371static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
345 __attribute__ ((section(".icode"))); 372 ICODE_ATTR;
346static void bgblock(unsigned char *address, unsigned mask, unsigned bits) 373static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
347{ 374{
348 *address &= (bits | ~mask); 375 mask &= ~bits;
376 *address = (*address & ~mask) | (bg_pattern & mask);
349} 377}
350 378
351static void fgblock(unsigned char *address, unsigned mask, unsigned bits) 379static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
352 __attribute__ ((section(".icode"))); 380 ICODE_ATTR;
353static void fgblock(unsigned char *address, unsigned mask, unsigned bits) 381static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
354{ 382{
355 *address |= (bits & mask); 383 mask &= bits;
384 *address = (*address & ~mask) | (fg_pattern & mask);
356} 385}
357 386
358static void solidblock(unsigned char *address, unsigned mask, unsigned bits) 387static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
359 __attribute__ ((section(".icode"))); 388 ICODE_ATTR;
360static void solidblock(unsigned char *address, unsigned mask, unsigned bits) 389static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
361{ 390{
362 *address = (*address & ~mask) | (bits & mask); 391 *address = (*address & ~mask) | (bits & mask & fg_pattern)
392 | (~bits & mask & bg_pattern);
363} 393}
364 394
365static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) 395static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
366 __attribute__ ((section(".icode"))); 396 ICODE_ATTR;
367static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) 397static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
368{ 398{
369 *address ^= (~bits & mask); 399 *address ^= ~bits & mask;
370} 400}
371 401
372static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) 402static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
373 __attribute__ ((section(".icode"))); 403 ICODE_ATTR;
374static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) 404static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
375{ 405{
376 *address &= ~(bits & mask); 406 mask &= bits;
407 *address = (*address & ~mask) | (bg_pattern & mask);
377} 408}
378 409
379static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) 410static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
380 __attribute__ ((section(".icode"))); 411 ICODE_ATTR;
381static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) 412static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
382{ 413{
383 *address |= (~bits & mask); 414 mask &= ~bits;
415 *address = (*address & ~mask) | (fg_pattern & mask);
384} 416}
385 417
386static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) 418static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
387 __attribute__ ((section(".icode"))); 419 ICODE_ATTR;
388static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) 420static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
389{ 421{
390 *address = (*address & ~mask) | (~bits & mask); 422 *address = (*address & ~mask) | (~bits & mask & fg_pattern)
423 | (bits & mask & bg_pattern);
391} 424}
392 425
393lcd_blockfunc_type* lcd_blockfuncs[8] = { 426lcd_blockfunc_type* lcd_blockfuncs[8] = {
@@ -400,7 +433,7 @@ lcd_blockfunc_type* lcd_blockfuncs[8] = {
400/* Clear the whole display */ 433/* Clear the whole display */
401void lcd_clear_display(void) 434void lcd_clear_display(void)
402{ 435{
403 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; 436 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? fg_pattern : bg_pattern;
404 437
405 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer); 438 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
406 scrolling_lines = 0; 439 scrolling_lines = 0;
@@ -511,8 +544,8 @@ void lcd_hline(int x1, int x2, int y)
511 x2 = LCD_WIDTH-1; 544 x2 = LCD_WIDTH-1;
512 545
513 bfunc = lcd_blockfuncs[drawmode]; 546 bfunc = lcd_blockfuncs[drawmode];
514 dst = &lcd_framebuffer[y>>3][x1]; 547 dst = &lcd_framebuffer[y>>2][x1];
515 mask = 1 << (y & 7); 548 mask = 3 << (2 * (y & 3));
516 549
517 dst_end = dst + x2 - x1; 550 dst_end = dst + x2 - x1;
518 do 551 do
@@ -547,12 +580,12 @@ void lcd_vline(int x, int y1, int y2)
547 y2 = LCD_HEIGHT-1; 580 y2 = LCD_HEIGHT-1;
548 581
549 bfunc = lcd_blockfuncs[drawmode]; 582 bfunc = lcd_blockfuncs[drawmode];
550 dst = &lcd_framebuffer[y1>>3][x]; 583 dst = &lcd_framebuffer[y1>>2][x];
551 ny = y2 - (y1 & ~7); 584 ny = y2 - (y1 & ~3);
552 mask = 0xFFu << (y1 & 7); 585 mask = 0xFFu << (2 * (y1 & 3));
553 mask_bottom = 0xFFu >> (7 - (ny & 7)); 586 mask_bottom = 0xFFu >> (2 * (~ny & 3));
554 587
555 for (; ny >= 8; ny -= 8) 588 for (; ny >= 4; ny -= 4)
556 { 589 {
557 bfunc(dst, mask, 0xFFu); 590 bfunc(dst, mask, 0xFFu);
558 dst += LCD_WIDTH; 591 dst += LCD_WIDTH;
@@ -583,7 +616,7 @@ void lcd_fillrect(int x, int y, int width, int height)
583 int ny; 616 int ny;
584 unsigned char *dst, *dst_end; 617 unsigned char *dst, *dst_end;
585 unsigned mask, mask_bottom; 618 unsigned mask, mask_bottom;
586 unsigned bits = 0xFFu; 619 unsigned bits = fg_pattern;
587 lcd_blockfunc_type *bfunc; 620 lcd_blockfunc_type *bfunc;
588 bool fillopt; 621 bool fillopt;
589 622
@@ -611,14 +644,14 @@ void lcd_fillrect(int x, int y, int width, int height)
611 fillopt = (drawmode & DRMODE_INVERSEVID) ? 644 fillopt = (drawmode & DRMODE_INVERSEVID) ?
612 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG); 645 (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
613 if (fillopt &&(drawmode & DRMODE_INVERSEVID)) 646 if (fillopt &&(drawmode & DRMODE_INVERSEVID))
614 bits = 0; 647 bits = bg_pattern;
615 bfunc = lcd_blockfuncs[drawmode]; 648 bfunc = lcd_blockfuncs[drawmode];
616 dst = &lcd_framebuffer[y>>3][x]; 649 dst = &lcd_framebuffer[y>>2][x];
617 ny = height - 1 + (y & 7); 650 ny = height - 1 + (y & 3);
618 mask = 0xFFu << (y & 7); 651 mask = 0xFFu << (2 * (y & 3));
619 mask_bottom = 0xFFu >> (7 - (ny & 7)); 652 mask_bottom = 0xFFu >> (2 * (~ny & 3));
620 653
621 for (; ny >= 8; ny -= 8) 654 for (; ny >= 4; ny -= 4)
622 { 655 {
623 if (fillopt && (mask == 0xFFu)) 656 if (fillopt && (mask == 0xFFu))
624 memset(dst, bits, width); 657 memset(dst, bits, width);
@@ -648,7 +681,7 @@ void lcd_fillrect(int x, int y, int width, int height)
648 } 681 }
649} 682}
650 683
651/* About Rockbox' internal bitmap format: 684/* About Rockbox' internal monochrome bitmap format:
652 * 685 *
653 * A bitmap contains one bit for every pixel that defines if that pixel is 686 * A bitmap contains one bit for every pixel that defines if that pixel is
654 * black (1) or white (0). Bits within a byte are arranged vertically, LSB 687 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
@@ -657,12 +690,180 @@ void lcd_fillrect(int x, int y, int width, int height)
657 * byte 1 2nd from left etc. The first row of bytes defines pixel rows 690 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
658 * 0..7, the second row defines pixel row 8..15 etc. 691 * 0..7, the second row defines pixel row 8..15 etc.
659 * 692 *
693 * This is similar to the internal lcd hw format. */
694
695/* Draw a partial monochrome bitmap */
696void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
697 int stride, int x, int y, int width, int height)
698 ICODE_ATTR;
699void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
700 int stride, int x, int y, int width, int height)
701{
702 int shift, ny;
703 unsigned char *dst, *dst_end;
704 unsigned mask, mask_bottom;
705 lcd_blockfunc_type *bfunc;
706
707 /* nothing to draw? */
708 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
709 || (x + width <= 0) || (y + height <= 0))
710 return;
711
712 /* clipping */
713 if (x < 0)
714 {
715 width += x;
716 src_x -= x;
717 x = 0;
718 }
719 if (y < 0)
720 {
721 height += y;
722 src_y -= y;
723 y = 0;
724 }
725 if (x + width > LCD_WIDTH)
726 width = LCD_WIDTH - x;
727 if (y + height > LCD_HEIGHT)
728 height = LCD_HEIGHT - y;
729
730 src += stride * (src_y >> 3) + src_x; /* move starting point */
731 src_y &= 7;
732 y -= src_y;
733 dst = &lcd_framebuffer[y>>2][x];
734 shift = y & 3;
735 ny = height - 1 + shift + src_y;
736
737 bfunc = lcd_blockfuncs[drawmode];
738 mask = 0xFFu << (shift + src_y);
739 mask_bottom = 0xFFu >> (~ny & 7);
740
741 if (shift == 0)
742 {
743 unsigned dmask1, dmask2, data;
744
745 for (; ny >= 8; ny -= 8)
746 {
747 const unsigned char *src_row = src;
748 unsigned char *dst_row = dst + LCD_WIDTH;
749
750 dmask1 = dibits[mask&0x0F];
751 dmask2 = dibits[(mask>>4)&0x0F];
752 dst_end = dst_row + width;
753
754 if (dmask1 != 0)
755 {
756 do
757 {
758 data = *src_row++;
759 bfunc(dst_row - LCD_WIDTH, dmask1, dibits[data&0x0F]);
760 bfunc(dst_row++, dmask2, dibits[(data>>4)&0x0F]);
761 }
762 while (dst_row < dst_end);
763 }
764 else
765 {
766 do
767 bfunc(dst_row++, dmask2, dibits[((*src_row++)>>4)&0x0F]);
768 while (dst_row < dst_end);
769 }
770 src += stride;
771 dst += 2*LCD_WIDTH;
772 mask = 0xFFu;
773 }
774 mask &= mask_bottom;
775 dmask1 = dibits[mask&0x0F];
776 dmask2 = dibits[(mask>>4)&0x0F];
777 dst_end = dst + width;
778
779 if (dmask1 != 0)
780 {
781 if (dmask2 != 0)
782 {
783 do
784 {
785 data = *src++;
786 bfunc(dst, dmask1, dibits[data&0x0F]);
787 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[(data>>4)&0x0F]);
788 }
789 while (dst < dst_end);
790 }
791 else
792 {
793 do
794 bfunc(dst++, dmask1, dibits[(*src++)&0x0F]);
795 while (dst < dst_end);
796 }
797 }
798 else
799 {
800 do
801 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[((*src++)>>4)&0x0F]);
802 while (dst < dst_end);
803 }
804 }
805 else
806 {
807 dst_end = dst + width;
808 do
809 {
810 const unsigned char *src_col = src++;
811 unsigned char *dst_col = dst++;
812 unsigned mask_col = mask;
813 unsigned data = 0;
814
815 for (y = ny; y >= 8; y -= 8)
816 {
817 data |= *src_col << shift;
818
819 if (mask_col & 0xFFu)
820 {
821 if (mask_col & 0x0F)
822 bfunc(dst_col, dibits[mask_col&0x0F], dibits[data&0x0F]);
823 bfunc(dst_col + LCD_WIDTH, dibits[(mask_col>>4)&0x0F],
824 dibits[(data>>4)&0x0F]);
825 mask_col = 0xFFu;
826 }
827 else
828 mask_col >>= 8;
829
830 src_col += stride;
831 dst_col += 2*LCD_WIDTH;
832 data >>= 8;
833 }
834 data |= *src_col << shift;
835 mask_bottom &= mask_col;
836 if (mask_bottom & 0x0F)
837 bfunc(dst_col, dibits[mask_bottom&0x0F], dibits[data&0x0F]);
838 if (mask_bottom & 0xF0)
839 bfunc(dst_col + LCD_WIDTH, dibits[(mask_bottom&0xF0)>>4],
840 dibits[(data>>4)&0x0F]);
841 }
842 while (dst < dst_end);
843 }
844}
845
846/* Draw a full monochrome bitmap */
847void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
848{
849 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
850}
851
852/* About Rockbox' internal native bitmap format:
853 *
854 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
855 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
856 * at top.
857 * The bytes are stored in row-major order, with byte 0 being top left,
858 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
859 * 0..3, the second row defines pixel row 4..7 etc.
860 *
660 * This is the same as the internal lcd hw format. */ 861 * This is the same as the internal lcd hw format. */
661 862
662/* Draw a partial bitmap */ 863/* Draw a partial native bitmap */
663void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, 864void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
664 int stride, int x, int y, int width, int height) 865 int stride, int x, int y, int width, int height)
665 __attribute__ ((section(".icode"))); 866 ICODE_ATTR;
666void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, 867void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
667 int stride, int x, int y, int width, int height) 868 int stride, int x, int y, int width, int height)
668{ 869{
@@ -694,32 +895,30 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
694 if (y + height > LCD_HEIGHT) 895 if (y + height > LCD_HEIGHT)
695 height = LCD_HEIGHT - y; 896 height = LCD_HEIGHT - y;
696 897
697 src += stride * (src_y >> 3) + src_x; /* move starting point */ 898 src += stride * (src_y >> 2) + src_x; /* move starting point */
698 src_y &= 7; 899 src_y &= 3;
699 y -= src_y; 900 y -= src_y;
700 dst = &lcd_framebuffer[y>>3][x]; 901 dst = &lcd_framebuffer[y>>2][x];
701 shift = y & 7; 902 shift = y & 3;
702 ny = height - 1 + shift + src_y; 903 ny = height - 1 + shift + src_y;
703 904
704 bfunc = lcd_blockfuncs[drawmode]; 905 bfunc = lcd_blockfuncs[drawmode];
705 mask = 0xFFu << (shift + src_y); 906 mask = 0xFFu << (2 * (shift + src_y));
706 mask_bottom = 0xFFu >> (7 - (ny & 7)); 907 mask_bottom = 0xFFu >> (2 * (~ny & 3));
707 908
708 if (shift == 0) 909 if (shift == 0)
709 { 910 {
710 bool copyopt = (drawmode == DRMODE_SOLID); 911 for (; ny >= 4; ny -= 4)
711
712 for (; ny >= 8; ny -= 8)
713 { 912 {
714 if (copyopt && (mask == 0xFFu)) 913 if (mask == 0xFFu)
715 memcpy(dst, src, width); 914 memcpy(dst, src, width);
716 else 915 else
717 { 916 {
718 const unsigned char *src_row = src; 917 const unsigned char *src_row = src;
719 unsigned char *dst_row = dst; 918 unsigned char *dst_row = dst;
720 919
721 dst_end = dst_row + width; 920 dst_end = dst_row + width;
722 do 921 do
723 bfunc(dst_row++, mask, *src_row++); 922 bfunc(dst_row++, mask, *src_row++);
724 while (dst_row < dst_end); 923 while (dst_row < dst_end);
725 } 924 }
@@ -730,7 +929,7 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
730 } 929 }
731 mask &= mask_bottom; 930 mask &= mask_bottom;
732 931
733 if (copyopt && (mask == 0xFFu)) 932 if (mask == 0xFFu)
734 memcpy(dst, src, width); 933 memcpy(dst, src, width);
735 else 934 else
736 { 935 {
@@ -742,6 +941,7 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
742 } 941 }
743 else 942 else
744 { 943 {
944 shift *= 2;
745 dst_end = dst + width; 945 dst_end = dst + width;
746 do 946 do
747 { 947 {
@@ -750,7 +950,7 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
750 unsigned mask_col = mask; 950 unsigned mask_col = mask;
751 unsigned data = 0; 951 unsigned data = 0;
752 952
753 for (y = ny; y >= 8; y -= 8) 953 for (y = ny; y >= 4; y -= 4)
754 { 954 {
755 data |= *src_col << shift; 955 data |= *src_col << shift;
756 956
@@ -773,7 +973,7 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
773 } 973 }
774} 974}
775 975
776/* Draw a full bitmap */ 976/* Draw a full native bitmap */
777void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height) 977void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
778{ 978{
779 lcd_bitmap_part(src, 0, 0, width, x, y, width, height); 979 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
@@ -807,7 +1007,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
807 bits = pf->bits + (pf->offset ? 1007 bits = pf->bits + (pf->offset ?
808 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch)); 1008 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
809 1009
810 lcd_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 1010 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
811 1011
812 x += width - ofs; 1012 x += width - ofs;
813 ofs = 0; 1013 ofs = 0;
@@ -825,7 +1025,7 @@ void lcd_putsxy(int x, int y, const unsigned char *str)
825void lcd_puts_style(int x, int y, const unsigned char *str, int style) 1025void lcd_puts_style(int x, int y, const unsigned char *str, int style)
826{ 1026{
827 int xpos,ypos,w,h; 1027 int xpos,ypos,w,h;
828 int lastmode = lcd_get_drawmode(); 1028 int lastmode = drawmode;
829 1029
830 /* make sure scrolling is turned off on the line we are updating */ 1030 /* make sure scrolling is turned off on the line we are updating */
831 scrolling_lines &= ~(1 << y); 1031 scrolling_lines &= ~(1 << y);
@@ -837,14 +1037,14 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
837 xpos = xmargin + x*w / strlen(str); 1037 xpos = xmargin + x*w / strlen(str);
838 ypos = ymargin + y*h; 1038 ypos = ymargin + y*h;
839 lcd_putsxy(xpos, ypos, str); 1039 lcd_putsxy(xpos, ypos, str);
840 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 1040 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
841 lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); 1041 lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h);
842 if (style & STYLE_INVERT) 1042 if (style & STYLE_INVERT)
843 { 1043 {
844 lcd_set_drawmode(DRMODE_COMPLEMENT); 1044 drawmode = DRMODE_COMPLEMENT;
845 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); 1045 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h);
846 } 1046 }
847 lcd_set_drawmode(lastmode); 1047 drawmode = lastmode;
848} 1048}
849 1049
850/* put a string at a given char position */ 1050/* put a string at a given char position */
@@ -1006,17 +1206,17 @@ static void scroll_thread(void)
1006 s->offset %= s->width; 1206 s->offset %= s->width;
1007 } 1207 }
1008 1208
1009 lastmode = lcd_get_drawmode(); 1209 lastmode = drawmode;
1010 lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); 1210 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
1011 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1211 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1012 lcd_set_drawmode(DRMODE_SOLID); 1212 drawmode = DRMODE_SOLID;
1013 lcd_putsxyofs(xpos, ypos, s->offset, s->line); 1213 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1014 if (s->invert) 1214 if (s->invert)
1015 { 1215 {
1016 lcd_set_drawmode(DRMODE_COMPLEMENT); 1216 drawmode = DRMODE_COMPLEMENT;
1017 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1217 lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1018 } 1218 }
1019 lcd_set_drawmode(lastmode); 1219 drawmode = lastmode;
1020 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 1220 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1021 } 1221 }
1022 1222