Move the PCM/audio playback part of SDL into the target tree.
[kugel-rb.git] / apps / plugins / lib / playergfx.c
blobd07043c572f0ee452c50c75c7111096a9b75ae25
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
24 #include "plugin.h"
26 #ifdef HAVE_LCD_CHARCELLS /* Player only :) */
27 #include "playergfx.h"
29 /*** globals ***/
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 ***/
41 /* library init */
42 bool pgfx_init(int cwidth, int cheight)
44 int i;
46 if (((unsigned) cwidth * (unsigned) cheight) > 8 || (unsigned) cheight > 2)
47 return false;
49 char_width = cwidth;
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)
58 pgfx_release();
59 return false;
63 return true;
66 /* library deinit */
67 void pgfx_release(void)
69 int i;
71 for (i = 0; i < 8; i++)
72 if (gfx_chars[i])
73 rb->lcd_unlock_pattern(gfx_chars[i]);
76 /* place the display */
77 void pgfx_display(int cx, int cy)
79 int i, j;
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)
98 int i;
100 for (i = 0; i < char_width * char_height; i++)
101 rb->lcd_define_pattern(gfx_chars[i], gfx_buffer + 7 * i);
103 rb->lcd_update();
106 /*** Parameter handling ***/
108 void pgfx_set_drawmode(int mode)
110 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
113 int pgfx_get_drawmode(void)
115 return drawmode;
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)
137 (void)x;
138 (void)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;
165 bits ^= data;
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;
188 bits = ~bits ^ data;
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);
215 /* Draw a line */
216 void pgfx_drawline(int x1, int y1, int x2, int y2)
218 int numpixels;
219 int i;
220 int deltax, deltay;
221 int d, dinc1, dinc2;
222 int x, xinc1, xinc2;
223 int y, yinc1, yinc2;
224 lcd_pixelfunc_type *pfunc = pgfx_pixelfuncs[drawmode];
226 deltax = abs(x2 - x1);
227 deltay = abs(y2 - y1);
228 xinc2 = 1;
229 yinc2 = 1;
231 if (deltax >= deltay)
233 numpixels = deltax;
234 d = 2 * deltay - deltax;
235 dinc1 = deltay * 2;
236 dinc2 = (deltay - deltax) * 2;
237 xinc1 = 1;
238 yinc1 = 0;
240 else
242 numpixels = deltay;
243 d = 2 * deltax - deltay;
244 dinc1 = deltax * 2;
245 dinc2 = (deltax - deltay) * 2;
246 xinc1 = 0;
247 yinc1 = 1;
249 numpixels++; /* include endpoints */
251 if (x1 > x2)
253 xinc1 = -xinc1;
254 xinc2 = -xinc2;
257 if (y1 > y2)
259 yinc1 = -yinc1;
260 yinc2 = -yinc2;
263 x = x1;
264 y = y1;
266 for (i = 0; i < numpixels; i++)
268 if (((unsigned)x < (unsigned)pixel_width)
269 && ((unsigned)y < (unsigned)pixel_height))
270 pfunc(x, y);
272 if (d < 0)
274 d += dinc1;
275 x += xinc1;
276 y += yinc1;
278 else
280 d += dinc2;
281 x += xinc2;
282 y += yinc2;
287 /* Draw a horizontal line (optimised) */
288 void pgfx_hline(int x1, int x2, int y)
290 int nx;
291 unsigned char *dst;
292 unsigned mask, mask_right;
293 lcd_blockfunc_type *bfunc;
295 /* direction flip */
296 if (x2 < x1)
298 nx = x1;
299 x1 = x2;
300 x2 = nx;
303 /* nothing to draw? */
304 if (((unsigned)y >= (unsigned)pixel_height) || (x1 >= pixel_width)
305 || (x2 < 0))
306 return;
308 /* clipping */
309 if (x1 < 0)
310 x1 = 0;
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);
323 dst += pixel_height;
324 mask = 0x1F;
326 mask &= mask_right;
327 bfunc(dst, mask, 0x1F);
330 /* Draw a vertical line (optimised) */
331 void pgfx_vline(int x, int y1, int y2)
333 int y;
334 unsigned char *dst, *dst_end;
335 unsigned mask;
336 lcd_blockfunc_type *bfunc;
338 /* direction flip */
339 if (y2 < y1)
341 y = y1;
342 y1 = y2;
343 y2 = y;
346 /* nothing to draw? */
347 if (((unsigned)x >= (unsigned)pixel_width) || (y1 >= pixel_height)
348 || (y2 < 0))
349 return;
351 /* clipping */
352 if (y1 < 0)
353 y1 = 0;
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))
371 return;
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)
385 int nx;
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))
393 return;
395 /* clipping */
396 if (x < 0)
398 width += x;
399 x = 0;
401 if (y < 0)
403 height += y;
404 y = 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);
426 dst += pixel_height;
427 mask = 0x1F;
429 mask &= mask_right;
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,
441 * MSB at the left.
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)
451 int nx, shift;
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))
459 return;
461 /* clipping */
462 if (x < 0)
464 width += x;
465 src_x -= x;
466 x = 0;
468 if (y < 0)
470 height += y;
471 src_y -= y;
472 y = 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)
501 if (extrabits < 0)
503 data = (data << 8) | *src_row++;
504 extrabits += 8;
506 bfunc(dst_row, mask_row, data >> extrabits);
507 extrabits -= 5;
508 dst_row += pixel_height;
509 mask_row = 0x1F;
511 if (extrabits < 0)
513 data = (data << 8) | *src_row;
514 extrabits += 8;
516 bfunc(dst_row, mask_row & mask_right, data >> extrabits);
518 src += stride;
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 */