summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/playergfx.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib/playergfx.c')
-rw-r--r--apps/plugins/lib/playergfx.c375
1 files changed, 316 insertions, 59 deletions
diff --git a/apps/plugins/lib/playergfx.c b/apps/plugins/lib/playergfx.c
index 51e003b048..5b756a7727 100644
--- a/apps/plugins/lib/playergfx.c
+++ b/apps/plugins/lib/playergfx.c
@@ -24,21 +24,20 @@
24#ifdef HAVE_LCD_CHARCELLS /* Player only :) */ 24#ifdef HAVE_LCD_CHARCELLS /* Player only :) */
25#include "playergfx.h" 25#include "playergfx.h"
26 26
27/* Global variables */ 27/*** globals ***/
28
28static struct plugin_api *pgfx_rb = NULL; /* global api struct pointer */ 29static struct plugin_api *pgfx_rb = NULL; /* global api struct pointer */
29static int char_width; 30static int char_width;
30static int char_height; 31static int char_height;
31static unsigned pixel_height; 32static int pixel_height;
32static unsigned pixel_width; 33static int pixel_width;
33static unsigned char gfx_chars[8]; 34static unsigned char gfx_chars[8];
34static unsigned char gfx_buffer[56]; 35static unsigned char gfx_buffer[56];
36static int drawmode = DRMODE_SOLID;
35 37
36/* Private function declarations */ 38/*** Special functions ***/
37static void linefunc(int x1, int y1, int x2, int y2,
38 void (*pixelfunc)(int x, int y));
39
40/* Implementation */
41 39
40/* library init */
42bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight) 41bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight)
43{ 42{
44 int i; 43 int i;
@@ -64,6 +63,7 @@ bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight)
64 return true; 63 return true;
65} 64}
66 65
66/* library deinit */
67void pgfx_release(void) 67void pgfx_release(void)
68{ 68{
69 int i; 69 int i;
@@ -73,6 +73,7 @@ void pgfx_release(void)
73 pgfx_rb->lcd_unlock_pattern(gfx_chars[i]); 73 pgfx_rb->lcd_unlock_pattern(gfx_chars[i]);
74} 74}
75 75
76/* place the display */
76void pgfx_display(int cx, int cy) 77void pgfx_display(int cx, int cy)
77{ 78{
78 int i, j; 79 int i, j;
@@ -84,6 +85,8 @@ void pgfx_display(int cx, int cy)
84 pgfx_rb->lcd_putc(cx + i, cy + j, gfx_chars[char_height * i + j]); 85 pgfx_rb->lcd_putc(cx + i, cy + j, gfx_chars[char_height * i + j]);
85} 86}
86 87
88/*** Update functions ***/
89
87void pgfx_update(void) 90void pgfx_update(void)
88{ 91{
89 int i; 92 int i;
@@ -92,28 +95,111 @@ void pgfx_update(void)
92 pgfx_rb->lcd_define_pattern(gfx_chars[i], gfx_buffer + 7 * i); 95 pgfx_rb->lcd_define_pattern(gfx_chars[i], gfx_buffer + 7 * i);
93} 96}
94 97
95void pgfx_clear_display(void) 98/*** Parameter handling ***/
99
100void pgfx_set_drawmode(int mode)
96{ 101{
97 pgfx_rb->memset(gfx_buffer, 0, char_width * pixel_height); 102 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
98} 103}
99 104
100void pgfx_drawpixel(int x, int y) 105int pgfx_get_drawmode(void)
106{
107 return drawmode;
108}
109
110/*** Low-level drawing functions ***/
111
112static void setpixel(int x, int y)
101{ 113{
102 gfx_buffer[pixel_height * (x/5) + y] |= 0x10 >> (x%5); 114 gfx_buffer[pixel_height * (x/5) + y] |= 0x10 >> (x%5);
103} 115}
104 116
105void pgfx_clearpixel(int x, int y) 117static void clearpixel(int x, int y)
106{ 118{
107 gfx_buffer[pixel_height * (x/5) + y] &= ~(0x10 >> (x%5)); 119 gfx_buffer[pixel_height * (x/5) + y] &= ~(0x10 >> (x%5));
108} 120}
109 121
110void pgfx_invertpixel(int x, int y) 122static void flippixel(int x, int y)
111{ 123{
112 gfx_buffer[pixel_height * (x/5) + y] ^= 0x10 >> (x%5); 124 gfx_buffer[pixel_height * (x/5) + y] ^= 0x10 >> (x%5);
113} 125}
114 126
115static void linefunc(int x1, int y1, int x2, int y2, 127static void nopixel(int x, int y)
116 void (*pixelfunc)(int x, int y)) 128{
129 (void)x;
130 (void)y;
131}
132
133lcd_pixelfunc_type* pgfx_pixelfuncs[8] = {
134 flippixel, nopixel, setpixel, setpixel,
135 nopixel, clearpixel, nopixel, clearpixel
136};
137
138static void flipblock(unsigned char *address, unsigned mask, unsigned bits)
139{
140 *address ^= (bits & mask);
141}
142
143static void bgblock(unsigned char *address, unsigned mask, unsigned bits)
144{
145 *address &= (bits | ~mask);
146}
147
148static void fgblock(unsigned char *address, unsigned mask, unsigned bits)
149{
150 *address |= (bits & mask);
151}
152
153static void solidblock(unsigned char *address, unsigned mask, unsigned bits)
154{
155 *address = (*address & ~mask) | (bits & mask);
156}
157
158static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits)
159{
160 *address ^= (~bits & mask);
161}
162
163static void bginvblock(unsigned char *address, unsigned mask, unsigned bits)
164{
165 *address &= ~(bits & mask);
166}
167
168static void fginvblock(unsigned char *address, unsigned mask, unsigned bits)
169{
170 *address |= (~bits & mask);
171}
172
173static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits)
174{
175 *address = (*address & ~mask) | (~bits & mask);
176}
177
178lcd_blockfunc_type* pgfx_blockfuncs[8] = {
179 flipblock, bgblock, fgblock, solidblock,
180 flipinvblock, bginvblock, fginvblock, solidinvblock
181};
182
183/*** Drawing functions ***/
184
185/* Clear the whole display */
186void pgfx_clear_display(void)
187{
188 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0x1F : 0;
189
190 pgfx_rb->memset(gfx_buffer, bits, char_width * pixel_height);
191}
192
193/* Set a single pixel */
194void pgfx_drawpixel(int x, int y)
195{
196 if (((unsigned)x < (unsigned)pixel_width)
197 && ((unsigned)y < (unsigned)pixel_height))
198 pgfx_pixelfuncs[drawmode](x, y);
199}
200
201/* Draw a line */
202void pgfx_drawline(int x1, int y1, int x2, int y2)
117{ 203{
118 int numpixels; 204 int numpixels;
119 int i; 205 int i;
@@ -121,6 +207,7 @@ static void linefunc(int x1, int y1, int x2, int y2,
121 int d, dinc1, dinc2; 207 int d, dinc1, dinc2;
122 int x, xinc1, xinc2; 208 int x, xinc1, xinc2;
123 int y, yinc1, yinc2; 209 int y, yinc1, yinc2;
210 lcd_pixelfunc_type *pfunc = pgfx_pixelfuncs[drawmode];
124 211
125 deltax = abs(x2 - x1); 212 deltax = abs(x2 - x1);
126 deltay = abs(y2 - y1); 213 deltay = abs(y2 - y1);
@@ -147,13 +234,13 @@ static void linefunc(int x1, int y1, int x2, int y2,
147 } 234 }
148 numpixels++; /* include endpoints */ 235 numpixels++; /* include endpoints */
149 236
150 if(x1 > x2) 237 if (x1 > x2)
151 { 238 {
152 xinc1 = -xinc1; 239 xinc1 = -xinc1;
153 xinc2 = -xinc2; 240 xinc2 = -xinc2;
154 } 241 }
155 242
156 if(y1 > y2) 243 if (y1 > y2)
157 { 244 {
158 yinc1 = -yinc1; 245 yinc1 = -yinc1;
159 yinc2 = -yinc2; 246 yinc2 = -yinc2;
@@ -164,7 +251,9 @@ static void linefunc(int x1, int y1, int x2, int y2,
164 251
165 for (i = 0; i < numpixels; i++) 252 for (i = 0; i < numpixels; i++)
166 { 253 {
167 pixelfunc(x, y); 254 if (((unsigned)x < (unsigned)pixel_width)
255 && ((unsigned)y < (unsigned)pixel_height))
256 pfunc(x, y);
168 257
169 if (d < 0) 258 if (d < 0)
170 { 259 {
@@ -181,69 +270,237 @@ static void linefunc(int x1, int y1, int x2, int y2,
181 } 270 }
182} 271}
183 272
184void pgfx_drawline(int x1, int y1, int x2, int y2) 273/* Draw a horizontal line (optimised) */
274void pgfx_hline(int x1, int x2, int y)
185{ 275{
186 linefunc(x1, y1, x2, y2, pgfx_drawpixel); 276 int nx;
187} 277 unsigned char *dst;
278 unsigned mask, mask_right;
279 lcd_blockfunc_type *bfunc;
188 280
189void pgfx_clearline(int x1, int y1, int x2, int y2) 281 /* direction flip */
190{ 282 if (x2 < x1)
191 linefunc(x1, y1, x2, y2, pgfx_clearpixel); 283 {
284 nx = x1;
285 x1 = x2;
286 x2 = nx;
287 }
288
289 /* nothing to draw? */
290 if (((unsigned)y >= (unsigned)pixel_height) || (x1 >= pixel_width)
291 || (x2 < 0))
292 return;
293
294 /* clipping */
295 if (x1 < 0)
296 x1 = 0;
297 if (x2 >= pixel_width)
298 x2 = pixel_width - 1;
299
300 bfunc = pgfx_blockfuncs[drawmode];
301 dst = &gfx_buffer[pixel_height * (x1/5) + y];
302 nx = x2 - (x1 - (x1 % 5));
303 mask = 0x1F >> (x1 % 5);
304 mask_right = 0x1F0 >> (nx % 5);
305
306 for (; nx >= 5; nx -= 5)
307 {
308 bfunc(dst, mask, 0xFFu);
309 dst += pixel_height;
310 mask = 0x1F;
311 }
312 mask &= mask_right;
313 bfunc(dst, mask, 0x1F);
192} 314}
193 315
194void pgfx_invertline(int x1, int y1, int x2, int y2) 316/* Draw a vertical line (optimised) */
317void pgfx_vline(int x, int y1, int y2)
195{ 318{
196 linefunc(x1, y1, x2, y2, pgfx_invertpixel); 319 int y;
320 unsigned char *dst;
321 unsigned mask;
322 lcd_blockfunc_type *bfunc;
323
324 /* direction flip */
325 if (y2 < y1)
326 {
327 y = y1;
328 y1 = y2;
329 y2 = y;
330 }
331
332 /* nothing to draw? */
333 if (((unsigned)x >= (unsigned)pixel_width) || (y1 >= pixel_height)
334 || (y2 < 0))
335 return;
336
337 /* clipping */
338 if (y1 < 0)
339 y1 = 0;
340 if (y2 >= pixel_height)
341 y2 = pixel_height - 1;
342
343 bfunc = pgfx_blockfuncs[drawmode];
344 dst = &gfx_buffer[pixel_height * (x/5) + y1];
345 mask = 0x10 >> (x % 5);
346
347 for (y = y1; y <= y2; y++)
348 bfunc(dst++, mask, 0x1F);
197} 349}
198 350
199void pgfx_invertrect (int x, int y, int nx, int ny) 351/* Draw a rectangular box */
352void pgfx_drawrect(int x, int y, int width, int height)
200{ 353{
201 int i, j; 354 if ((width <= 0) || (height <= 0))
202
203 if (((unsigned) x >= pixel_width) || ((unsigned) y >= pixel_height))
204 return; 355 return;
205 356
206 if ((unsigned)(x + nx) > pixel_width) 357 int x2 = x + width - 1;
207 nx = pixel_width - x; 358 int y2 = y + height - 1;
208 if ((unsigned)(y + ny) > pixel_height)
209 ny = pixel_height - y;
210 359
211 for (i = 0; i < nx; i++) 360 pgfx_vline(x, y, y2);
212 for (j = 0; j < ny; j++) 361 pgfx_vline(x2, y, y2);
213 pgfx_invertpixel(x + i, y + j); 362 pgfx_hline(x, x2, y);
363 pgfx_hline(x, x2, y2);
214} 364}
215 365
216void pgfx_bitmap (const unsigned char *src, int x, int y, int nx, int ny, 366/* Fill a rectangular area */
217 bool clear) 367void pgfx_fillrect(int x, int y, int width, int height)
218{ 368{
219 int stride, i, j; 369 int nx, i;
220 unsigned data; 370 unsigned char *dst;
221 371 unsigned mask, mask_right;
222 if (((unsigned) x >= pixel_width) || ((unsigned) y >= pixel_height)) 372 lcd_blockfunc_type *bfunc;
373
374 /* nothing to draw? */
375 if ((width <= 0) || (height <= 0) || (x >= pixel_width)
376 || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0))
223 return; 377 return;
224 378
225 stride = nx; /* otherwise right-clipping will destroy the image */ 379 /* clipping */
380 if (x < 0)
381 {
382 width += x;
383 x = 0;
384 }
385 if (y < 0)
386 {
387 height += y;
388 y = 0;
389 }
390 if (x + width > pixel_width)
391 width = pixel_width - x;
392 if (y + height > pixel_height)
393 height = pixel_height - y;
394
395 bfunc = pgfx_blockfuncs[drawmode];
396 dst = &gfx_buffer[pixel_height * (x/5) + y];
397 nx = width - 1 + (x % 5);
398 mask = 0x1F >> (x % 5);
399 mask_right = 0x1F0 >> (nx % 5);
400
401 for (; nx >= 5; nx -= 5)
402 {
403 unsigned char *dst_col = dst;
404
405 for (i = height; i > 0; i--)
406 bfunc(dst_col++, mask, 0x1F);
226 407
227 if (((unsigned)(x + nx)) >= pixel_width) 408 dst += pixel_height;
228 nx = pixel_width - x; 409 mask = 0x1F;
229 if (((unsigned)(y + ny)) >= pixel_height) 410 }
230 ny = pixel_height - y; 411 mask &= mask_right;
231 412
232 for (i = 0; i < nx; i++, src++) 413 for (i = height; i > 0; i--)
414 bfunc(dst++, mask, 0x1F);
415}
416
417/* About PlayerGFX internal bitmap format:
418 *
419 * A bitmap contains one bit for every pixel that defines if that pixel is
420 * black (1) or white (0). Bits within a byte are arranged horizontally,
421 * MSB at the left.
422 * The bytes are stored in row-major order, with byte 0 being top left,
423 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
424 *
425 * This approximates the (even more strange) internal hardware format. */
426
427/* Draw a partial bitmap. Note that stride is given in bytes */
428void pgfx_bitmap_part(const unsigned char *src, int src_x, int src_y,
429 int stride, int x, int y, int width, int height)
430{
431 int nx, shift;
432 unsigned char *dst;
433 unsigned mask, mask_right;
434 lcd_blockfunc_type *bfunc;
435
436 /* nothing to draw? */
437 if ((width <= 0) || (height <= 0) || (x >= pixel_width)
438 || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0))
439 return;
440
441 /* clipping */
442 if (x < 0)
443 {
444 width += x;
445 src_x -= x;
446 x = 0;
447 }
448 if (y < 0)
449 {
450 height += y;
451 src_y -= y;
452 y = 0;
453 }
454 if (x + width > pixel_width)
455 width = pixel_width - x;
456 if (y + height > pixel_height)
457 height = pixel_height - y;
458
459 src += stride * src_y + (src_x >> 3); /* move starting point */
460 dst = &gfx_buffer[pixel_height * (x/5) + y];
461 shift = 3 + (x % 5) - (src_x & 7);
462 nx = width - 1 + (x % 5);
463
464 bfunc = pgfx_blockfuncs[drawmode];
465 mask = 0x1F >> (x % 5);
466 mask_right = 0x1F0 >> (nx % 5);
467
468 for (y = 0; y < height; y++)
233 { 469 {
234 data = src[0]; 470 const unsigned char *src_row = src;
235 if (ny > 8) /* ny is max. 14 */ 471 unsigned char *dst_row = dst;
236 data |= src[stride] << 8; 472 unsigned mask_row = mask;
237 for (j = 0; j < ny; j++) 473 unsigned data = *src_row++;
474 int extrabits = shift;
475
476 for (x = nx; x >= 5; x -= 5)
238 { 477 {
239 if (data & 1) 478 if (extrabits < 0)
240 pgfx_drawpixel(x + i, y + j); 479 {
241 else 480 data = (data << 8) | *src_row++;
242 if (clear) 481 extrabits += 8;
243 pgfx_clearpixel(x + i, y + j); 482 }
244 data >>= 1; 483 bfunc(dst_row, mask_row, data >> extrabits);
484 extrabits -= 5;
485 dst_row += pixel_height;
486 mask_row = 0x1F;
245 } 487 }
488 if (extrabits < 0)
489 {
490 data = (data << 8) | *src_row;
491 extrabits += 8;
492 }
493 bfunc(dst_row, mask_row & mask_right, data >> extrabits);
494
495 src += stride;
496 dst++;
246 } 497 }
247} 498}
248 499
500/* Draw a full bitmap */
501void pgfx_bitmap(const unsigned char *src, int x, int y, int width, int height)
502{
503 pgfx_bitmap_part(src, 0, 0, (width + 7) >> 3, x, y, width, height);
504}
505
249#endif /* HAVE_LCD_CHARCELLS */ 506#endif /* HAVE_LCD_CHARCELLS */