Prepare new maemo release
[maemo-rb.git] / apps / plugins / lib / playergfx.c
blobb2ba71351fc12be347bdcd2bd4278cd373ad77a0
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 #include "playergfx.h"
28 /*** globals ***/
30 static int char_width;
31 static int char_height;
32 static int pixel_height;
33 static int pixel_width;
34 static unsigned long gfx_chars[8];
35 static unsigned char gfx_buffer[56];
36 static int drawmode = DRMODE_SOLID;
38 /*** Special functions ***/
40 /* library init */
41 bool pgfx_init(int cwidth, int cheight)
43 int i;
45 if (((unsigned) cwidth * (unsigned) cheight) > 8 || (unsigned) cheight > 2)
46 return false;
48 char_width = cwidth;
49 char_height = cheight;
50 pixel_height = 7 * char_height;
51 pixel_width = 5 * char_width;
53 for (i = 0; i < cwidth * cheight; i++)
55 if ((gfx_chars[i] = rb->lcd_get_locked_pattern()) == 0)
57 pgfx_release();
58 return false;
62 return true;
65 /* library deinit */
66 void pgfx_release(void)
68 int i;
70 for (i = 0; i < 8; i++)
71 if (gfx_chars[i])
72 rb->lcd_unlock_pattern(gfx_chars[i]);
75 /* place the display */
76 void pgfx_display(int cx, int cy)
78 int i, j;
79 int width = MIN(char_width, 11 - cx);
80 int height = MIN(char_height, 2 - cy);
82 for (i = 0; i < width; i++)
83 for (j = 0; j < height; j++)
84 rb->lcd_putc(cx + i, cy + j, gfx_chars[char_height * i + j]);
87 void pgfx_display_block(int cx, int cy, int x, int y)
89 rb->lcd_putc(cx, cy, gfx_chars[char_height * x + y]);
93 /*** Update functions ***/
95 void pgfx_update(void)
97 int i;
99 for (i = 0; i < char_width * char_height; i++)
100 rb->lcd_define_pattern(gfx_chars[i], gfx_buffer + 7 * i);
102 rb->lcd_update();
105 /*** Parameter handling ***/
107 void pgfx_set_drawmode(int mode)
109 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
112 int pgfx_get_drawmode(void)
114 return drawmode;
117 /*** Low-level drawing functions ***/
119 static void setpixel(int x, int y)
121 gfx_buffer[pixel_height * (x/5) + y] |= 0x10 >> (x%5);
124 static void clearpixel(int x, int y)
126 gfx_buffer[pixel_height * (x/5) + y] &= ~(0x10 >> (x%5));
129 static void flippixel(int x, int y)
131 gfx_buffer[pixel_height * (x/5) + y] ^= 0x10 >> (x%5);
134 static void nopixel(int x, int y)
136 (void)x;
137 (void)y;
140 lcd_pixelfunc_type* pgfx_pixelfuncs[8] = {
141 flippixel, nopixel, setpixel, setpixel,
142 nopixel, clearpixel, nopixel, clearpixel
145 static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
147 *address ^= (bits & mask);
150 static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
152 *address &= (bits | ~mask);
155 static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
157 *address |= (bits & mask);
160 static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
162 unsigned data = *(char *)address;
164 bits ^= data;
165 *address = data ^ (bits & mask);
168 static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
170 *address ^= (~bits & mask);
173 static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
175 *address &= ~(bits & mask);
178 static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
180 *address |= (~bits & mask);
183 static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
185 unsigned data = *(char *)address;
187 bits = ~bits ^ data;
188 *address = data ^ (bits & mask);
191 lcd_blockfunc_type* pgfx_blockfuncs[8] = {
192 flipblock, bgblock, fgblock, solidblock,
193 flipinvblock, bginvblock, fginvblock, solidinvblock
196 /*** Drawing functions ***/
198 /* Clear the whole display */
199 void pgfx_clear_display(void)
201 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0x1F : 0;
203 rb->memset(gfx_buffer, bits, char_width * pixel_height);
206 /* Set a single pixel */
207 void pgfx_drawpixel(int x, int y)
209 if (((unsigned)x < (unsigned)pixel_width)
210 && ((unsigned)y < (unsigned)pixel_height))
211 pgfx_pixelfuncs[drawmode](x, y);
214 /* Draw a line */
215 void pgfx_drawline(int x1, int y1, int x2, int y2)
217 int numpixels;
218 int i;
219 int deltax, deltay;
220 int d, dinc1, dinc2;
221 int x, xinc1, xinc2;
222 int y, yinc1, yinc2;
223 lcd_pixelfunc_type *pfunc = pgfx_pixelfuncs[drawmode];
225 deltax = abs(x2 - x1);
226 deltay = abs(y2 - y1);
227 xinc2 = 1;
228 yinc2 = 1;
230 if (deltax >= deltay)
232 numpixels = deltax;
233 d = 2 * deltay - deltax;
234 dinc1 = deltay * 2;
235 dinc2 = (deltay - deltax) * 2;
236 xinc1 = 1;
237 yinc1 = 0;
239 else
241 numpixels = deltay;
242 d = 2 * deltax - deltay;
243 dinc1 = deltax * 2;
244 dinc2 = (deltax - deltay) * 2;
245 xinc1 = 0;
246 yinc1 = 1;
248 numpixels++; /* include endpoints */
250 if (x1 > x2)
252 xinc1 = -xinc1;
253 xinc2 = -xinc2;
256 if (y1 > y2)
258 yinc1 = -yinc1;
259 yinc2 = -yinc2;
262 x = x1;
263 y = y1;
265 for (i = 0; i < numpixels; i++)
267 if (((unsigned)x < (unsigned)pixel_width)
268 && ((unsigned)y < (unsigned)pixel_height))
269 pfunc(x, y);
271 if (d < 0)
273 d += dinc1;
274 x += xinc1;
275 y += yinc1;
277 else
279 d += dinc2;
280 x += xinc2;
281 y += yinc2;
286 /* Draw a horizontal line (optimised) */
287 void pgfx_hline(int x1, int x2, int y)
289 int nx;
290 unsigned char *dst;
291 unsigned mask, mask_right;
292 lcd_blockfunc_type *bfunc;
294 /* direction flip */
295 if (x2 < x1)
297 nx = x1;
298 x1 = x2;
299 x2 = nx;
302 /* nothing to draw? */
303 if (((unsigned)y >= (unsigned)pixel_height) || (x1 >= pixel_width)
304 || (x2 < 0))
305 return;
307 /* clipping */
308 if (x1 < 0)
309 x1 = 0;
310 if (x2 >= pixel_width)
311 x2 = pixel_width - 1;
313 bfunc = pgfx_blockfuncs[drawmode];
314 dst = &gfx_buffer[pixel_height * (x1/5) + y];
315 nx = x2 - (x1 - (x1 % 5));
316 mask = 0x1F >> (x1 % 5);
317 mask_right = 0x1F0 >> (nx % 5);
319 for (; nx >= 5; nx -= 5)
321 bfunc(dst, mask, 0xFFu);
322 dst += pixel_height;
323 mask = 0x1F;
325 mask &= mask_right;
326 bfunc(dst, mask, 0x1F);
329 /* Draw a vertical line (optimised) */
330 void pgfx_vline(int x, int y1, int y2)
332 int y;
333 unsigned char *dst, *dst_end;
334 unsigned mask;
335 lcd_blockfunc_type *bfunc;
337 /* direction flip */
338 if (y2 < y1)
340 y = y1;
341 y1 = y2;
342 y2 = y;
345 /* nothing to draw? */
346 if (((unsigned)x >= (unsigned)pixel_width) || (y1 >= pixel_height)
347 || (y2 < 0))
348 return;
350 /* clipping */
351 if (y1 < 0)
352 y1 = 0;
353 if (y2 >= pixel_height)
354 y2 = pixel_height - 1;
356 bfunc = pgfx_blockfuncs[drawmode];
357 dst = &gfx_buffer[pixel_height * (x/5) + y1];
358 mask = 0x10 >> (x % 5);
360 dst_end = dst + y2 - y1;
362 bfunc(dst++, mask, 0x1F);
363 while (dst <= dst_end);
366 /* Draw a rectangular box */
367 void pgfx_drawrect(int x, int y, int width, int height)
369 if ((width <= 0) || (height <= 0))
370 return;
372 int x2 = x + width - 1;
373 int y2 = y + height - 1;
375 pgfx_vline(x, y, y2);
376 pgfx_vline(x2, y, y2);
377 pgfx_hline(x, x2, y);
378 pgfx_hline(x, x2, y2);
381 /* Fill a rectangular area */
382 void pgfx_fillrect(int x, int y, int width, int height)
384 int nx;
385 unsigned char *dst, *dst_end;
386 unsigned mask, mask_right;
387 lcd_blockfunc_type *bfunc;
389 /* nothing to draw? */
390 if ((width <= 0) || (height <= 0) || (x >= pixel_width)
391 || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0))
392 return;
394 /* clipping */
395 if (x < 0)
397 width += x;
398 x = 0;
400 if (y < 0)
402 height += y;
403 y = 0;
405 if (x + width > pixel_width)
406 width = pixel_width - x;
407 if (y + height > pixel_height)
408 height = pixel_height - y;
410 bfunc = pgfx_blockfuncs[drawmode];
411 dst = &gfx_buffer[pixel_height * (x/5) + y];
412 nx = width - 1 + (x % 5);
413 mask = 0x1F >> (x % 5);
414 mask_right = 0x1F0 >> (nx % 5);
416 for (; nx >= 5; nx -= 5)
418 unsigned char *dst_col = dst;
420 dst_end = dst_col + height;
422 bfunc(dst_col++, mask, 0x1F);
423 while (dst_col < dst_end);
425 dst += pixel_height;
426 mask = 0x1F;
428 mask &= mask_right;
430 dst_end = dst + height;
432 bfunc(dst++, mask, 0x1F);
433 while (dst < dst_end);
436 /* About PlayerGFX internal bitmap format:
438 * A bitmap contains one bit for every pixel that defines if that pixel is
439 * black (1) or white (0). Bits within a byte are arranged horizontally,
440 * MSB at the left.
441 * The bytes are stored in row-major order, with byte 0 being top left,
442 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
444 * This approximates the (even more strange) internal hardware format. */
446 /* Draw a partial bitmap. stride is given in pixels */
447 void pgfx_bitmap_part(const unsigned char *src, int src_x, int src_y,
448 int stride, int x, int y, int width, int height)
450 int nx, shift;
451 unsigned char *dst, *dst_end;
452 unsigned mask, mask_right;
453 lcd_blockfunc_type *bfunc;
455 /* nothing to draw? */
456 if ((width <= 0) || (height <= 0) || (x >= pixel_width)
457 || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0))
458 return;
460 /* clipping */
461 if (x < 0)
463 width += x;
464 src_x -= x;
465 x = 0;
467 if (y < 0)
469 height += y;
470 src_y -= y;
471 y = 0;
473 if (x + width > pixel_width)
474 width = pixel_width - x;
475 if (y + height > pixel_height)
476 height = pixel_height - y;
478 stride = (stride + 7) >> 3; /* convert to no. of bytes */
480 src += stride * src_y + (src_x >> 3); /* move starting point */
481 dst = &gfx_buffer[pixel_height * (x/5) + y];
482 shift = 3 + (x % 5) - (src_x & 7);
483 nx = width - 1 + (x % 5);
485 bfunc = pgfx_blockfuncs[drawmode];
486 mask = 0x1F >> (x % 5);
487 mask_right = 0x1F0 >> (nx % 5);
489 dst_end = dst + height;
492 const unsigned char *src_row = src;
493 unsigned char *dst_row = dst++;
494 unsigned mask_row = mask;
495 unsigned data = *src_row++;
496 int extrabits = shift;
498 for (x = nx; x >= 5; x -= 5)
500 if (extrabits < 0)
502 data = (data << 8) | *src_row++;
503 extrabits += 8;
505 bfunc(dst_row, mask_row, data >> extrabits);
506 extrabits -= 5;
507 dst_row += pixel_height;
508 mask_row = 0x1F;
510 if (extrabits < 0)
512 data = (data << 8) | *src_row;
513 extrabits += 8;
515 bfunc(dst_row, mask_row & mask_right, data >> extrabits);
517 src += stride;
519 while (dst < dst_end);
522 /* Draw a full bitmap */
523 void pgfx_bitmap(const unsigned char *src, int x, int y, int width, int height)
525 pgfx_bitmap_part(src, 0, 0, width, x, y, width, height);