1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Bitmap graphics on player LCD!
12 * Copyright (C) 2005 Jens Arnold
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
26 #ifdef HAVE_LCD_CHARCELLS /* Player only :) */
27 #include "playergfx.h"
31 static int char_width
;
32 static int char_height
;
33 static int pixel_height
;
34 static int pixel_width
;
35 static unsigned long gfx_chars
[8];
36 static unsigned char gfx_buffer
[56];
37 static int drawmode
= DRMODE_SOLID
;
39 /*** Special functions ***/
42 bool pgfx_init(int cwidth
, int cheight
)
46 if (((unsigned) cwidth
* (unsigned) cheight
) > 8 || (unsigned) cheight
> 2)
50 char_height
= cheight
;
51 pixel_height
= 7 * char_height
;
52 pixel_width
= 5 * char_width
;
54 for (i
= 0; i
< cwidth
* cheight
; i
++)
56 if ((gfx_chars
[i
] = rb
->lcd_get_locked_pattern()) == 0)
67 void pgfx_release(void)
71 for (i
= 0; i
< 8; i
++)
73 rb
->lcd_unlock_pattern(gfx_chars
[i
]);
76 /* place the display */
77 void pgfx_display(int cx
, int cy
)
80 int width
= MIN(char_width
, 11 - cx
);
81 int height
= MIN(char_height
, 2 - cy
);
83 for (i
= 0; i
< width
; i
++)
84 for (j
= 0; j
< height
; j
++)
85 rb
->lcd_putc(cx
+ i
, cy
+ j
, gfx_chars
[char_height
* i
+ j
]);
88 void pgfx_display_block(int cx
, int cy
, int x
, int y
)
90 rb
->lcd_putc(cx
, cy
, gfx_chars
[char_height
* x
+ y
]);
94 /*** Update functions ***/
96 void pgfx_update(void)
100 for (i
= 0; i
< char_width
* char_height
; i
++)
101 rb
->lcd_define_pattern(gfx_chars
[i
], gfx_buffer
+ 7 * i
);
106 /*** Parameter handling ***/
108 void pgfx_set_drawmode(int mode
)
110 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
113 int pgfx_get_drawmode(void)
118 /*** Low-level drawing functions ***/
120 static void setpixel(int x
, int y
)
122 gfx_buffer
[pixel_height
* (x
/5) + y
] |= 0x10 >> (x
%5);
125 static void clearpixel(int x
, int y
)
127 gfx_buffer
[pixel_height
* (x
/5) + y
] &= ~(0x10 >> (x
%5));
130 static void flippixel(int x
, int y
)
132 gfx_buffer
[pixel_height
* (x
/5) + y
] ^= 0x10 >> (x
%5);
135 static void nopixel(int x
, int y
)
141 lcd_pixelfunc_type
* pgfx_pixelfuncs
[8] = {
142 flippixel
, nopixel
, setpixel
, setpixel
,
143 nopixel
, clearpixel
, nopixel
, clearpixel
146 static void flipblock(unsigned char *address
, unsigned mask
, unsigned bits
)
148 *address
^= (bits
& mask
);
151 static void bgblock(unsigned char *address
, unsigned mask
, unsigned bits
)
153 *address
&= (bits
| ~mask
);
156 static void fgblock(unsigned char *address
, unsigned mask
, unsigned bits
)
158 *address
|= (bits
& mask
);
161 static void solidblock(unsigned char *address
, unsigned mask
, unsigned bits
)
163 unsigned data
= *(char *)address
;
166 *address
= data
^ (bits
& mask
);
169 static void flipinvblock(unsigned char *address
, unsigned mask
, unsigned bits
)
171 *address
^= (~bits
& mask
);
174 static void bginvblock(unsigned char *address
, unsigned mask
, unsigned bits
)
176 *address
&= ~(bits
& mask
);
179 static void fginvblock(unsigned char *address
, unsigned mask
, unsigned bits
)
181 *address
|= (~bits
& mask
);
184 static void solidinvblock(unsigned char *address
, unsigned mask
, unsigned bits
)
186 unsigned data
= *(char *)address
;
189 *address
= data
^ (bits
& mask
);
192 lcd_blockfunc_type
* pgfx_blockfuncs
[8] = {
193 flipblock
, bgblock
, fgblock
, solidblock
,
194 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
197 /*** Drawing functions ***/
199 /* Clear the whole display */
200 void pgfx_clear_display(void)
202 unsigned bits
= (drawmode
& DRMODE_INVERSEVID
) ? 0x1F : 0;
204 rb
->memset(gfx_buffer
, bits
, char_width
* pixel_height
);
207 /* Set a single pixel */
208 void pgfx_drawpixel(int x
, int y
)
210 if (((unsigned)x
< (unsigned)pixel_width
)
211 && ((unsigned)y
< (unsigned)pixel_height
))
212 pgfx_pixelfuncs
[drawmode
](x
, y
);
216 void pgfx_drawline(int x1
, int y1
, int x2
, int y2
)
224 lcd_pixelfunc_type
*pfunc
= pgfx_pixelfuncs
[drawmode
];
226 deltax
= abs(x2
- x1
);
227 deltay
= abs(y2
- y1
);
231 if (deltax
>= deltay
)
234 d
= 2 * deltay
- deltax
;
236 dinc2
= (deltay
- deltax
) * 2;
243 d
= 2 * deltax
- deltay
;
245 dinc2
= (deltax
- deltay
) * 2;
249 numpixels
++; /* include endpoints */
266 for (i
= 0; i
< numpixels
; i
++)
268 if (((unsigned)x
< (unsigned)pixel_width
)
269 && ((unsigned)y
< (unsigned)pixel_height
))
287 /* Draw a horizontal line (optimised) */
288 void pgfx_hline(int x1
, int x2
, int y
)
292 unsigned mask
, mask_right
;
293 lcd_blockfunc_type
*bfunc
;
303 /* nothing to draw? */
304 if (((unsigned)y
>= (unsigned)pixel_height
) || (x1
>= pixel_width
)
311 if (x2
>= pixel_width
)
312 x2
= pixel_width
- 1;
314 bfunc
= pgfx_blockfuncs
[drawmode
];
315 dst
= &gfx_buffer
[pixel_height
* (x1
/5) + y
];
316 nx
= x2
- (x1
- (x1
% 5));
317 mask
= 0x1F >> (x1
% 5);
318 mask_right
= 0x1F0 >> (nx
% 5);
320 for (; nx
>= 5; nx
-= 5)
322 bfunc(dst
, mask
, 0xFFu
);
327 bfunc(dst
, mask
, 0x1F);
330 /* Draw a vertical line (optimised) */
331 void pgfx_vline(int x
, int y1
, int y2
)
334 unsigned char *dst
, *dst_end
;
336 lcd_blockfunc_type
*bfunc
;
346 /* nothing to draw? */
347 if (((unsigned)x
>= (unsigned)pixel_width
) || (y1
>= pixel_height
)
354 if (y2
>= pixel_height
)
355 y2
= pixel_height
- 1;
357 bfunc
= pgfx_blockfuncs
[drawmode
];
358 dst
= &gfx_buffer
[pixel_height
* (x
/5) + y1
];
359 mask
= 0x10 >> (x
% 5);
361 dst_end
= dst
+ y2
- y1
;
363 bfunc(dst
++, mask
, 0x1F);
364 while (dst
<= dst_end
);
367 /* Draw a rectangular box */
368 void pgfx_drawrect(int x
, int y
, int width
, int height
)
370 if ((width
<= 0) || (height
<= 0))
373 int x2
= x
+ width
- 1;
374 int y2
= y
+ height
- 1;
376 pgfx_vline(x
, y
, y2
);
377 pgfx_vline(x2
, y
, y2
);
378 pgfx_hline(x
, x2
, y
);
379 pgfx_hline(x
, x2
, y2
);
382 /* Fill a rectangular area */
383 void pgfx_fillrect(int x
, int y
, int width
, int height
)
386 unsigned char *dst
, *dst_end
;
387 unsigned mask
, mask_right
;
388 lcd_blockfunc_type
*bfunc
;
390 /* nothing to draw? */
391 if ((width
<= 0) || (height
<= 0) || (x
>= pixel_width
)
392 || (y
>= pixel_height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
406 if (x
+ width
> pixel_width
)
407 width
= pixel_width
- x
;
408 if (y
+ height
> pixel_height
)
409 height
= pixel_height
- y
;
411 bfunc
= pgfx_blockfuncs
[drawmode
];
412 dst
= &gfx_buffer
[pixel_height
* (x
/5) + y
];
413 nx
= width
- 1 + (x
% 5);
414 mask
= 0x1F >> (x
% 5);
415 mask_right
= 0x1F0 >> (nx
% 5);
417 for (; nx
>= 5; nx
-= 5)
419 unsigned char *dst_col
= dst
;
421 dst_end
= dst_col
+ height
;
423 bfunc(dst_col
++, mask
, 0x1F);
424 while (dst_col
< dst_end
);
431 dst_end
= dst
+ height
;
433 bfunc(dst
++, mask
, 0x1F);
434 while (dst
< dst_end
);
437 /* About PlayerGFX internal bitmap format:
439 * A bitmap contains one bit for every pixel that defines if that pixel is
440 * black (1) or white (0). Bits within a byte are arranged horizontally,
442 * The bytes are stored in row-major order, with byte 0 being top left,
443 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
445 * This approximates the (even more strange) internal hardware format. */
447 /* Draw a partial bitmap. stride is given in pixels */
448 void pgfx_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
449 int stride
, int x
, int y
, int width
, int height
)
452 unsigned char *dst
, *dst_end
;
453 unsigned mask
, mask_right
;
454 lcd_blockfunc_type
*bfunc
;
456 /* nothing to draw? */
457 if ((width
<= 0) || (height
<= 0) || (x
>= pixel_width
)
458 || (y
>= pixel_height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
474 if (x
+ width
> pixel_width
)
475 width
= pixel_width
- x
;
476 if (y
+ height
> pixel_height
)
477 height
= pixel_height
- y
;
479 stride
= (stride
+ 7) >> 3; /* convert to no. of bytes */
481 src
+= stride
* src_y
+ (src_x
>> 3); /* move starting point */
482 dst
= &gfx_buffer
[pixel_height
* (x
/5) + y
];
483 shift
= 3 + (x
% 5) - (src_x
& 7);
484 nx
= width
- 1 + (x
% 5);
486 bfunc
= pgfx_blockfuncs
[drawmode
];
487 mask
= 0x1F >> (x
% 5);
488 mask_right
= 0x1F0 >> (nx
% 5);
490 dst_end
= dst
+ height
;
493 const unsigned char *src_row
= src
;
494 unsigned char *dst_row
= dst
++;
495 unsigned mask_row
= mask
;
496 unsigned data
= *src_row
++;
497 int extrabits
= shift
;
499 for (x
= nx
; x
>= 5; x
-= 5)
503 data
= (data
<< 8) | *src_row
++;
506 bfunc(dst_row
, mask_row
, data
>> extrabits
);
508 dst_row
+= pixel_height
;
513 data
= (data
<< 8) | *src_row
;
516 bfunc(dst_row
, mask_row
& mask_right
, data
>> extrabits
);
520 while (dst
< dst_end
);
523 /* Draw a full bitmap */
524 void pgfx_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
526 pgfx_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
529 #endif /* HAVE_LCD_CHARCELLS */