From 93867305d514b90bec2d5d7541297aef6a157efa Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Thu, 30 Jun 2005 21:07:00 +0000 Subject: Player graphics library extended and converted to new api. Please note that the player gfx bitmap format chas changed. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6956 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/lib/playergfx.c | 375 ++++++++++++++++++++++++++++++++++++------- apps/plugins/lib/playergfx.h | 18 ++- apps/plugins/logo.c | 8 +- apps/plugins/mosaique.c | 44 ++--- apps/plugins/snow.c | 20 +-- 5 files changed, 354 insertions(+), 111 deletions(-) (limited to 'apps') 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 @@ #ifdef HAVE_LCD_CHARCELLS /* Player only :) */ #include "playergfx.h" -/* Global variables */ +/*** globals ***/ + static struct plugin_api *pgfx_rb = NULL; /* global api struct pointer */ static int char_width; static int char_height; -static unsigned pixel_height; -static unsigned pixel_width; +static int pixel_height; +static int pixel_width; static unsigned char gfx_chars[8]; static unsigned char gfx_buffer[56]; +static int drawmode = DRMODE_SOLID; -/* Private function declarations */ -static void linefunc(int x1, int y1, int x2, int y2, - void (*pixelfunc)(int x, int y)); - -/* Implementation */ +/*** Special functions ***/ +/* library init */ bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight) { int i; @@ -64,6 +63,7 @@ bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight) return true; } +/* library deinit */ void pgfx_release(void) { int i; @@ -73,6 +73,7 @@ void pgfx_release(void) pgfx_rb->lcd_unlock_pattern(gfx_chars[i]); } +/* place the display */ void pgfx_display(int cx, int cy) { int i, j; @@ -84,6 +85,8 @@ void pgfx_display(int cx, int cy) pgfx_rb->lcd_putc(cx + i, cy + j, gfx_chars[char_height * i + j]); } +/*** Update functions ***/ + void pgfx_update(void) { int i; @@ -92,28 +95,111 @@ void pgfx_update(void) pgfx_rb->lcd_define_pattern(gfx_chars[i], gfx_buffer + 7 * i); } -void pgfx_clear_display(void) +/*** Parameter handling ***/ + +void pgfx_set_drawmode(int mode) { - pgfx_rb->memset(gfx_buffer, 0, char_width * pixel_height); + drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } -void pgfx_drawpixel(int x, int y) +int pgfx_get_drawmode(void) +{ + return drawmode; +} + +/*** Low-level drawing functions ***/ + +static void setpixel(int x, int y) { gfx_buffer[pixel_height * (x/5) + y] |= 0x10 >> (x%5); } -void pgfx_clearpixel(int x, int y) +static void clearpixel(int x, int y) { gfx_buffer[pixel_height * (x/5) + y] &= ~(0x10 >> (x%5)); } -void pgfx_invertpixel(int x, int y) +static void flippixel(int x, int y) { gfx_buffer[pixel_height * (x/5) + y] ^= 0x10 >> (x%5); } -static void linefunc(int x1, int y1, int x2, int y2, - void (*pixelfunc)(int x, int y)) +static void nopixel(int x, int y) +{ + (void)x; + (void)y; +} + +lcd_pixelfunc_type* pgfx_pixelfuncs[8] = { + flippixel, nopixel, setpixel, setpixel, + nopixel, clearpixel, nopixel, clearpixel +}; + +static void flipblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address ^= (bits & mask); +} + +static void bgblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address &= (bits | ~mask); +} + +static void fgblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address |= (bits & mask); +} + +static void solidblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (bits & mask); +} + +static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address ^= (~bits & mask); +} + +static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address &= ~(bits & mask); +} + +static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address |= (~bits & mask); +} + +static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (~bits & mask); +} + +lcd_blockfunc_type* pgfx_blockfuncs[8] = { + flipblock, bgblock, fgblock, solidblock, + flipinvblock, bginvblock, fginvblock, solidinvblock +}; + +/*** Drawing functions ***/ + +/* Clear the whole display */ +void pgfx_clear_display(void) +{ + unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0x1F : 0; + + pgfx_rb->memset(gfx_buffer, bits, char_width * pixel_height); +} + +/* Set a single pixel */ +void pgfx_drawpixel(int x, int y) +{ + if (((unsigned)x < (unsigned)pixel_width) + && ((unsigned)y < (unsigned)pixel_height)) + pgfx_pixelfuncs[drawmode](x, y); +} + +/* Draw a line */ +void pgfx_drawline(int x1, int y1, int x2, int y2) { int numpixels; int i; @@ -121,6 +207,7 @@ static void linefunc(int x1, int y1, int x2, int y2, int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; + lcd_pixelfunc_type *pfunc = pgfx_pixelfuncs[drawmode]; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -147,13 +234,13 @@ static void linefunc(int x1, int y1, int x2, int y2, } numpixels++; /* include endpoints */ - if(x1 > x2) + if (x1 > x2) { xinc1 = -xinc1; xinc2 = -xinc2; } - if(y1 > y2) + if (y1 > y2) { yinc1 = -yinc1; yinc2 = -yinc2; @@ -164,7 +251,9 @@ static void linefunc(int x1, int y1, int x2, int y2, for (i = 0; i < numpixels; i++) { - pixelfunc(x, y); + if (((unsigned)x < (unsigned)pixel_width) + && ((unsigned)y < (unsigned)pixel_height)) + pfunc(x, y); if (d < 0) { @@ -181,69 +270,237 @@ static void linefunc(int x1, int y1, int x2, int y2, } } -void pgfx_drawline(int x1, int y1, int x2, int y2) +/* Draw a horizontal line (optimised) */ +void pgfx_hline(int x1, int x2, int y) { - linefunc(x1, y1, x2, y2, pgfx_drawpixel); -} + int nx; + unsigned char *dst; + unsigned mask, mask_right; + lcd_blockfunc_type *bfunc; -void pgfx_clearline(int x1, int y1, int x2, int y2) -{ - linefunc(x1, y1, x2, y2, pgfx_clearpixel); + /* direction flip */ + if (x2 < x1) + { + nx = x1; + x1 = x2; + x2 = nx; + } + + /* nothing to draw? */ + if (((unsigned)y >= (unsigned)pixel_height) || (x1 >= pixel_width) + || (x2 < 0)) + return; + + /* clipping */ + if (x1 < 0) + x1 = 0; + if (x2 >= pixel_width) + x2 = pixel_width - 1; + + bfunc = pgfx_blockfuncs[drawmode]; + dst = &gfx_buffer[pixel_height * (x1/5) + y]; + nx = x2 - (x1 - (x1 % 5)); + mask = 0x1F >> (x1 % 5); + mask_right = 0x1F0 >> (nx % 5); + + for (; nx >= 5; nx -= 5) + { + bfunc(dst, mask, 0xFFu); + dst += pixel_height; + mask = 0x1F; + } + mask &= mask_right; + bfunc(dst, mask, 0x1F); } -void pgfx_invertline(int x1, int y1, int x2, int y2) +/* Draw a vertical line (optimised) */ +void pgfx_vline(int x, int y1, int y2) { - linefunc(x1, y1, x2, y2, pgfx_invertpixel); + int y; + unsigned char *dst; + unsigned mask; + lcd_blockfunc_type *bfunc; + + /* direction flip */ + if (y2 < y1) + { + y = y1; + y1 = y2; + y2 = y; + } + + /* nothing to draw? */ + if (((unsigned)x >= (unsigned)pixel_width) || (y1 >= pixel_height) + || (y2 < 0)) + return; + + /* clipping */ + if (y1 < 0) + y1 = 0; + if (y2 >= pixel_height) + y2 = pixel_height - 1; + + bfunc = pgfx_blockfuncs[drawmode]; + dst = &gfx_buffer[pixel_height * (x/5) + y1]; + mask = 0x10 >> (x % 5); + + for (y = y1; y <= y2; y++) + bfunc(dst++, mask, 0x1F); } -void pgfx_invertrect (int x, int y, int nx, int ny) +/* Draw a rectangular box */ +void pgfx_drawrect(int x, int y, int width, int height) { - int i, j; - - if (((unsigned) x >= pixel_width) || ((unsigned) y >= pixel_height)) + if ((width <= 0) || (height <= 0)) return; - if ((unsigned)(x + nx) > pixel_width) - nx = pixel_width - x; - if ((unsigned)(y + ny) > pixel_height) - ny = pixel_height - y; + int x2 = x + width - 1; + int y2 = y + height - 1; - for (i = 0; i < nx; i++) - for (j = 0; j < ny; j++) - pgfx_invertpixel(x + i, y + j); + pgfx_vline(x, y, y2); + pgfx_vline(x2, y, y2); + pgfx_hline(x, x2, y); + pgfx_hline(x, x2, y2); } -void pgfx_bitmap (const unsigned char *src, int x, int y, int nx, int ny, - bool clear) +/* Fill a rectangular area */ +void pgfx_fillrect(int x, int y, int width, int height) { - int stride, i, j; - unsigned data; - - if (((unsigned) x >= pixel_width) || ((unsigned) y >= pixel_height)) + int nx, i; + unsigned char *dst; + unsigned mask, mask_right; + lcd_blockfunc_type *bfunc; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= pixel_width) + || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0)) return; - stride = nx; /* otherwise right-clipping will destroy the image */ + /* clipping */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > pixel_width) + width = pixel_width - x; + if (y + height > pixel_height) + height = pixel_height - y; + + bfunc = pgfx_blockfuncs[drawmode]; + dst = &gfx_buffer[pixel_height * (x/5) + y]; + nx = width - 1 + (x % 5); + mask = 0x1F >> (x % 5); + mask_right = 0x1F0 >> (nx % 5); + + for (; nx >= 5; nx -= 5) + { + unsigned char *dst_col = dst; + + for (i = height; i > 0; i--) + bfunc(dst_col++, mask, 0x1F); - if (((unsigned)(x + nx)) >= pixel_width) - nx = pixel_width - x; - if (((unsigned)(y + ny)) >= pixel_height) - ny = pixel_height - y; + dst += pixel_height; + mask = 0x1F; + } + mask &= mask_right; - for (i = 0; i < nx; i++, src++) + for (i = height; i > 0; i--) + bfunc(dst++, mask, 0x1F); +} + +/* About PlayerGFX internal bitmap format: + * + * A bitmap contains one bit for every pixel that defines if that pixel is + * black (1) or white (0). Bits within a byte are arranged horizontally, + * MSB at the left. + * The bytes are stored in row-major order, with byte 0 being top left, + * byte 1 2nd from left etc. Each row of bytes defines one pixel row. + * + * This approximates the (even more strange) internal hardware format. */ + +/* Draw a partial bitmap. Note that stride is given in bytes */ +void pgfx_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + int nx, shift; + unsigned char *dst; + unsigned mask, mask_right; + lcd_blockfunc_type *bfunc; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= pixel_width) + || (y >= pixel_height) || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > pixel_width) + width = pixel_width - x; + if (y + height > pixel_height) + height = pixel_height - y; + + src += stride * src_y + (src_x >> 3); /* move starting point */ + dst = &gfx_buffer[pixel_height * (x/5) + y]; + shift = 3 + (x % 5) - (src_x & 7); + nx = width - 1 + (x % 5); + + bfunc = pgfx_blockfuncs[drawmode]; + mask = 0x1F >> (x % 5); + mask_right = 0x1F0 >> (nx % 5); + + for (y = 0; y < height; y++) { - data = src[0]; - if (ny > 8) /* ny is max. 14 */ - data |= src[stride] << 8; - for (j = 0; j < ny; j++) + const unsigned char *src_row = src; + unsigned char *dst_row = dst; + unsigned mask_row = mask; + unsigned data = *src_row++; + int extrabits = shift; + + for (x = nx; x >= 5; x -= 5) { - if (data & 1) - pgfx_drawpixel(x + i, y + j); - else - if (clear) - pgfx_clearpixel(x + i, y + j); - data >>= 1; + if (extrabits < 0) + { + data = (data << 8) | *src_row++; + extrabits += 8; + } + bfunc(dst_row, mask_row, data >> extrabits); + extrabits -= 5; + dst_row += pixel_height; + mask_row = 0x1F; } + if (extrabits < 0) + { + data = (data << 8) | *src_row; + extrabits += 8; + } + bfunc(dst_row, mask_row & mask_right, data >> extrabits); + + src += stride; + dst++; } } +/* Draw a full bitmap */ +void pgfx_bitmap(const unsigned char *src, int x, int y, int width, int height) +{ + pgfx_bitmap_part(src, 0, 0, (width + 7) >> 3, x, y, width, height); +} + #endif /* HAVE_LCD_CHARCELLS */ diff --git a/apps/plugins/lib/playergfx.h b/apps/plugins/lib/playergfx.h index ced484398e..a0e3973dd4 100644 --- a/apps/plugins/lib/playergfx.h +++ b/apps/plugins/lib/playergfx.h @@ -30,16 +30,20 @@ bool pgfx_init(struct plugin_api* newrb, int cwidth, int cheight); void pgfx_release(void); void pgfx_display(int cx, int cy); void pgfx_update(void); + +void pgfx_set_drawmode(int mode); +int pgfx_get_drawmode(void); + void pgfx_clear_display(void); void pgfx_drawpixel(int x, int y); -void pgfx_clearpixel(int x, int y); -void pgfx_invertpixel(int x, int y); void pgfx_drawline(int x1, int y1, int x2, int y2); -void pgfx_clearline(int x1, int y1, int x2, int y2); -void pgfx_invertline(int x1, int y1, int x2, int y2); -void pgfx_invertrect (int x, int y, int nx, int ny); -void pgfx_bitmap (const unsigned char *src, int x, int y, int nx, int ny, - bool clear); +void pgfx_hline(int x1, int x2, int y); +void pgfx_vline(int x, int y1, int y2); +void pgfx_drawrect(int x, int y, int width, int height); +void pgfx_fillrect(int x, int y, int width, int height); +void pgfx_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height); +void pgfx_bitmap(const unsigned char *src, int x, int y, int width, int height); #endif /* HAVE_LCD_CHARCELLS */ #endif /* __PGFX_H__ */ diff --git a/apps/plugins/logo.c b/apps/plugins/logo.c index ba3c86c9f2..08e0266a75 100644 --- a/apps/plugins/logo.c +++ b/apps/plugins/logo.c @@ -64,7 +64,7 @@ const unsigned char rockbox91x32[] = { 0x08, 0x10, 0x20, 0x41, 0x42, 0x42, 0x43, 0x42, 0x41, 0x40, 0x60, 0x50, 0x40, 0x40, 0x40, 0x20, 0x50, 0x28, 0x10, 0x20, 0x40, 0x43, 0x44, 0x5b, 0x64, 0x18, }; -#endif /* IRIVER_H100 */ +#endif /* HAVE_REMOTE_LCD */ #if LCD_WIDTH > 112 #define LOGO_WIDTH 112 @@ -169,8 +169,8 @@ const unsigned char rockbox91x32[] = { #define LOGO_HEIGHT 7 #define LOGO rockbox16x7 const unsigned char rockbox16x7[] = { - 0x0a, 0x55, 0x7e, 0x18, 0x00, 0xff, 0xff, 0x09, - 0xff, 0x76, 0x00, 0xff, 0xff, 0x44, 0x7c, 0x38, + 0x47, 0x18, 0xa6, 0xd8, 0x66, 0xde, 0xb7, 0x9b, + 0x76, 0xdb, 0x26, 0xdb, 0x66, 0xde, }; #endif /* !LCD_BITMAP */ @@ -240,7 +240,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { #endif #else pgfx_clear_display(); - pgfx_bitmap(LOGO, x % 5, y, LOGO_WIDTH, LOGO_HEIGHT, false); + pgfx_bitmap(LOGO, x % 5, y, LOGO_WIDTH, LOGO_HEIGHT); cpos = x / 5; #endif diff --git a/apps/plugins/mosaique.c b/apps/plugins/mosaique.c index 87ff3a4fdc..75bd155338 100644 --- a/apps/plugins/mosaique.c +++ b/apps/plugins/mosaique.c @@ -22,9 +22,11 @@ #ifdef HAVE_LCD_BITMAP #define LARGE ((LCD_WIDTH - 2) / 2) #define HAUT ((LCD_HEIGHT - 2) / 2) +#define MYLCD(fn) rb->lcd_ ## fn #else #define LARGE 9 #define HAUT 6 +#define MYLCD(fn) pgfx_ ## fn #endif /* variable button definitions */ @@ -62,18 +64,16 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) TEST_PLUGIN_API(api); (void)parameter; -#ifdef HAVE_LCD_BITMAP - rb->lcd_clear_display(); - rb->lcd_set_drawmode(DRMODE_COMPLEMENT); -#else +#ifdef HAVE_LCD_CHARCELLS if (!pgfx_init(rb, 4, 2)) { rb->splash(HZ*2, true, "Old LCD :("); return PLUGIN_OK; } pgfx_display(3, 0); - pgfx_clear_display(); #endif + MYLCD(clear_display)(); + MYLCD(set_drawmode)(DRMODE_COMPLEMENT); while (1) { x+=sx; @@ -102,19 +102,11 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) sy = -sy; } -#ifdef HAVE_LCD_BITMAP - rb->lcd_fillrect(LARGE-x, HAUT-y, 2*x+1, 1); - rb->lcd_fillrect(LARGE-x, HAUT+y, 2*x+1, 1); - rb->lcd_fillrect(LARGE-x, HAUT-y+1, 1, 2*y-1); - rb->lcd_fillrect(LARGE+x, HAUT-y+1, 1, 2*y-1); - rb->lcd_update(); -#else - pgfx_invertrect(LARGE-x, HAUT-y, 2*x+1, 1); - pgfx_invertrect(LARGE-x, HAUT+y, 2*x+1, 1); - pgfx_invertrect(LARGE-x, HAUT-y+1, 1, 2*y-1); - pgfx_invertrect(LARGE+x, HAUT-y+1, 1, 2*y-1); - pgfx_update(); -#endif + MYLCD(fillrect)(LARGE-x, HAUT-y, 2*x+1, 1); + MYLCD(fillrect)(LARGE-x, HAUT+y, 2*x+1, 1); + MYLCD(fillrect)(LARGE-x, HAUT-y+1, 1, 2*y-1); + MYLCD(fillrect)(LARGE+x, HAUT-y+1, 1, 2*y-1); + MYLCD(update)(); rb->sleep(HZ/timer); @@ -122,9 +114,8 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) switch (button) { case MOSAIQUE_QUIT: -#ifdef HAVE_LCD_BITMAP - rb->lcd_set_drawmode(DRMODE_SOLID); -#else + MYLCD(set_drawmode)(DRMODE_SOLID); +#ifdef HAVE_LCD_CHARCELLS pgfx_release(); #endif return PLUGIN_OK; @@ -141,20 +132,15 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) sy = rb->rand() % (HAUT/2) + 1; x=0; y=0; -#ifdef HAVE_LCD_BITMAP - rb->lcd_clear_display(); -#else - pgfx_clear_display(); -#endif + MYLCD(clear_display)(); break; default: if (rb->default_event_handler(button) == SYS_USB_CONNECTED) { -#ifdef HAVE_LCD_BITMAP - rb->lcd_set_drawmode(DRMODE_SOLID); -#else + MYLCD(set_drawmode)(DRMODE_SOLID); +#ifdef HAVE_LCD_CHARCELLS pgfx_release(); #endif return PLUGIN_USB_CONNECTED; diff --git a/apps/plugins/snow.c b/apps/plugins/snow.c index b3d3b14c46..75c561427a 100644 --- a/apps/plugins/snow.c +++ b/apps/plugins/snow.c @@ -23,10 +23,12 @@ #define NUM_PARTICLES (LCD_WIDTH * LCD_HEIGHT / 72) #define SNOW_HEIGHT LCD_HEIGHT #define SNOW_WIDTH LCD_WIDTH +#define MYLCD(fn) rb->lcd_ ## fn #else #define NUM_PARTICLES 10 #define SNOW_HEIGHT 14 #define SNOW_WIDTH 20 +#define MYLCD(fn) pgfx_ ## fn #endif /* variable button definitions */ @@ -81,14 +83,14 @@ static void snow_move(void) for (i=0; ilcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); rb->lcd_fillrect(particles[i][0],particles[i][1], FLAKE_WIDTH,FLAKE_WIDTH); - rb->lcd_set_drawmode(DRMODE_SOLID); #else - pgfx_clearpixel(particles[i][0],particles[i][1]); + pgfx_drawpixel(particles[i][0],particles[i][1]); #endif + MYLCD(set_drawmode)(DRMODE_SOLID); #ifdef HAVE_REMOTE_LCD if (particles[i][0] <= LCD_REMOTE_WIDTH && particles[i][1] <= LCD_REMOTE_HEIGHT) { @@ -141,14 +143,12 @@ static void snow_init(void) particles[i][0]=-1; particles[i][1]=-1; } -#ifdef HAVE_LCD_BITMAP - rb->lcd_clear_display(); -#else +#ifdef HAVE_LCD_CHARCELLS pgfx_display(0, 0); /* display three times */ pgfx_display(4, 0); pgfx_display(8, 0); - pgfx_clear_display(); #endif + MYLCD(clear_display)(); #ifdef HAVE_REMOTE_LCD rb->lcd_remote_clear_display(); #endif @@ -171,11 +171,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter) snow_init(); while (1) { snow_move(); -#ifdef HAVE_LCD_BITMAP - rb->lcd_update(); -#else - pgfx_update(); -#endif + MYLCD(update)(); #ifdef HAVE_REMOTE_LCD rb->lcd_remote_update(); #endif -- cgit v1.2.3