Font support, several speed and size tweaks
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4654 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
2cf4f47005
commit
512079f944
2 changed files with 149 additions and 67 deletions
|
@ -38,7 +38,8 @@
|
|||
#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
|
||||
|
||||
/* unsigned 16 bit multiplication (a single instruction on the SH) */
|
||||
#define MULU16(a, b) (((unsigned short) (a)) * ((unsigned short) (b)))
|
||||
#define MULU16(a, b) ((unsigned long) \
|
||||
(((unsigned short) (a)) * ((unsigned short) (b))))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -52,8 +53,9 @@ typedef struct
|
|||
int cur_plane; /* for the timer isr */
|
||||
unsigned long randmask; /* mask for random value in graypixel() */
|
||||
unsigned long flags; /* various flags, see #defines */
|
||||
unsigned char *data; /* pointer to start of bitplane data */
|
||||
unsigned long *bitpattern; /* pointer to start of pattern table */
|
||||
unsigned char *data; /* pointer to start of bitplane data */
|
||||
int curfont; /* current selected font */
|
||||
} tGraybuf;
|
||||
|
||||
static struct plugin_api *rb = NULL; /* global api struct pointer */
|
||||
|
@ -103,26 +105,24 @@ static void graypixel(int x, int y, unsigned long pattern)
|
|||
* pattern randomly, otherwise you would get flicker and/or moire.
|
||||
* Since rand() is relatively slow, I've implemented a simple, but very
|
||||
* fast pseudo-random generator based on linear congruency in assembler.
|
||||
* It delivers 16 pseudo-random bits in each iteration. */
|
||||
* It delivers max. 16 pseudo-random bits in each iteration. */
|
||||
|
||||
/* simple but fast pseudo-random generator */
|
||||
asm(
|
||||
"mov.w @%1,%0 \n" /* load last value */
|
||||
"mov #75,r1 \n"
|
||||
"mulu %0,r1 \n" /* multiply by 75 */
|
||||
"sts macl,%0 \n" /* get result */
|
||||
"add #74,%0 \n" /* add another 74 */
|
||||
"mov.w %0,@%1 \n" /* store new value */
|
||||
"mulu %1,r1 \n" /* multiply by 75 */
|
||||
"sts macl,%1 \n" /* get result */
|
||||
"add #74,%1 \n" /* add another 74 */
|
||||
/* Since the lower bits are not very random: */
|
||||
"shlr8 %0 \n" /* get bits 8..15 (need max. 5) */
|
||||
"swap.b %1,%0 \n" /* get bits 8..15 (need max. 5) */
|
||||
"and %2,%0 \n" /* mask out unneeded bits */
|
||||
: /* outputs */
|
||||
/* %0 */ "=&r"(random)
|
||||
/* %0 */ "=&r"(random),
|
||||
/* %1, in & out */ "+r"(gray_random_buffer)
|
||||
: /* inputs */
|
||||
/* %1 */ "r"(&gray_random_buffer),
|
||||
/* %2 */ "r"(graybuf->randmask)
|
||||
: /* clobbers */
|
||||
"r1","macl"
|
||||
"r1", "macl"
|
||||
);
|
||||
|
||||
/* precalculate mask and byte address in first bitplane */
|
||||
|
@ -233,12 +233,16 @@ static void graypixel(int x, int y, unsigned long pattern)
|
|||
* for larger rectangles and graymaps */
|
||||
static void grayblock(int x, int by, unsigned char* src, int stride)
|
||||
{
|
||||
register unsigned char *address, *end_addr;
|
||||
unsigned long pat_stack[8];
|
||||
register unsigned long *pat_ptr = &pat_stack[8]; /* behind last element */
|
||||
|
||||
/* precalculate the bit patterns with random shifts (same RNG as graypixel,
|
||||
* see there for an explanation) for all 8 pixels and put them on the
|
||||
* stack (!) */
|
||||
* see there for an explanation) for all 8 pixels and put them on an
|
||||
* extra stack */
|
||||
asm(
|
||||
"mova .gb_reload,r0 \n" /* set default loopback address */
|
||||
"tst %1,%1 \n" /* stride == 0 ? */
|
||||
"tst %3,%3 \n" /* stride == 0 ? */
|
||||
"bf .gb_needreload \n" /* no: keep that address */
|
||||
"mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
|
||||
".gb_needreload: \n"
|
||||
|
@ -247,46 +251,45 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
|
|||
|
||||
".align 2 \n" /** load pattern for pixel **/
|
||||
".gb_reload: \n"
|
||||
"mov.b @%0,r0 \n" /* load src byte */
|
||||
"mov.b @%2,r0 \n" /* load src byte */
|
||||
"nop \n" /* align here, saves a pipeline stall */
|
||||
"extu.b r0,r0 \n" /* extend unsigned */
|
||||
"mulu %2,r0 \n" /* macl = byte * depth; */
|
||||
"add %1,%0 \n" /* src += stride; */
|
||||
"mulu %4,r0 \n" /* macl = byte * depth; */
|
||||
"add %3,%2 \n" /* src += stride; */
|
||||
"sts macl,r4 \n" /* r4 = macl; */
|
||||
"add r4,r0 \n" /* byte += r4; */
|
||||
"shlr8 r0 \n" /* byte >>= 8; */
|
||||
"shll2 r0 \n"
|
||||
"mov.l @(r0,%3),r4 \n" /* r4 = bitpattern[byte]; */
|
||||
"mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
|
||||
|
||||
".align 2 \n" /** RNG **/
|
||||
".gb_reuse: \n"
|
||||
"mov.w @%4,r1 \n" /* load last value */
|
||||
"mov #75,r0 \n"
|
||||
"mulu r0,r1 \n" /* multiply by 75 */
|
||||
"sts macl,r1 \n"
|
||||
"add #74,r1 \n" /* add another 74 */
|
||||
"mov.w r1,@%4 \n" /* store new value */
|
||||
"mulu r0,%1 \n" /* multiply by 75 */
|
||||
"sts macl,%1 \n"
|
||||
"add #74,%1 \n" /* add another 74 */
|
||||
/* Since the lower bits are not very random: */
|
||||
"shlr8 r1 \n" /* get bits 8..15 (need max. 5) */
|
||||
"and %5,r1 \n" /* mask out unneeded bits */
|
||||
"swap.b %1,r1 \n" /* get bits 8..15 (need max. 5) */
|
||||
"and %6,r1 \n" /* mask out unneeded bits */
|
||||
|
||||
"cmp/hs %2,r1 \n" /* random >= depth ? */
|
||||
"cmp/hs %4,r1 \n" /* random >= depth ? */
|
||||
"bf .gb_ntrim \n"
|
||||
"sub %2,r1 \n" /* yes: random -= depth; */
|
||||
"sub %4,r1 \n" /* yes: random -= depth; */
|
||||
".gb_ntrim: \n"
|
||||
|
||||
"mov.l .ashlsi3,r0 \n" /** rotate pattern **/
|
||||
"jsr @r0 \n" /* shift r4 left by r1 */
|
||||
"jsr @r0 \n" /* r4 -> r0, shift left by r5 */
|
||||
"mov r1,r5 \n"
|
||||
|
||||
"mov %2,r5 \n"
|
||||
"mov %4,r5 \n"
|
||||
"sub r1,r5 \n" /* r5 = depth - r1 */
|
||||
"mov.l .lshrsi3,r1 \n"
|
||||
"jsr @r1 \n" /* shift r4 right by r5 */
|
||||
"mov r0,r1 \n" /* last result stored in r1 */
|
||||
"jsr @r1 \n" /* r4 -> r0, shift right by r5 */
|
||||
"mov r0,r1 \n" /* store previous result in r1 */
|
||||
|
||||
"or r1,r0 \n" /* rotated_pattern = r0 | r1 */
|
||||
"mov.l r0,@-r15 \n" /* push pattern */
|
||||
|
||||
"mov.l r0,@-%0 \n" /* push on pattern stack */
|
||||
|
||||
"cmp/pl r3 \n" /* loop count > 0? */
|
||||
"bf .gb_patdone \n" /* no: done */
|
||||
|
||||
|
@ -302,34 +305,33 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
|
|||
|
||||
".gb_patdone: \n"
|
||||
: /* outputs */
|
||||
/* %0, in & out */ "+r"(pat_ptr),
|
||||
/* %1, in & out */ "+r"(gray_random_buffer)
|
||||
: /* inputs */
|
||||
/* %0 */ "r"(src),
|
||||
/* %1 */ "r"(stride),
|
||||
/* %2 */ "r"(graybuf->depth),
|
||||
/* %3 */ "r"(graybuf->bitpattern),
|
||||
/* %4 */ "r"(&gray_random_buffer),
|
||||
/* %5 */ "r"(graybuf->randmask)
|
||||
/* %2 */ "r"(src),
|
||||
/* %3 */ "r"(stride),
|
||||
/* %4 */ "r"(graybuf->depth),
|
||||
/* %5 */ "r"(graybuf->bitpattern),
|
||||
/* %6 */ "r"(graybuf->randmask)
|
||||
: /* clobbers */
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "macl"
|
||||
);
|
||||
|
||||
/* calculate start address in first bitplane and end address */
|
||||
register unsigned char *address = graybuf->data + x
|
||||
+ MULU16(graybuf->width, by);
|
||||
register unsigned char *end_addr = address
|
||||
+ MULU16(graybuf->depth, graybuf->plane_size);
|
||||
address = graybuf->data + x + MULU16(graybuf->width, by);
|
||||
end_addr = address + MULU16(graybuf->depth, graybuf->plane_size);
|
||||
|
||||
/* set the bits for all 8 pixels in all bytes according to the
|
||||
* precalculated patterns on the stack */
|
||||
* precalculated patterns on the pattern stack */
|
||||
asm (
|
||||
"mov.l @r15+,r1 \n" /* pop all 8 patterns */
|
||||
"mov.l @r15+,r2 \n"
|
||||
"mov.l @r15+,r3 \n"
|
||||
"mov.l @r15+,r4 \n"
|
||||
"mov.l @r15+,r5 \n"
|
||||
"mov.l @r15+,r6 \n"
|
||||
"mov.l @r15+,r7 \n"
|
||||
"mov.l @r15+,r8 \n"
|
||||
"mov.l @%3+,r1 \n" /* pop all 8 patterns */
|
||||
"mov.l @%3+,r2 \n"
|
||||
"mov.l @%3+,r3 \n"
|
||||
"mov.l @%3+,r4 \n"
|
||||
"mov.l @%3+,r5 \n"
|
||||
"mov.l @%3+,r6 \n"
|
||||
"mov.l @%3+,r7 \n"
|
||||
"mov.l @%3+,%3 \n"
|
||||
|
||||
".gb_loop: \n" /* loop for all bitplanes */
|
||||
"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)
|
|||
"rotcl r0 \n"
|
||||
"shlr r7 \n"
|
||||
"rotcl r0 \n"
|
||||
"shlr r8 \n"
|
||||
"shlr %3 \n"
|
||||
"rotcl r0 \n"
|
||||
"mov.b r0,@%0 \n" /* store byte to bitplane */
|
||||
"add %2,%0 \n" /* advance to next bitplane */
|
||||
|
@ -356,9 +358,10 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
|
|||
: /* inputs */
|
||||
/* %0 */ "r"(address),
|
||||
/* %1 */ "r"(end_addr),
|
||||
/* %2 */ "r"(graybuf->plane_size)
|
||||
/* %2 */ "r"(graybuf->plane_size),
|
||||
/* %3 */ "r"(pat_ptr)
|
||||
: /* clobbers */
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -445,7 +448,7 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
|
|||
gbuf += align;
|
||||
gbuf_size -= align;
|
||||
|
||||
plane_size = width * bheight;
|
||||
plane_size = MULU16(width, bheight);
|
||||
possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(long))
|
||||
/ (plane_size + sizeof(long));
|
||||
|
||||
|
@ -466,9 +469,9 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
|
|||
graybuf->depth = depth;
|
||||
graybuf->cur_plane = 0;
|
||||
graybuf->flags = 0;
|
||||
graybuf->data = gbuf + sizeof(tGraybuf);
|
||||
graybuf->bitpattern = (unsigned long *) (graybuf->data
|
||||
+ depth * plane_size);
|
||||
graybuf->bitpattern = (unsigned long *) gbuf + sizeof(tGraybuf);
|
||||
graybuf->data = (unsigned char *) (graybuf->bitpattern + depth + 1);
|
||||
graybuf->curfont = FONT_SYSFIXED;
|
||||
|
||||
i = depth;
|
||||
j = 8;
|
||||
|
@ -477,10 +480,10 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
|
|||
i >>= 1;
|
||||
j--;
|
||||
}
|
||||
graybuf->randmask = 0xFF >> j;
|
||||
graybuf->randmask = 0xFFu >> j;
|
||||
|
||||
/* initial state is all white */
|
||||
rb->memset(graybuf->data, 0, depth * plane_size);
|
||||
rb->memset(graybuf->data, 0, MULU16(depth, plane_size));
|
||||
|
||||
/* Precalculate the bit patterns for all possible pixel values */
|
||||
for (i = 0; i <= depth; i++)
|
||||
|
@ -506,7 +509,7 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
|
|||
if (buf_taken) /* caller requested info about space taken */
|
||||
{
|
||||
*buf_taken = sizeof(tGraybuf) + sizeof(long)
|
||||
+ (plane_size + sizeof(long)) * depth + align;
|
||||
+ MULU16(plane_size + sizeof(long), depth) + align;
|
||||
}
|
||||
|
||||
return depth;
|
||||
|
@ -1391,15 +1394,15 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
|
|||
|
||||
if (yb1 == yb2)
|
||||
{
|
||||
mask = 0xFF << (y1 & 7);
|
||||
mask &= 0xFF >> (7 - (y2 & 7));
|
||||
mask = 0xFFu << (y1 & 7);
|
||||
mask &= 0xFFu >> (7 - (y2 & 7));
|
||||
|
||||
for (x = x1; x <= x2; x++)
|
||||
grayinvertmasked(x, yb1, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = 0xFF << (y1 & 7);
|
||||
mask = 0xFFu << (y1 & 7);
|
||||
|
||||
for (x = x1; x <= x2; x++)
|
||||
grayinvertmasked(x, yb1, mask);
|
||||
|
@ -1410,7 +1413,7 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
|
|||
grayinvertmasked(x, yb, 0xFF);
|
||||
}
|
||||
|
||||
mask = 0xFF >> (7 - (y2 & 7));
|
||||
mask = 0xFFu >> (7 - (y2 & 7));
|
||||
|
||||
for (x = x1; x <= x2; x++)
|
||||
grayinvertmasked(x, yb2, mask);
|
||||
|
@ -1539,6 +1542,81 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
|
|||
}
|
||||
}
|
||||
|
||||
/* Set font for the font routines
|
||||
*
|
||||
* newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
|
||||
* core routines
|
||||
*/
|
||||
void gray_setfont(int newfont)
|
||||
{
|
||||
graybuf->curfont = newfont;
|
||||
}
|
||||
|
||||
/* Calculate width and height of the given text in pixels when rendered with
|
||||
* the currently selected font.
|
||||
*
|
||||
* This works exactly the same way as the core lcd_getstringsize(), only that
|
||||
* it uses the selected font for grayscale.
|
||||
*/
|
||||
int gray_getstringsize(unsigned char *str, int *w, int *h)
|
||||
{
|
||||
int ch;
|
||||
int width = 0;
|
||||
struct font* pf = rb->font_get(graybuf->curfont);
|
||||
|
||||
while ((ch = *str++))
|
||||
{
|
||||
/* check input range */
|
||||
if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
|
||||
ch = pf->defaultchar;
|
||||
ch -= pf->firstchar;
|
||||
|
||||
/* get proportional width */
|
||||
width += pf->width ? pf->width[ch] : pf->maxwidth;
|
||||
}
|
||||
if (w)
|
||||
*w = width;
|
||||
if (h)
|
||||
*h = pf->height;
|
||||
return width;
|
||||
}
|
||||
|
||||
/* Display text with specified foreground and background shades
|
||||
*
|
||||
* If draw_bg is false, only foreground pixels are drawn, so the background
|
||||
* is transparent. In this case bg_brightness is ignored.
|
||||
*/
|
||||
void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg,
|
||||
int fg_brightness, int bg_brightness)
|
||||
{
|
||||
int ch, width;
|
||||
bitmap_t *bits;
|
||||
struct font *pf = rb->font_get(graybuf->curfont);
|
||||
|
||||
if (graybuf == NULL
|
||||
|| (unsigned) x >= (unsigned) graybuf->width
|
||||
|| (unsigned) y >= (unsigned) graybuf->height
|
||||
|| (unsigned) fg_brightness > 255
|
||||
|| (unsigned) bg_brightness > 255)
|
||||
return;
|
||||
|
||||
while ((ch = *str++) != '\0' && x < graybuf->width)
|
||||
{
|
||||
/* check input range */
|
||||
if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
|
||||
ch = pf->defaultchar;
|
||||
ch -= pf->firstchar;
|
||||
|
||||
/* get proportional width and glyph bits */
|
||||
width = pf->width ? pf->width[ch] : pf->maxwidth;
|
||||
bits = pf->bits + (pf->offset ? pf->offset[ch] : (pf->height * ch));
|
||||
|
||||
gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height,
|
||||
width, draw_bg, fg_brightness, bg_brightness);
|
||||
x += width;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef HAVE_LCD_BITMAP
|
||||
#endif // #ifndef SIMULATOR
|
||||
|
||||
|
|
|
@ -75,6 +75,10 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
|
|||
int stride, bool draw_bg, int fg_brightness,
|
||||
int bg_brightness);
|
||||
|
||||
/* font support */
|
||||
void gray_setfont(int newfont);
|
||||
int gray_getstringsize(unsigned char *str, int *w, int *h);
|
||||
|
||||
#endif /* HAVE_LCD_BITMAP */
|
||||
#endif /* SIMULATOR */
|
||||
#endif /* __GRAY_H__ */
|
||||
|
|
Loading…
Reference in a new issue