1
0
Fork 0
forked from len0rd/rockbox

First part of graphics api rework. Special functions, parameter handling, pixel functions, lines and filled primitives done for black & white core, main display.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6856 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jens Arnold 2005-06-24 22:33:21 +00:00
parent 0e935bdf01
commit 04daef17a1
41 changed files with 1019 additions and 558 deletions

View file

@ -77,6 +77,7 @@
unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH];
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
@ -84,11 +85,6 @@ static int curfont = FONT_SYSFIXED;
static int xoffset; /* needed for flip */
#endif
/* All zeros and ones bitmaps for area filling */
static const unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static const unsigned char ones[8] = { 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff};
/* scrolling */
static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
static void scroll_thread(void);
@ -335,6 +331,16 @@ void lcd_update_rect(int x_start, int y, int width, int height)
/*** parameter handling ***/
void lcd_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_get_drawmode(void)
{
return drawmode;
}
void lcd_setmargins(int x, int y)
{
xmargin = x;
@ -361,32 +367,74 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
return font_getstringsize(str, w, h, curfont);
}
/*** low-level drawing functions ***/
static void setpixel(int x, int y)
{
lcd_framebuffer[y/8][x] |= 1 << (y & 7);
}
static void clearpixel(int x, int y)
{
lcd_framebuffer[y/8][x] &= ~(1 << (y & 7));
}
static void flippixel(int x, int y)
{
lcd_framebuffer[y/8][x] ^= 1 << (y & 7);
}
static void nopixel(int x, int y)
{
(void)x;
(void)y;
}
tLCDPixelFunc* pixelfunc[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);
}
tLCDBlockFunc* blockfunc[4] = {flipblock, bgblock, fgblock, solidblock};
/*** drawing functions ***/
/* Clear the whole display */
void lcd_clear_display(void)
{
memset (lcd_framebuffer, 0, sizeof lcd_framebuffer);
if (drawmode & DRMODE_INVERSEVID)
memset (lcd_framebuffer, 0xFF, sizeof lcd_framebuffer);
else
memset (lcd_framebuffer, 0, sizeof lcd_framebuffer);
scrolling_lines = 0;
}
/* Set a single pixel */
void lcd_drawpixel(int x, int y)
{
DRAW_PIXEL(x,y);
}
/* Clear a single pixel */
void lcd_clearpixel(int x, int y)
{
CLEAR_PIXEL(x,y);
}
/* Invert a single pixel */
void lcd_invertpixel(int x, int y)
{
INVERT_PIXEL(x,y);
if (((unsigned)x < LCD_WIDTH) || ((unsigned)y < LCD_HEIGHT))
pixelfunc[drawmode](x, y);
}
/* Draw a line */
void lcd_drawline(int x1, int y1, int x2, int y2)
{
int numpixels;
@ -395,20 +443,21 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
tLCDPixelFunc *pfunc = pixelfunc[drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
xinc2 = 1;
yinc2 = 1;
if(deltax >= deltay)
if (deltax >= deltay)
{
numpixels = deltax;
d = 2 * deltay - deltax;
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
}
else
{
@ -417,19 +466,17 @@ void lcd_drawline(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 */
if(x1 > x2)
if (x1 > x2)
{
xinc1 = -xinc1;
xinc2 = -xinc2;
}
if(y1 > y2)
if (y1 > y2)
{
yinc1 = -yinc1;
yinc2 = -yinc2;
@ -438,11 +485,12 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
x = x1;
y = y1;
for(i=0; i<numpixels; i++)
for (i = 0; i < numpixels; i++)
{
DRAW_PIXEL(x,y);
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
pfunc(x, y);
if(d < 0)
if (d < 0)
{
d += dinc1;
x += xinc1;
@ -457,138 +505,178 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
}
}
void lcd_clearline(int x1, int y1, int x2, int y2)
/* Draw a horizontal line (optimised) */
void lcd_hline(int x1, int x2, int y)
{
int numpixels;
int i;
int deltax, deltay;
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
int x;
unsigned char *dst;
unsigned char mask, bits;
tLCDBlockFunc *bfunc;
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
if(deltax >= deltay)
/* direction flip */
if (x2 < x1)
{
numpixels = deltax;
d = 2 * deltay - deltax;
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
x = x1;
x1 = x2;
x2 = x;
}
/* nothing to draw? */
if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_WIDTH)
x2 = LCD_WIDTH-1;
bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
dst = &lcd_framebuffer[y/8][x1];
mask = 1 << (y & 7);
for (x = x1; x <= x2; x++)
bfunc(dst++, mask, bits);
}
/* Draw a vertical line (optimised) */
void lcd_vline(int x, int y1, int y2)
{
int ny;
unsigned char *dst;
unsigned char mask_top, mask_bottom, bits;
tLCDBlockFunc *bfunc;
/* direction flip */
if (y2 < y1)
{
ny = y1;
y1 = y2;
y2 = ny;
}
/* nothing to draw? */
if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_HEIGHT)
y2 = LCD_HEIGHT-1;
bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
dst = &lcd_framebuffer[y1/8][x];
ny = y2 - (y1 & ~7);
mask_top = 0xFFu << (y1 & 7);
mask_bottom = 0xFFu >> (7 - (ny & 7));
if (ny >= 8)
{
bfunc(dst, mask_top, bits);
dst += LCD_WIDTH;
for (; ny > 15; ny -= 8)
{
bfunc(dst, 0xFFu, bits);
dst += LCD_WIDTH;
}
}
else
mask_bottom &= mask_top;
bfunc(dst, mask_bottom, bits);
}
/* Draw a rectangular box */
void lcd_drawrect(int x, int y, int width, int height)
{
if ((width <= 0) || (height <= 0))
return;
int x2 = x + width - 1;
int y2 = y + height - 1;
lcd_vline(x, y, y2);
lcd_vline(x2, y, y2);
lcd_hline(x, x2, y);
lcd_hline(x, x2, y2);
}
/* helper function for lcd_fillrect() */
static void fillrow(tLCDBlockFunc *bfunc, unsigned char *address,
int width, unsigned mask, unsigned bits)
{
int i;
for (i = 0; i < width; i++)
bfunc(address++, mask, bits);
}
/* Fill a rectangular area */
void lcd_fillrect(int x, int y, int width, int height)
{
int ny;
unsigned char *dst;
unsigned char mask_top, mask_bottom, bits;
tLCDBlockFunc *bfunc;
bool fillopt = (drawmode & DRMODE_INVERSEVID) ?
(drawmode & DRMODE_BG) : (drawmode & DRMODE_FG);
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width < 0) || (y + height < 0))
return;
/* clipping */
if (x < 0)
{
numpixels = deltay;
d = 2 * deltax - deltay;
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
width += x;
x = 0;
}
numpixels++; /* include endpoints */
if(x1 > x2)
if (y < 0)
{
xinc1 = -xinc1;
xinc2 = -xinc2;
height += y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
bfunc = blockfunc[drawmode & ~DRMODE_INVERSEVID];
bits = (drawmode & DRMODE_INVERSEVID) ? 0x00 : 0xFFu;
dst = &lcd_framebuffer[y/8][x];
ny = height - 1 + (y & 7);
mask_top = 0xFFu << (y & 7);
mask_bottom = 0xFFu >> (7 - (ny & 7));
if(y1 > y2)
if (ny >= 8)
{
yinc1 = -yinc1;
yinc2 = -yinc2;
}
x = x1;
y = y1;
for(i=0; i<numpixels; i++)
{
CLEAR_PIXEL(x,y);
if(d < 0)
{
d += dinc1;
x += xinc1;
y += yinc1;
}
if (fillopt && mask_top == 0xFF)
memset(dst, bits, width);
else
fillrow(bfunc, dst, width, mask_top, bits);
dst += LCD_WIDTH;
for (; ny > 15; ny -= 8)
{
d += dinc2;
x += xinc2;
y += yinc2;
if (fillopt)
memset(dst, bits, width);
else
fillrow(bfunc, dst, width, 0xFFu, bits);
dst += LCD_WIDTH;
}
}
}
/* Draw a rectangle with upper left corner at (x, y) and size (nx, ny) */
void lcd_drawrect(int x, int y, int nx, int ny)
{
int i;
if (x > LCD_WIDTH)
return;
if (y > LCD_HEIGHT)
return;
if (x + nx > LCD_WIDTH)
nx = LCD_WIDTH - x;
if (y + ny > LCD_HEIGHT)
ny = LCD_HEIGHT - y;
/* vertical lines */
for (i = 0; i < ny; i++) {
DRAW_PIXEL(x, (y + i));
DRAW_PIXEL((x + nx - 1), (y + i));
}
/* horizontal lines */
for (i = 0; i < nx; i++) {
DRAW_PIXEL((x + i),y);
DRAW_PIXEL((x + i),(y + ny - 1));
}
}
/* Clear a rectangular area at (x, y), size (nx, ny) */
void lcd_clearrect(int x, int y, int nx, int ny)
{
int i;
for (i = 0; i < nx; i++)
lcd_bitmap(zeros, x+i, y, 1, ny, true);
}
/* Fill a rectangular area at (x, y), size (nx, ny) */
void lcd_fillrect(int x, int y, int nx, int ny)
{
int i;
for (i = 0; i < nx; i++)
lcd_bitmap(ones, x+i, y, 1, ny, true);
}
/* Invert a rectangular area at (x, y), size (nx, ny) */
void lcd_invertrect(int x, int y, int nx, int ny)
{
int i, j;
if (x > LCD_WIDTH)
return;
if (y > LCD_HEIGHT)
return;
if (x + nx > LCD_WIDTH)
nx = LCD_WIDTH - x;
if (y + ny > LCD_HEIGHT)
ny = LCD_HEIGHT - y;
for (i = 0; i < nx; i++)
for (j = 0; j < ny; j++)
INVERT_PIXEL((x + i), (y + j));
else
mask_bottom &= mask_top;
if (fillopt && mask_bottom == 0xFF)
memset(dst, bits, width);
else
fillrow(bfunc, dst, width, mask_bottom, bits);
}
/* About Rockbox' internal bitmap format:
@ -756,6 +844,7 @@ void lcd_putsxy(int x, int y, const unsigned char *str)
void lcd_puts_style(int x, int y, const unsigned char *str, int style)
{
int xpos,ypos,w,h;
int lastmode = lcd_get_drawmode();
/* make sure scrolling is turned off on the line we are updating */
scrolling_lines &= ~(1 << y);
@ -767,9 +856,14 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
xpos = xmargin + x*w / strlen(str);
ypos = ymargin + y*h;
lcd_putsxy(xpos, ypos, str);
lcd_clearrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h);
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h);
if (style & STYLE_INVERT)
lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, h);
{
lcd_set_drawmode(DRMODE_COMPLEMENT);
lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h);
}
lcd_set_drawmode(lastmode);
}
/* put a string at a given char position */
@ -885,6 +979,7 @@ static void scroll_thread(void)
struct scrollinfo* s;
int index;
int xpos, ypos;
int lastmode;
/* initialize scroll struct array */
scrolling_lines = 0;
@ -930,10 +1025,17 @@ static void scroll_thread(void)
s->offset %= s->width;
}
lcd_clearrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
lastmode = lcd_get_drawmode();
lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
lcd_set_drawmode(DRMODE_SOLID);
lcd_putsxyofs(xpos, ypos, s->offset, s->line);
if (s->invert)
lcd_invertrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
{
lcd_set_drawmode(DRMODE_COMPLEMENT);
lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
}
lcd_set_drawmode(lastmode);
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
}