Included improved grayscale framework

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4627 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jens Arnold 2004-05-15 22:01:30 +00:00
parent 9580e3a577
commit bde77c047d

View file

@ -64,6 +64,9 @@ static struct plugin_api* rb;
#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
#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)))
typedef struct
{
int x;
@ -81,19 +84,21 @@ typedef struct
} tGraybuf;
static tGraybuf *graybuf = NULL;
static short gray_random_buffer;
/** prototypes **/
void timer_isr(void);
void gray_timer_isr(void);
void graypixel(int x, int y, unsigned long pattern);
void grayinvertmasked(int x, int yb, unsigned char mask);
void grayblock(int x, int by, unsigned char* src, int stride);
void grayinvertmasked(int x, int by, unsigned char mask);
/** implementation **/
/* timer interrupt handler: display next bitplane */
void timer_isr(void)
void gray_timer_isr(void)
{
rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane),
rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
graybuf->width);
@ -127,7 +132,6 @@ void timer_isr(void)
* This is the fundamental graphics primitive, asm optimized */
void graypixel(int x, int y, unsigned long pattern)
{
static short random_buffer;
register long address, mask, random;
/* Some (pseudo-)random function must be used here to shift the bit
@ -150,7 +154,7 @@ void graypixel(int x, int y, unsigned long pattern)
: /* outputs */
/* %0 */ "=&r"(random)
: /* inputs */
/* %1 */ "r"(&random_buffer),
/* %1 */ "r"(&gray_random_buffer),
/* %2 */ "r"(graybuf->randmask)
: /* clobbers */
"r1","macl"
@ -259,6 +263,141 @@ void graypixel(int x, int y, unsigned long pattern)
);
}
/* Set 8 pixels to specific gray values at once, asm optimized
* This greatly enhances performance of gray_fillrect() and gray_drawgraymap()
* for larger rectangles and graymaps */
void grayblock(int x, int by, unsigned char* src, int stride)
{
/* 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 (!) */
asm(
"mova .gb_reload,r0 \n" /* set default loopback address */
"tst %1,%1 \n" /* stride == 0 ? */
"bf .gb_needreload \n" /* no: keep that address */
"mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
".gb_needreload: \n"
"mov r0,r2 \n" /* loopback address to r2 */
"mov #7,r3 \n" /* loop count in r3: 8 pixels */
".align 2 \n" /** load pattern for pixel **/
".gb_reload: \n"
"mov.b @%0,r0 \n" /* load src byte */
"extu.b r0,r0 \n" /* extend unsigned */
"mulu %2,r0 \n" /* macl = byte * depth; */
"add %1,%0 \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]; */
".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 */
/* 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 */
"cmp/hs %2,r1 \n" /* random >= depth ? */
"bf .gb_ntrim \n"
"sub %2,r1 \n" /* yes: random -= depth; */
".gb_ntrim: \n"
"mov.l .ashlsi3,r0 \n" /** rotate pattern **/
"jsr @r0 \n" /* shift r4 left by r1 */
"mov r1,r5 \n"
"mov %2,r5 \n"
"sub r1,r5 \n" /* r5 = depth - r1 */
"mov r0,r1 \n" /* last result stored in r1 */
"mov.l .lshrsi3,r0 \n"
"jsr @r0 \n" /* shift r4 right by r5 */
"nop \n"
"or r1,r0 \n" /* rotated_pattern = r0 | r1 */
"mov.l r0,@-r15 \n" /* push pattern */
"cmp/pl r3 \n" /* loop count > 0? */
"bf .gb_patdone \n" /* no: done */
"jmp @r2 \n" /* yes: loop */
"add #-1,r3 \n" /* decrease loop count */
".align 2 \n"
".ashlsi3: \n" /* C library routine: */
".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
".lshrsi3: \n" /* C library routine: */
".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
/* both routines preserve r4, destroy r5 and take ~16 cycles */
".gb_patdone: \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(src),
/* %1 */ "r"(stride),
/* %2 */ "r"(graybuf->depth),
/* %3 */ "r"(graybuf->bitpattern),
/* %4 */ "r"(&gray_random_buffer),
/* %5 */ "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);
/* set the bits for all 8 pixels in all bytes according to the
* precalculated patterns on the 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"
".gb_loop: \n" /* loop for all bitplanes */
"shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
"rotcl r0 \n" /* rotate t bit into r0 */
"shlr r2 \n"
"rotcl r0 \n"
"shlr r3 \n"
"rotcl r0 \n"
"shlr r4 \n"
"rotcl r0 \n"
"shlr r5 \n"
"rotcl r0 \n"
"shlr r6 \n"
"rotcl r0 \n"
"shlr r7 \n"
"rotcl r0 \n"
"shlr r8 \n"
"rotcl r0 \n"
"mov.b r0,@%0 \n" /* store byte to bitplane */
"add %2,%0 \n" /* advance to next bitplane */
"cmp/hi %0,%1 \n" /* last bitplane done? */
"bt .gb_loop \n" /* no: loop */
: /* outputs */
: /* inputs */
/* %0 */ "r"(address),
/* %1 */ "r"(end_addr),
/* %2 */ "r"(graybuf->plane_size)
: /* clobbers */
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
);
}
/* Invert the bits for 1-8 pixels within the buffer */
void grayinvertmasked(int x, int by, unsigned char mask)
{
@ -335,7 +474,9 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
int possible_depth, plane_size;
int i, j;
if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1)
if ((unsigned) width > LCD_WIDTH
|| (unsigned) bheight > (LCD_HEIGHT >> 3)
|| depth < 1)
return 0;
while ((unsigned long)gbuf & 3) /* the buffer has to be long aligned */
@ -472,7 +613,7 @@ void gray_show_display(bool enable)
if (enable)
{
graybuf->flags |= GRAY_RUNNING;
rb->plugin_register_timer(FREQ / 67, 1, timer_isr);
rb->plugin_register_timer(FREQ / 67, 1, gray_timer_isr);
}
else
{
@ -532,7 +673,7 @@ void gray_clear_display(void)
if (graybuf == NULL)
return;
rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size);
rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
}
/* Set the grayscale display to all black
@ -542,7 +683,7 @@ void gray_black_display(void)
if (graybuf == NULL)
return;
rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size);
rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
}
/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
@ -566,11 +707,11 @@ void gray_deferred_update(void)
*/
void gray_scroll_left(int count, bool black_border)
{
int x, by, d;
unsigned char *src, *dest;
int by, d;
unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL || count >= graybuf->width)
if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
return;
if (black_border)
@ -581,17 +722,42 @@ void gray_scroll_left(int count, bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 0; by < graybuf->bheight; by++)
{
ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
dest = graybuf->data + graybuf->plane_size * d
+ graybuf->width * by;
src = dest + count;
if (count & 1) /* odd count: scroll byte-wise */
asm volatile (
".sl_loop1: \n"
"mov.b @%0+,r1 \n"
"mov.b r1,@(%2,%0) \n"
"cmp/hi %0,%1 \n"
"bt .sl_loop1 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(ptr + count),
/* %1 */ "r"(ptr + graybuf->width),
/* %2 */ "z"(-count - 1)
: /* clobbers */
"r1"
);
else /* even count: scroll word-wise */
asm volatile (
".sl_loop2: \n"
"mov.w @%0+,r1 \n"
"mov.w r1,@(%2,%0) \n"
"cmp/hi %0,%1 \n"
"bt .sl_loop2 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(ptr + count),
/* %1 */ "r"(ptr + graybuf->width),
/* %2 */ "z"(-count - 2)
: /* clobbers */
"r1"
);
for (x = count; x < graybuf->width; x++)
*dest++ = *src++;
for (x = 0; x < count; x++)
*dest++ = filler;
rb->memset(ptr + graybuf->width - count, filler, count);
ptr += graybuf->plane_size;
}
}
}
@ -603,11 +769,11 @@ void gray_scroll_left(int count, bool black_border)
*/
void gray_scroll_right(int count, bool black_border)
{
int x, by, d;
unsigned char *src, *dest;
int by, d;
unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL || count >= graybuf->width)
if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
return;
if (black_border)
@ -618,17 +784,42 @@ void gray_scroll_right(int count, bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 0; by < graybuf->bheight; by++)
{
ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
dest = graybuf->data + graybuf->plane_size * d
+ graybuf->width * (by + 1) - 1;
src = dest - count;
if (count & 1) /* odd count: scroll byte-wise */
asm volatile (
".sr_loop1: \n"
"mov.b @(%2,%0),r1 \n"
"mov.b r1,@-%0 \n"
"cmp/hs %1,%0 \n"
"bt .sr_loop1 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(ptr + graybuf->width),
/* %1 */ "r"(ptr + count),
/* %2 */ "z"(-count - 1)
: /* clobbers */
"r1"
);
else /* even count: scroll word-wise */
asm volatile (
".sr_loop2: \n"
"mov.w @(%2,%0),r1 \n"
"mov.w r1,@-%0 \n"
"cmp/hs %1,%0 \n"
"bt .sr_loop2 \n"
: /* outputs */
: /* inputs */
/* %0 */ "r"(ptr + graybuf->width),
/* %1 */ "r"(ptr + count),
/* %2 */ "z"(-count - 2)
: /* clobbers */
"r1"
);
for (x = count; x < graybuf->width; x++)
*dest-- = *src--;
for (x = 0; x < count; x++)
*dest-- = filler;
rb->memset(ptr, filler, count);
ptr += graybuf->plane_size;
}
}
}
@ -641,7 +832,7 @@ void gray_scroll_right(int count, bool black_border)
void gray_scroll_up8(bool black_border)
{
int by, d;
unsigned char *src;
unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL)
@ -655,18 +846,19 @@ void gray_scroll_up8(bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 1; by < graybuf->bheight; by++)
{
ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
src = graybuf->data + graybuf->plane_size * d
+ graybuf->width * by;
rb->memcpy(src - graybuf->width, src, graybuf->width);
rb->memcpy(ptr - graybuf->width, ptr, graybuf->width);
ptr += graybuf->plane_size;
}
}
for (d = 0; d < graybuf->depth; d++) /* fill last row */
/* fill last row */
ptr = graybuf->data + graybuf->plane_size - graybuf->width;
for (d = 0; d < graybuf->depth; d++)
{
rb->memset(graybuf->data + graybuf->plane_size * (d + 1)
- graybuf->width, filler, graybuf->width);
rb->memset(ptr, filler, graybuf->width);
ptr += graybuf->plane_size;
}
}
@ -678,7 +870,7 @@ void gray_scroll_up8(bool black_border)
void gray_scroll_down8(bool black_border)
{
int by, d;
unsigned char *dest;
unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL)
@ -692,18 +884,19 @@ void gray_scroll_down8(bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = graybuf->bheight - 1; by > 0; by--)
{
ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
dest = graybuf->data + graybuf->plane_size * d
+ graybuf->width * by;
rb->memcpy(dest, dest - graybuf->width, graybuf->width);
rb->memcpy(ptr, ptr - graybuf->width, graybuf->width);
ptr += graybuf->plane_size;
}
}
for (d = 0; d < graybuf->depth; d++) /* fill first row */
/* fill first row */
ptr = graybuf->data;
for (d = 0; d < graybuf->depth; d++)
{
rb->memset(graybuf->data + graybuf->plane_size * d, filler,
graybuf->width);
rb->memset(ptr, filler, graybuf->width);
ptr += graybuf->plane_size;
}
}
@ -851,12 +1044,14 @@ void gray_scroll_down1(bool black_border)
*/
void gray_drawpixel(int x, int y, int brightness)
{
if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height
|| brightness > 255)
if (graybuf == NULL
|| (unsigned) x >= (unsigned) graybuf->width
|| (unsigned) y >= (unsigned) graybuf->height
|| (unsigned) brightness > 255)
return;
graypixel(x, y, graybuf->bitpattern[(brightness
* (graybuf->depth + 1)) >> 8]);
graypixel(x, y, graybuf->bitpattern[MULU16(brightness,
graybuf->depth + 1) >> 8]);
}
/* Invert a pixel
@ -866,7 +1061,9 @@ void gray_drawpixel(int x, int y, int brightness)
*/
void gray_invertpixel(int x, int y)
{
if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
if (graybuf == NULL
|| (unsigned) x >= (unsigned) graybuf->width
|| (unsigned) y >= (unsigned) graybuf->height)
return;
grayinvertmasked(x, (y >> 3), 1 << (y & 7));
@ -886,14 +1083,20 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
int y, yinc1, yinc2;
unsigned long pattern;
if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
|| x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255)
if (graybuf == NULL
|| (unsigned) x1 >= (unsigned) graybuf->width
|| (unsigned) y1 >= (unsigned) graybuf->height
|| (unsigned) x2 >= (unsigned) graybuf->width
|| (unsigned) y2 >= (unsigned) graybuf->height
|| (unsigned) brightness > 255)
return;
pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
xinc2 = 1;
yinc2 = 1;
if (deltax >= deltay)
{
@ -902,9 +1105,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
}
else
{
@ -913,9 +1114,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
numpixels++; /* include endpoints */
@ -967,12 +1166,17 @@ void gray_invertline(int x1, int y1, int x2, int y2)
int x, xinc1, xinc2;
int y, yinc1, yinc2;
if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
|| x2 >= graybuf->width || y2 >= graybuf->height)
if (graybuf == NULL
|| (unsigned) x1 >= (unsigned) graybuf->width
|| (unsigned) y1 >= (unsigned) graybuf->height
|| (unsigned) x2 >= (unsigned) graybuf->width
|| (unsigned) y2 >= (unsigned) graybuf->height)
return;
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
xinc2 = 1;
yinc2 = 1;
if (deltax >= deltay)
{
@ -981,9 +1185,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
}
else
{
@ -992,9 +1194,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
numpixels++; /* include endpoints */
@ -1041,13 +1241,16 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
{
int x, y;
unsigned long pattern;
unsigned char srcpixel;
if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
|| x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255)
if (graybuf == NULL
|| (unsigned) x1 >= (unsigned) graybuf->width
|| (unsigned) y1 >= (unsigned) graybuf->height
|| (unsigned) x2 >= (unsigned) graybuf->width
|| (unsigned) y2 >= (unsigned) graybuf->height
|| (unsigned) brightness > 255)
return;
pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
if (y1 > y2)
{
y = y1;
@ -1061,15 +1264,30 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
x2 = x;
}
for (x = x1; x <= x2; x++)
pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
srcpixel = brightness;
for (x = x1 + 1; x < x2; x++)
{
graypixel(x, y1, pattern);
graypixel(x, y2, pattern);
}
for (y = y1; y <= y2; y++)
for (y = y1; y <= y2; )
{
if (!(y & 7) && (y2 - y >= 7))
/* current row byte aligned in fb & at least 8 rows left */
{
/* shortcut: draw all 8 rows at once: 2..3 times faster */
grayblock(x1, y >> 3, &srcpixel, 0);
grayblock(x2, y >> 3, &srcpixel, 0);
y += 8;
}
else
{
graypixel(x1, y, pattern);
graypixel(x2, y, pattern);
y++;
}
}
}
@ -1082,9 +1300,14 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
{
int x, y;
unsigned long pattern;
unsigned char srcpixel;
if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
|| x2 >= graybuf->width || y2 >= graybuf->height || brightness > 255)
if (graybuf == NULL
|| (unsigned) x1 >= (unsigned) graybuf->width
|| (unsigned) y1 >= (unsigned) graybuf->height
|| (unsigned) x2 >= (unsigned) graybuf->width
|| (unsigned) y2 >= (unsigned) graybuf->height
|| (unsigned) brightness > 255)
return;
if (y1 > y2)
@ -1100,14 +1323,29 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
x2 = x;
}
pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
srcpixel = brightness;
for (y = y1; y <= y2; y++)
for (y = y1; y <= y2; )
{
if (!(y & 7) && (y2 - y >= 7))
/* current row byte aligned in fb & at least 8 rows left */
{
for (x = x1; x <= x2; x++)
{
/* shortcut: draw all 8 rows at once: 2..3 times faster */
grayblock(x, y >> 3, &srcpixel, 0);
}
y += 8;
}
else
{
for (x = x1; x <= x2; x++)
{
graypixel(x, y, pattern);
}
y++;
}
}
}
@ -1122,8 +1360,11 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
int x, yb, yb1, yb2;
unsigned char mask;
if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
|| x2 >= graybuf->width || y2 >= graybuf->height)
if (graybuf == NULL
|| (unsigned) x1 >= (unsigned) graybuf->width
|| (unsigned) y1 >= (unsigned) graybuf->height
|| (unsigned) x2 >= (unsigned) graybuf->width
|| (unsigned) y2 >= (unsigned) graybuf->height)
return;
if (y1 > y2)
@ -1175,7 +1416,7 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
* A grayscale bitmap contains one byte for every pixel that defines the
* brightness of the pixel (0..255). Bytes are read in row-major order.
* The <stride> parameter is useful if you want to show only a part of a
* bitmap. It should always be set to the "line length" of the bitmap, so
* bitmap. It should always be set to the "row length" of the bitmap, so
* for displaying the whole bitmap, nx == stride.
*/
void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
@ -1184,7 +1425,9 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
int xi, yi;
unsigned char *row;
if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
if (graybuf == NULL
|| (unsigned) x >= (unsigned) graybuf->width
|| (unsigned) y >= (unsigned) graybuf->height)
return;
if ((y + ny) >= graybuf->height) /* clip bottom */
@ -1193,28 +1436,49 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
if ((x + nx) >= graybuf->width) /* clip right */
nx = graybuf->width - x;
for (yi = y; yi < y + ny; yi++)
for (yi = y; yi < y + ny; )
{
row = src;
src += stride;
if (!(yi & 7) && (y + ny - yi > 7))
/* current row byte aligned in fb & at least 8 rows left */
{
for (xi = x; xi < x + nx; xi++)
{
graypixel(xi, yi, graybuf->bitpattern[((int)(*row++)
* (graybuf->depth + 1)) >> 8]);
/* shortcut: draw all 8 rows at once: 2..3 times faster */
grayblock(xi, yi >> 3, row++, stride);
}
yi += 8;
src += stride << 3;
}
else
{
for (xi = x; xi < x + nx; xi++)
{
graypixel(xi, yi, graybuf->bitpattern[MULU16(*row++,
graybuf->depth + 1) >> 8]);
}
yi++;
src += stride;
}
}
}
/* Display a bitmap with specific foreground and background gray values
*
* This (now) uses the same bitmap format as the core b&w graphics routines,
* so you can use bmp2rb to generate bitmaps for use with this function as
* well.
*
* A bitmap contains one bit for every pixel that defines if that pixel is
* foreground (1) or background (0). Bytes are read in row-major order, MSB
* first. A row consists of an integer number of bytes, extra bits past the
* right margin are ignored.
* foreground (1) or background (0). Bits within a byte are arranged
* vertically, LSB at top.
* The bytes are stored in row-major order, with byte 0 being top left,
* byte 1 2nd from left etc. The first row of bytes defines pixel rows
* 0..7, the second row defines pixel row 8..15 etc.
*
* The <stride> parameter is useful if you want to show only a part of a
* bitmap. It should always be set to the "line length" of the bitmap.
* Beware that this is counted in bytes, so nx == 8 * stride for the whole
* bitmap.
* bitmap. It should always be set to the "row length" of the bitmap.
*
* If draw_bg is false, only foreground pixels are drawn, so the background
* is transparent. In this case bg_brightness is ignored.
@ -1223,13 +1487,16 @@ 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)
{
int xi, yi, i;
int xi, dy;
int bits = 0; /* Have to initialize to prevent warning */
unsigned long fg_pattern, bg_pattern;
unsigned long bits = 0; /* Have to initialize to prevent warning */
unsigned char *row;
unsigned char *col;
if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height
|| fg_brightness > 255 || bg_brightness > 255)
if (graybuf == NULL
|| (unsigned) x >= (unsigned) graybuf->width
|| (unsigned) y >= (unsigned) graybuf->height
|| (unsigned) fg_brightness > 255
|| (unsigned) bg_brightness > 255)
return;
if ((y + ny) >= graybuf->height) /* clip bottom */
@ -1238,36 +1505,36 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
if ((x + nx) >= graybuf->width) /* clip right */
nx = graybuf->width - x;
fg_pattern = graybuf->bitpattern[(fg_brightness
* (graybuf->depth + 1)) >> 8];
fg_pattern = graybuf->bitpattern[MULU16(fg_brightness,
graybuf->depth + 1) >> 8];
bg_pattern = graybuf->bitpattern[(bg_brightness
* (graybuf->depth + 1)) >> 8];
bg_pattern = graybuf->bitpattern[MULU16(bg_brightness,
graybuf->depth + 1) >> 8];
for (yi = y; yi < y + ny; yi++)
{
i = 0;
row = src;
src += stride;
for (xi = x; xi < x + nx; xi++)
{
if (i == 0) /* get next 8 bits */
bits = (unsigned long)(*row++);
col = src++;
for (dy = 0; dy < ny; dy++)
{
if (!(dy & 7)) /* get next 8 bits */
{
bits = (int)(*col);
col += stride;
}
if (bits & 0x80)
graypixel(xi, yi, fg_pattern);
if (bits & 0x01)
graypixel(xi, y + dy, fg_pattern);
else
if (draw_bg)
graypixel(xi, yi, bg_pattern);
graypixel(xi, y + dy, bg_pattern);
bits <<= 1;
i++;
i &= 7;
bits >>= 1;
}
}
}
/**************** end grayscale framework ********************/
/*********************** end grayscale framework ***************************/
/* for portability of below JPEG code */
#define MEMSET(p,v,c) rb->memset(p,v,c)