diff options
Diffstat (limited to 'firmware/drivers/lcd-h100.c')
-rw-r--r-- | firmware/drivers/lcd-h100.c | 370 |
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 | ||
63 | unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH] IDATA_ATTR; | 63 | unsigned char lcd_framebuffer[LCD_HEIGHT/4][LCD_WIDTH] IDATA_ATTR; |
64 | 64 | ||
65 | /* should be 'const', but this causes a section type conflict */ | ||
66 | static 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 | |||
71 | static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ | ||
72 | static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ | ||
65 | static int drawmode = DRMODE_SOLID; | 73 | static int drawmode = DRMODE_SOLID; |
66 | static int xmargin = 0; | 74 | static int xmargin = 0; |
67 | static int ymargin = 0; | 75 | static 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. */ |
132 | void lcd_roll(int lines) | 140 | void 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! */ |
208 | void lcd_blit(const unsigned char* data, int x, int by, int width, | 210 | void 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. */ |
226 | void lcd_update(void) __attribute__ ((section (".icode"))); | 228 | void lcd_update(void) ICODE_ATTR; |
227 | void lcd_update(void) | 229 | void 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. */ |
243 | void lcd_update_rect(int, int, int, int) __attribute__ ((section (".icode"))); | 245 | void lcd_update_rect(int, int, int, int) ICODE_ATTR; |
244 | void lcd_update_rect(int x, int y, int width, int height) | 246 | void 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 | ||
285 | void lcd_set_foreground(int brightness) | ||
286 | { | ||
287 | fg_pattern = 0x55 * (~brightness & 3); | ||
288 | } | ||
289 | |||
290 | int lcd_get_foreground(void) | ||
291 | { | ||
292 | return ~fg_pattern & 3; | ||
293 | } | ||
294 | |||
295 | void lcd_set_background(int brightness) | ||
296 | { | ||
297 | bg_pattern = 0x55 * (~brightness & 3); | ||
298 | } | ||
299 | |||
300 | int lcd_get_background(void) | ||
301 | { | ||
302 | return ~bg_pattern & 3; | ||
303 | } | ||
304 | |||
283 | void lcd_setmargins(int x, int y) | 305 | void 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 | ||
311 | static void setpixel(int x, int y) | 333 | static 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 | ||
316 | static void clearpixel(int x, int y) | 340 | static 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 | ||
321 | static void flippixel(int x, int y) | 347 | static 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 | ||
326 | static void nopixel(int x, int y) | 352 | static 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 */ | ||
337 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | 364 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) |
338 | __attribute__ ((section(".icode"))); | 365 | ICODE_ATTR; |
339 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | 366 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) |
340 | { | 367 | { |
341 | *address ^= (bits & mask); | 368 | *address ^= bits & mask; |
342 | } | 369 | } |
343 | 370 | ||
344 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | 371 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) |
345 | __attribute__ ((section(".icode"))); | 372 | ICODE_ATTR; |
346 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | 373 | static 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 | ||
351 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | 379 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) |
352 | __attribute__ ((section(".icode"))); | 380 | ICODE_ATTR; |
353 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | 381 | static 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 | ||
358 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | 387 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) |
359 | __attribute__ ((section(".icode"))); | 388 | ICODE_ATTR; |
360 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | 389 | static 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 | ||
365 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | 395 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) |
366 | __attribute__ ((section(".icode"))); | 396 | ICODE_ATTR; |
367 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | 397 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) |
368 | { | 398 | { |
369 | *address ^= (~bits & mask); | 399 | *address ^= ~bits & mask; |
370 | } | 400 | } |
371 | 401 | ||
372 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | 402 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) |
373 | __attribute__ ((section(".icode"))); | 403 | ICODE_ATTR; |
374 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | 404 | static 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 | ||
379 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | 410 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) |
380 | __attribute__ ((section(".icode"))); | 411 | ICODE_ATTR; |
381 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | 412 | static 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 | ||
386 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | 418 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) |
387 | __attribute__ ((section(".icode"))); | 419 | ICODE_ATTR; |
388 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | 420 | static 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 | ||
393 | lcd_blockfunc_type* lcd_blockfuncs[8] = { | 426 | lcd_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 */ |
401 | void lcd_clear_display(void) | 434 | void 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 */ | ||
696 | void 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; | ||
699 | void 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 */ | ||
847 | void 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 */ |
663 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | 864 | void 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; |
666 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | 867 | void 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 */ |
777 | void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height) | 977 | void 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) | |||
825 | void lcd_puts_style(int x, int y, const unsigned char *str, int style) | 1025 | void 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 | ||