summaryrefslogtreecommitdiffstats
path: root/apps/plugins/lib/playergfx.c
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2005-06-30 21:07:00 +0000
committerJens Arnold <amiconn@rockbox.org>2005-06-30 21:07:00 +0000
commit93867305d514b90bec2d5d7541297aef6a157efa (patch)
treee3e5ecfb84c337a227093122f7ddcf085d6c9f32 /apps/plugins/lib/playergfx.c
parent05c3cc297814543d68065389b08ef2123020b0b9 (diff)
downloadrockbox-93867305d514b90bec2d5d7541297aef6a157efa.tar.gz
rockbox-93867305d514b90bec2d5d7541297aef6a157efa.zip
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
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 @@
#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 */