summaryrefslogtreecommitdiff
path: root/apps/plugins/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib')
-rw-r--r--apps/plugins/lib/gray.c212
-rw-r--r--apps/plugins/lib/gray.h4
2 files changed, 149 insertions, 67 deletions
diff --git a/apps/plugins/lib/gray.c b/apps/plugins/lib/gray.c
index f026ff7cd4..a18f3f7644 100644
--- a/apps/plugins/lib/gray.c
+++ b/apps/plugins/lib/gray.c
@@ -38,7 +38,8 @@
38#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */ 38#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
39 39
40/* unsigned 16 bit multiplication (a single instruction on the SH) */ 40/* unsigned 16 bit multiplication (a single instruction on the SH) */
41#define MULU16(a, b) (((unsigned short) (a)) * ((unsigned short) (b))) 41#define MULU16(a, b) ((unsigned long) \
42 (((unsigned short) (a)) * ((unsigned short) (b))))
42 43
43typedef struct 44typedef struct
44{ 45{
@@ -52,8 +53,9 @@ typedef struct
52 int cur_plane; /* for the timer isr */ 53 int cur_plane; /* for the timer isr */
53 unsigned long randmask; /* mask for random value in graypixel() */ 54 unsigned long randmask; /* mask for random value in graypixel() */
54 unsigned long flags; /* various flags, see #defines */ 55 unsigned long flags; /* various flags, see #defines */
55 unsigned char *data; /* pointer to start of bitplane data */
56 unsigned long *bitpattern; /* pointer to start of pattern table */ 56 unsigned long *bitpattern; /* pointer to start of pattern table */
57 unsigned char *data; /* pointer to start of bitplane data */
58 int curfont; /* current selected font */
57} tGraybuf; 59} tGraybuf;
58 60
59static struct plugin_api *rb = NULL; /* global api struct pointer */ 61static struct plugin_api *rb = NULL; /* global api struct pointer */
@@ -103,26 +105,24 @@ static void graypixel(int x, int y, unsigned long pattern)
103 * pattern randomly, otherwise you would get flicker and/or moire. 105 * pattern randomly, otherwise you would get flicker and/or moire.
104 * Since rand() is relatively slow, I've implemented a simple, but very 106 * Since rand() is relatively slow, I've implemented a simple, but very
105 * fast pseudo-random generator based on linear congruency in assembler. 107 * fast pseudo-random generator based on linear congruency in assembler.
106 * It delivers 16 pseudo-random bits in each iteration. */ 108 * It delivers max. 16 pseudo-random bits in each iteration. */
107 109
108 /* simple but fast pseudo-random generator */ 110 /* simple but fast pseudo-random generator */
109 asm( 111 asm(
110 "mov.w @%1,%0 \n" /* load last value */
111 "mov #75,r1 \n" 112 "mov #75,r1 \n"
112 "mulu %0,r1 \n" /* multiply by 75 */ 113 "mulu %1,r1 \n" /* multiply by 75 */
113 "sts macl,%0 \n" /* get result */ 114 "sts macl,%1 \n" /* get result */
114 "add #74,%0 \n" /* add another 74 */ 115 "add #74,%1 \n" /* add another 74 */
115 "mov.w %0,@%1 \n" /* store new value */
116 /* Since the lower bits are not very random: */ 116 /* Since the lower bits are not very random: */
117 "shlr8 %0 \n" /* get bits 8..15 (need max. 5) */ 117 "swap.b %1,%0 \n" /* get bits 8..15 (need max. 5) */
118 "and %2,%0 \n" /* mask out unneeded bits */ 118 "and %2,%0 \n" /* mask out unneeded bits */
119 : /* outputs */ 119 : /* outputs */
120 /* %0 */ "=&r"(random) 120 /* %0 */ "=&r"(random),
121 /* %1, in & out */ "+r"(gray_random_buffer)
121 : /* inputs */ 122 : /* inputs */
122 /* %1 */ "r"(&gray_random_buffer),
123 /* %2 */ "r"(graybuf->randmask) 123 /* %2 */ "r"(graybuf->randmask)
124 : /* clobbers */ 124 : /* clobbers */
125 "r1","macl" 125 "r1", "macl"
126 ); 126 );
127 127
128 /* precalculate mask and byte address in first bitplane */ 128 /* precalculate mask and byte address in first bitplane */
@@ -233,12 +233,16 @@ static void graypixel(int x, int y, unsigned long pattern)
233 * for larger rectangles and graymaps */ 233 * for larger rectangles and graymaps */
234static void grayblock(int x, int by, unsigned char* src, int stride) 234static void grayblock(int x, int by, unsigned char* src, int stride)
235{ 235{
236 register unsigned char *address, *end_addr;
237 unsigned long pat_stack[8];
238 register unsigned long *pat_ptr = &pat_stack[8]; /* behind last element */
239
236 /* precalculate the bit patterns with random shifts (same RNG as graypixel, 240 /* precalculate the bit patterns with random shifts (same RNG as graypixel,
237 * see there for an explanation) for all 8 pixels and put them on the 241 * see there for an explanation) for all 8 pixels and put them on an
238 * stack (!) */ 242 * extra stack */
239 asm( 243 asm(
240 "mova .gb_reload,r0 \n" /* set default loopback address */ 244 "mova .gb_reload,r0 \n" /* set default loopback address */
241 "tst %1,%1 \n" /* stride == 0 ? */ 245 "tst %3,%3 \n" /* stride == 0 ? */
242 "bf .gb_needreload \n" /* no: keep that address */ 246 "bf .gb_needreload \n" /* no: keep that address */
243 "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */ 247 "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
244 ".gb_needreload: \n" 248 ".gb_needreload: \n"
@@ -247,46 +251,45 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
247 251
248 ".align 2 \n" /** load pattern for pixel **/ 252 ".align 2 \n" /** load pattern for pixel **/
249 ".gb_reload: \n" 253 ".gb_reload: \n"
250 "mov.b @%0,r0 \n" /* load src byte */ 254 "mov.b @%2,r0 \n" /* load src byte */
255 "nop \n" /* align here, saves a pipeline stall */
251 "extu.b r0,r0 \n" /* extend unsigned */ 256 "extu.b r0,r0 \n" /* extend unsigned */
252 "mulu %2,r0 \n" /* macl = byte * depth; */ 257 "mulu %4,r0 \n" /* macl = byte * depth; */
253 "add %1,%0 \n" /* src += stride; */ 258 "add %3,%2 \n" /* src += stride; */
254 "sts macl,r4 \n" /* r4 = macl; */ 259 "sts macl,r4 \n" /* r4 = macl; */
255 "add r4,r0 \n" /* byte += r4; */ 260 "add r4,r0 \n" /* byte += r4; */
256 "shlr8 r0 \n" /* byte >>= 8; */ 261 "shlr8 r0 \n" /* byte >>= 8; */
257 "shll2 r0 \n" 262 "shll2 r0 \n"
258 "mov.l @(r0,%3),r4 \n" /* r4 = bitpattern[byte]; */ 263 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
259 264
260 ".align 2 \n" /** RNG **/ 265 ".align 2 \n" /** RNG **/
261 ".gb_reuse: \n" 266 ".gb_reuse: \n"
262 "mov.w @%4,r1 \n" /* load last value */
263 "mov #75,r0 \n" 267 "mov #75,r0 \n"
264 "mulu r0,r1 \n" /* multiply by 75 */ 268 "mulu r0,%1 \n" /* multiply by 75 */
265 "sts macl,r1 \n" 269 "sts macl,%1 \n"
266 "add #74,r1 \n" /* add another 74 */ 270 "add #74,%1 \n" /* add another 74 */
267 "mov.w r1,@%4 \n" /* store new value */
268 /* Since the lower bits are not very random: */ 271 /* Since the lower bits are not very random: */
269 "shlr8 r1 \n" /* get bits 8..15 (need max. 5) */ 272 "swap.b %1,r1 \n" /* get bits 8..15 (need max. 5) */
270 "and %5,r1 \n" /* mask out unneeded bits */ 273 "and %6,r1 \n" /* mask out unneeded bits */
271 274
272 "cmp/hs %2,r1 \n" /* random >= depth ? */ 275 "cmp/hs %4,r1 \n" /* random >= depth ? */
273 "bf .gb_ntrim \n" 276 "bf .gb_ntrim \n"
274 "sub %2,r1 \n" /* yes: random -= depth; */ 277 "sub %4,r1 \n" /* yes: random -= depth; */
275 ".gb_ntrim: \n" 278 ".gb_ntrim: \n"
276 279
277 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/ 280 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
278 "jsr @r0 \n" /* shift r4 left by r1 */ 281 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
279 "mov r1,r5 \n" 282 "mov r1,r5 \n"
280 283
281 "mov %2,r5 \n" 284 "mov %4,r5 \n"
282 "sub r1,r5 \n" /* r5 = depth - r1 */ 285 "sub r1,r5 \n" /* r5 = depth - r1 */
283 "mov.l .lshrsi3,r1 \n" 286 "mov.l .lshrsi3,r1 \n"
284 "jsr @r1 \n" /* shift r4 right by r5 */ 287 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
285 "mov r0,r1 \n" /* last result stored in r1 */ 288 "mov r0,r1 \n" /* store previous result in r1 */
286 289
287 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */ 290 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
288 "mov.l r0,@-r15 \n" /* push pattern */ 291 "mov.l r0,@-%0 \n" /* push on pattern stack */
289 292
290 "cmp/pl r3 \n" /* loop count > 0? */ 293 "cmp/pl r3 \n" /* loop count > 0? */
291 "bf .gb_patdone \n" /* no: done */ 294 "bf .gb_patdone \n" /* no: done */
292 295
@@ -302,34 +305,33 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
302 305
303 ".gb_patdone: \n" 306 ".gb_patdone: \n"
304 : /* outputs */ 307 : /* outputs */
308 /* %0, in & out */ "+r"(pat_ptr),
309 /* %1, in & out */ "+r"(gray_random_buffer)
305 : /* inputs */ 310 : /* inputs */
306 /* %0 */ "r"(src), 311 /* %2 */ "r"(src),
307 /* %1 */ "r"(stride), 312 /* %3 */ "r"(stride),
308 /* %2 */ "r"(graybuf->depth), 313 /* %4 */ "r"(graybuf->depth),
309 /* %3 */ "r"(graybuf->bitpattern), 314 /* %5 */ "r"(graybuf->bitpattern),
310 /* %4 */ "r"(&gray_random_buffer), 315 /* %6 */ "r"(graybuf->randmask)
311 /* %5 */ "r"(graybuf->randmask)
312 : /* clobbers */ 316 : /* clobbers */
313 "r0", "r1", "r2", "r3", "r4", "r5", "macl" 317 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
314 ); 318 );
315 319
316 /* calculate start address in first bitplane and end address */ 320 /* calculate start address in first bitplane and end address */
317 register unsigned char *address = graybuf->data + x 321 address = graybuf->data + x + MULU16(graybuf->width, by);
318 + MULU16(graybuf->width, by); 322 end_addr = address + MULU16(graybuf->depth, graybuf->plane_size);
319 register unsigned char *end_addr = address
320 + MULU16(graybuf->depth, graybuf->plane_size);
321 323
322 /* set the bits for all 8 pixels in all bytes according to the 324 /* set the bits for all 8 pixels in all bytes according to the
323 * precalculated patterns on the stack */ 325 * precalculated patterns on the pattern stack */
324 asm ( 326 asm (
325 "mov.l @r15+,r1 \n" /* pop all 8 patterns */ 327 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
326 "mov.l @r15+,r2 \n" 328 "mov.l @%3+,r2 \n"
327 "mov.l @r15+,r3 \n" 329 "mov.l @%3+,r3 \n"
328 "mov.l @r15+,r4 \n" 330 "mov.l @%3+,r4 \n"
329 "mov.l @r15+,r5 \n" 331 "mov.l @%3+,r5 \n"
330 "mov.l @r15+,r6 \n" 332 "mov.l @%3+,r6 \n"
331 "mov.l @r15+,r7 \n" 333 "mov.l @%3+,r7 \n"
332 "mov.l @r15+,r8 \n" 334 "mov.l @%3+,%3 \n"
333 335
334 ".gb_loop: \n" /* loop for all bitplanes */ 336 ".gb_loop: \n" /* loop for all bitplanes */
335 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */ 337 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
@@ -346,7 +348,7 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
346 "rotcl r0 \n" 348 "rotcl r0 \n"
347 "shlr r7 \n" 349 "shlr r7 \n"
348 "rotcl r0 \n" 350 "rotcl r0 \n"
349 "shlr r8 \n" 351 "shlr %3 \n"
350 "rotcl r0 \n" 352 "rotcl r0 \n"
351 "mov.b r0,@%0 \n" /* store byte to bitplane */ 353 "mov.b r0,@%0 \n" /* store byte to bitplane */
352 "add %2,%0 \n" /* advance to next bitplane */ 354 "add %2,%0 \n" /* advance to next bitplane */
@@ -356,9 +358,10 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
356 : /* inputs */ 358 : /* inputs */
357 /* %0 */ "r"(address), 359 /* %0 */ "r"(address),
358 /* %1 */ "r"(end_addr), 360 /* %1 */ "r"(end_addr),
359 /* %2 */ "r"(graybuf->plane_size) 361 /* %2 */ "r"(graybuf->plane_size),
362 /* %3 */ "r"(pat_ptr)
360 : /* clobbers */ 363 : /* clobbers */
361 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8" 364 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"
362 ); 365 );
363} 366}
364 367
@@ -445,7 +448,7 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
445 gbuf += align; 448 gbuf += align;
446 gbuf_size -= align; 449 gbuf_size -= align;
447 450
448 plane_size = width * bheight; 451 plane_size = MULU16(width, bheight);
449 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(long)) 452 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(long))
450 / (plane_size + sizeof(long)); 453 / (plane_size + sizeof(long));
451 454
@@ -466,9 +469,9 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
466 graybuf->depth = depth; 469 graybuf->depth = depth;
467 graybuf->cur_plane = 0; 470 graybuf->cur_plane = 0;
468 graybuf->flags = 0; 471 graybuf->flags = 0;
469 graybuf->data = gbuf + sizeof(tGraybuf); 472 graybuf->bitpattern = (unsigned long *) gbuf + sizeof(tGraybuf);
470 graybuf->bitpattern = (unsigned long *) (graybuf->data 473 graybuf->data = (unsigned char *) (graybuf->bitpattern + depth + 1);
471 + depth * plane_size); 474 graybuf->curfont = FONT_SYSFIXED;
472 475
473 i = depth; 476 i = depth;
474 j = 8; 477 j = 8;
@@ -477,10 +480,10 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
477 i >>= 1; 480 i >>= 1;
478 j--; 481 j--;
479 } 482 }
480 graybuf->randmask = 0xFF >> j; 483 graybuf->randmask = 0xFFu >> j;
481 484
482 /* initial state is all white */ 485 /* initial state is all white */
483 rb->memset(graybuf->data, 0, depth * plane_size); 486 rb->memset(graybuf->data, 0, MULU16(depth, plane_size));
484 487
485 /* Precalculate the bit patterns for all possible pixel values */ 488 /* Precalculate the bit patterns for all possible pixel values */
486 for (i = 0; i <= depth; i++) 489 for (i = 0; i <= depth; i++)
@@ -506,7 +509,7 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
506 if (buf_taken) /* caller requested info about space taken */ 509 if (buf_taken) /* caller requested info about space taken */
507 { 510 {
508 *buf_taken = sizeof(tGraybuf) + sizeof(long) 511 *buf_taken = sizeof(tGraybuf) + sizeof(long)
509 + (plane_size + sizeof(long)) * depth + align; 512 + MULU16(plane_size + sizeof(long), depth) + align;
510 } 513 }
511 514
512 return depth; 515 return depth;
@@ -1391,15 +1394,15 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
1391 1394
1392 if (yb1 == yb2) 1395 if (yb1 == yb2)
1393 { 1396 {
1394 mask = 0xFF << (y1 & 7); 1397 mask = 0xFFu << (y1 & 7);
1395 mask &= 0xFF >> (7 - (y2 & 7)); 1398 mask &= 0xFFu >> (7 - (y2 & 7));
1396 1399
1397 for (x = x1; x <= x2; x++) 1400 for (x = x1; x <= x2; x++)
1398 grayinvertmasked(x, yb1, mask); 1401 grayinvertmasked(x, yb1, mask);
1399 } 1402 }
1400 else 1403 else
1401 { 1404 {
1402 mask = 0xFF << (y1 & 7); 1405 mask = 0xFFu << (y1 & 7);
1403 1406
1404 for (x = x1; x <= x2; x++) 1407 for (x = x1; x <= x2; x++)
1405 grayinvertmasked(x, yb1, mask); 1408 grayinvertmasked(x, yb1, mask);
@@ -1410,7 +1413,7 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
1410 grayinvertmasked(x, yb, 0xFF); 1413 grayinvertmasked(x, yb, 0xFF);
1411 } 1414 }
1412 1415
1413 mask = 0xFF >> (7 - (y2 & 7)); 1416 mask = 0xFFu >> (7 - (y2 & 7));
1414 1417
1415 for (x = x1; x <= x2; x++) 1418 for (x = x1; x <= x2; x++)
1416 grayinvertmasked(x, yb2, mask); 1419 grayinvertmasked(x, yb2, mask);
@@ -1539,6 +1542,81 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1539 } 1542 }
1540} 1543}
1541 1544
1545/* Set font for the font routines
1546 *
1547 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
1548 * core routines
1549 */
1550void gray_setfont(int newfont)
1551{
1552 graybuf->curfont = newfont;
1553}
1554
1555/* Calculate width and height of the given text in pixels when rendered with
1556 * the currently selected font.
1557 *
1558 * This works exactly the same way as the core lcd_getstringsize(), only that
1559 * it uses the selected font for grayscale.
1560 */
1561int gray_getstringsize(unsigned char *str, int *w, int *h)
1562{
1563 int ch;
1564 int width = 0;
1565 struct font* pf = rb->font_get(graybuf->curfont);
1566
1567 while ((ch = *str++))
1568 {
1569 /* check input range */
1570 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
1571 ch = pf->defaultchar;
1572 ch -= pf->firstchar;
1573
1574 /* get proportional width */
1575 width += pf->width ? pf->width[ch] : pf->maxwidth;
1576 }
1577 if (w)
1578 *w = width;
1579 if (h)
1580 *h = pf->height;
1581 return width;
1582}
1583
1584/* Display text with specified foreground and background shades
1585 *
1586 * If draw_bg is false, only foreground pixels are drawn, so the background
1587 * is transparent. In this case bg_brightness is ignored.
1588 */
1589void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg,
1590 int fg_brightness, int bg_brightness)
1591{
1592 int ch, width;
1593 bitmap_t *bits;
1594 struct font *pf = rb->font_get(graybuf->curfont);
1595
1596 if (graybuf == NULL
1597 || (unsigned) x >= (unsigned) graybuf->width
1598 || (unsigned) y >= (unsigned) graybuf->height
1599 || (unsigned) fg_brightness > 255
1600 || (unsigned) bg_brightness > 255)
1601 return;
1602
1603 while ((ch = *str++) != '\0' && x < graybuf->width)
1604 {
1605 /* check input range */
1606 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
1607 ch = pf->defaultchar;
1608 ch -= pf->firstchar;
1609
1610 /* get proportional width and glyph bits */
1611 width = pf->width ? pf->width[ch] : pf->maxwidth;
1612 bits = pf->bits + (pf->offset ? pf->offset[ch] : (pf->height * ch));
1613
1614 gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height,
1615 width, draw_bg, fg_brightness, bg_brightness);
1616 x += width;
1617 }
1618}
1619
1542#endif // #ifdef HAVE_LCD_BITMAP 1620#endif // #ifdef HAVE_LCD_BITMAP
1543#endif // #ifndef SIMULATOR 1621#endif // #ifndef SIMULATOR
1544 1622
diff --git a/apps/plugins/lib/gray.h b/apps/plugins/lib/gray.h
index 62c3dd753f..26cfc35e0d 100644
--- a/apps/plugins/lib/gray.h
+++ b/apps/plugins/lib/gray.h
@@ -75,6 +75,10 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
75 int stride, bool draw_bg, int fg_brightness, 75 int stride, bool draw_bg, int fg_brightness,
76 int bg_brightness); 76 int bg_brightness);
77 77
78/* font support */
79void gray_setfont(int newfont);
80int gray_getstringsize(unsigned char *str, int *w, int *h);
81
78#endif /* HAVE_LCD_BITMAP */ 82#endif /* HAVE_LCD_BITMAP */
79#endif /* SIMULATOR */ 83#endif /* SIMULATOR */
80#endif /* __GRAY_H__ */ 84#endif /* __GRAY_H__ */