1
0
Fork 0
forked from len0rd/rockbox

Add viewport capabilities to all the LCD drivers, and adapt scrolling code. This is the firmware/ part of FS#8385 - the changes to the WPS code still need more work and will be committed at a later date. NOTE: There are no user-visible changes with this commit - just the infrastructure.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16018 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dave Chapman 2008-01-07 20:34:11 +00:00
parent 2a8f39820b
commit 945c8a221a
12 changed files with 1475 additions and 665 deletions

View file

@ -49,24 +49,30 @@ fb_data lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
static fb_data* lcd_backdrop = NULL;
static long lcd_backdrop_offset IDATA_ATTR = 0;
#if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR)
static unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG;
static unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG;
static unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS;
static unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG;
static unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG;
#else
unsigned fg_pattern IDATA_ATTR = LCD_DEFAULT_FG;
unsigned bg_pattern IDATA_ATTR = LCD_DEFAULT_BG;
unsigned lss_pattern IDATA_ATTR = LCD_DEFAULT_LS;
unsigned lse_pattern IDATA_ATTR = LCD_DEFAULT_BG;
unsigned lst_pattern IDATA_ATTR = LCD_DEFAULT_FG;
#endif
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
.fg_pattern = LCD_DEFAULT_FG,
.bg_pattern = LCD_DEFAULT_BG,
.lss_pattern = LCD_DEFAULT_BG,
.lse_pattern = LCD_DEFAULT_BG,
.lst_pattern = LCD_DEFAULT_BG,
};
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
/* The Gigabeat target build requires access to the current fg_pattern
in lcd-meg-fx.c */
#if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR)
static struct viewport* current_vp IDATA_ATTR = &default_vp;
#else
struct viewport* current_vp IDATA_ATTR = &default_vp;
#endif
/* LCD init */
void lcd_init(void)
@ -78,84 +84,115 @@ void lcd_init(void)
scroll_init();
}
/*** Viewports ***/
void lcd_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
}
void lcd_update_viewport(void)
{
lcd_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_update_viewport_rect(int x, int y, int width, int height)
{
lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/*** parameter handling ***/
void lcd_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_set_foreground(unsigned color)
{
fg_pattern = color;
current_vp->fg_pattern = color;
}
unsigned lcd_get_foreground(void)
{
return fg_pattern;
return current_vp->fg_pattern;
}
void lcd_set_background(unsigned color)
{
bg_pattern = color;
current_vp->bg_pattern = color;
}
unsigned lcd_get_background(void)
{
return bg_pattern;
return current_vp->bg_pattern;
}
void lcd_set_selector_start(unsigned color)
{
lss_pattern = color;
current_vp->lss_pattern = color;
}
void lcd_set_selector_end(unsigned color)
{
lse_pattern = color;
current_vp->lse_pattern = color;
}
void lcd_set_selector_text(unsigned color)
{
lst_pattern = color;
current_vp->lst_pattern = color;
}
void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
{
lcd_set_drawmode(mode);
fg_pattern = fg_color;
bg_pattern = bg_color;
current_vp->fg_pattern = fg_color;
current_vp->bg_pattern = bg_color;
}
void lcd_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_getwidth(void)
{
return current_vp->width;
}
int lcd_getheight(void)
{
return current_vp->height;
}
int lcd_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
void lcd_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -165,13 +202,13 @@ int lcd_getstringsize(const unsigned char *str, int *w, int *h)
static void setpixel(fb_data *address) ICODE_ATTR;
static void setpixel(fb_data *address)
{
*address = fg_pattern;
*address = current_vp->fg_pattern;
}
static void clearpixel(fb_data *address) ICODE_ATTR;
static void clearpixel(fb_data *address)
{
*address = bg_pattern;
*address = current_vp->bg_pattern;
}
static void clearimgpixel(fb_data *address) ICODE_ATTR;
@ -226,31 +263,74 @@ fb_data* lcd_get_backdrop(void)
/*** drawing functions ***/
/* Clear the whole display */
void lcd_clear_display(void)
/* Clear the current viewport */
void lcd_clear_viewport(void)
{
fb_data *dst = LCDADDR(0, 0);
fb_data *dst, *dst_end;
if (drawmode & DRMODE_INVERSEVID)
dst = LCDADDR(current_vp->x, current_vp->y);
dst_end = dst + current_vp->height * LCD_WIDTH;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
memset16(dst, fg_pattern, LCD_WIDTH*LCD_HEIGHT);
do
{
memset16(dst, current_vp->fg_pattern, current_vp->width);
dst += LCD_WIDTH;
}
while (dst < dst_end);
}
else
{
if (!lcd_backdrop)
memset16(dst, bg_pattern, LCD_WIDTH*LCD_HEIGHT);
{
do
{
memset16(dst, current_vp->bg_pattern, current_vp->width);
dst += LCD_WIDTH;
}
while (dst < dst_end);
}
else
memcpy(dst, lcd_backdrop, sizeof(lcd_framebuffer));
{
do
{
memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
current_vp->width * sizeof(fb_data));
dst += LCD_WIDTH;
}
while (dst < dst_end);
}
}
if (current_vp == &default_vp)
{
lcd_scroll_info.lines = 0;
}
else
{
lcd_scroll_stop(current_vp);
}
}
/* Clear the whole display */
void lcd_clear_display(void)
{
struct viewport* old_vp = current_vp;
current_vp = &default_vp;
lcd_clear_viewport();
current_vp = old_vp;
}
/* Set a single pixel */
void lcd_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
lcd_fastpixelfuncs[drawmode](LCDADDR(x, y));
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y));
}
/* Draw a line */
@ -262,7 +342,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode];
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -306,8 +386,8 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
pfunc(LCDADDR(x, y));
if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
pfunc(LCDADDR(x + current_vp->x, y + current_vp->y));
if (d < 0)
{
@ -331,7 +411,7 @@ void lcd_hline(int x1, int x2, int y)
unsigned bits = 0;
enum fill_opt fillopt = OPT_NONE;
fb_data *dst, *dst_end;
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode];
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
/* direction flip */
if (x2 < x1)
@ -342,23 +422,31 @@ void lcd_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
if (((unsigned)y >= (unsigned)current_vp->height) ||
(x1 >= current_vp->width) ||
(x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_WIDTH)
x2 = LCD_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
if (drawmode & DRMODE_INVERSEVID)
width = x2 - x1 + 1;
/* Adjust x1 and y to viewport */
x1 += current_vp->x;
y += current_vp->y;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (drawmode & DRMODE_BG)
if (current_vp->drawmode & DRMODE_BG)
{
if (!lcd_backdrop)
{
fillopt = OPT_SET;
bits = bg_pattern;
bits = current_vp->bg_pattern;
}
else
fillopt = OPT_COPY;
@ -366,14 +454,13 @@ void lcd_hline(int x1, int x2, int y)
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = OPT_SET;
bits = fg_pattern;
bits = current_vp->fg_pattern;
}
}
dst = LCDADDR(x1, y);
width = x2 - x1 + 1;
switch (fillopt)
{
@ -400,7 +487,7 @@ void lcd_vline(int x, int y1, int y2)
{
int y;
fb_data *dst, *dst_end;
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode];
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
/* direction flip */
if (y2 < y1)
@ -411,16 +498,18 @@ void lcd_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
if ((x >= current_vp->width) ||
(y1 >= current_vp->height) ||
(y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_HEIGHT)
y2 = LCD_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
dst = LCDADDR(x, y1);
dst = LCDADDR(x + current_vp->x, y1 + current_vp->y);
dst_end = dst + (y2 - y1) * LCD_WIDTH;
do
@ -452,11 +541,11 @@ void lcd_fillrect(int x, int y, int width, int height)
unsigned bits = 0;
enum fill_opt fillopt = OPT_NONE;
fb_data *dst, *dst_end;
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[drawmode];
lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -470,19 +559,19 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
if (drawmode & DRMODE_INVERSEVID)
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (drawmode & DRMODE_BG)
if (current_vp->drawmode & DRMODE_BG)
{
if (!lcd_backdrop)
{
fillopt = OPT_SET;
bits = bg_pattern;
bits = current_vp->bg_pattern;
}
else
fillopt = OPT_COPY;
@ -490,13 +579,13 @@ void lcd_fillrect(int x, int y, int width, int height)
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = OPT_SET;
bits = fg_pattern;
bits = current_vp->fg_pattern;
}
}
dst = LCDADDR(x, y);
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
dst_end = dst + height * LCD_WIDTH;
do
@ -530,24 +619,28 @@ void lcd_fillrect(int x, int y, int width, int height)
/* Fill a rectangle with a gradient */
void lcd_gradient_rect(int x1, int x2, int y, int h)
{
int old_pattern = current_vp->fg_pattern;
if (h == 0) return;
int h_r = RGB_UNPACK_RED(lss_pattern) << 16;
int h_b = RGB_UNPACK_BLUE(lss_pattern) << 16;
int h_g = RGB_UNPACK_GREEN(lss_pattern) << 16;
int rstep = (h_r - ((signed)RGB_UNPACK_RED(lse_pattern) << 16)) / h;
int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(lse_pattern) << 16)) / h;
int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(lse_pattern) << 16)) / h;
int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16;
int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16;
int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16;
int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h;
int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h;
int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h;
int count;
fg_pattern = lss_pattern;
current_vp->fg_pattern = current_vp->lss_pattern;
for(count = 0; count < h; count++) {
lcd_hline(x1, x2, y + count);
h_r -= rstep;
h_g -= gstep;
h_b -= bstep;
fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
}
current_vp->fg_pattern = old_pattern;
}
#define H_COLOR(lss, lse, cur_line, max_line) \
@ -562,14 +655,14 @@ void lcd_gradient_rect_scroll(int x1, int x2, int y, int h,
{
if (h == 0 || num_lines == 0) return;
unsigned tmp_lss = lss_pattern;
unsigned tmp_lse = lse_pattern;
int lss_r = (signed)RGB_UNPACK_RED(lss_pattern);
int lss_b = (signed)RGB_UNPACK_BLUE(lss_pattern);
int lss_g = (signed)RGB_UNPACK_GREEN(lss_pattern);
int lse_r = (signed)RGB_UNPACK_RED(lse_pattern);
int lse_b = (signed)RGB_UNPACK_BLUE(lse_pattern);
int lse_g = (signed)RGB_UNPACK_GREEN(lse_pattern);
unsigned tmp_lss = current_vp->lss_pattern;
unsigned tmp_lse = current_vp->lse_pattern;
int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern);
int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern);
int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern);
int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern);
int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern);
int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern);
int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines);
int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines);
@ -583,8 +676,8 @@ void lcd_gradient_rect_scroll(int x1, int x2, int y, int h,
lcd_gradient_rect(x1, x2, y, h);
lcd_set_selector_start(tmp_lss);
lcd_set_selector_end(tmp_lse);
current_vp->lss_pattern = tmp_lss;
current_vp->lse_pattern = tmp_lse;
}
/* About Rockbox' internal monochrome bitmap format:
@ -613,8 +706,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_fastpixelfunc_type *fgfunc, *bgfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -630,20 +723,20 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
dst = LCDADDR(x, y);
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
has_backdrop = (lcd_backdrop != NULL);
backdrop = lcd_backdrop + y * LCD_WIDTH + x;
fgfunc = lcd_fastpixelfuncs[drawmode];
bgfunc = lcd_fastpixelfuncs[drawmode ^ DRMODE_INVERSEVID];
backdrop = lcd_backdrop + (current_vp->y + y) * LCD_WIDTH + current_vp->x + x;
fgfunc = lcd_fastpixelfuncs[current_vp->drawmode];
bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
do
{
const unsigned char *src_col = src++;
@ -654,23 +747,23 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
dst_end = dst_col + height * LCD_WIDTH;
do
{
switch (drawmode)
switch (current_vp->drawmode)
{
case DRMODE_SOLID:
if (data & 0x01)
*dst_col = fg_pattern;
*dst_col = current_vp->fg_pattern;
else
*dst_col = has_backdrop ? *backdrop_col : bg_pattern;
*dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern;
break;
case DRMODE_FG:
if (data & 0x01)
*dst_col = fg_pattern;
*dst_col = current_vp->fg_pattern;
break;
case (DRMODE_SOLID|DRMODE_INVERSEVID):
if (data & 0x01)
*dst_col = has_backdrop ? *backdrop_col : bg_pattern;
*dst_col = has_backdrop ? *backdrop_col : current_vp->bg_pattern;
else
*dst_col = fg_pattern;
*dst_col = current_vp->fg_pattern;
break;
default:
if (data & 0x01)
@ -709,8 +802,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
fb_data *dst, *dst_end;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -726,13 +819,13 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
src += stride * src_y + src_x; /* move starting point */
dst = LCDADDR(x, y);
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
dst_end = dst + height * LCD_WIDTH;
do
@ -763,8 +856,8 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
fb_data *dst, *dst_end;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -780,13 +873,13 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
src += stride * src_y + src_x; /* move starting point */
dst = LCDADDR(x, y);
dst = LCDADDR(current_vp->x + x, current_vp->y + y);
dst_end = dst + height * LCD_WIDTH;
do
@ -795,7 +888,7 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
for(i = 0;i < width;i++)
{
if (src[i] == REPLACEWITHFG_COLOR)
dst[i] = fg_pattern;
dst[i] = current_vp->fg_pattern;
else if(src[i] != TRANSPARENT_COLOR)
dst[i] = src[i];
}
@ -818,11 +911,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -875,51 +968,51 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style,
int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int oldfgcolor = fg_pattern;
int oldbgcolor = bg_pattern;
int lastmode = current_vp->drawmode;
int oldfgcolor = current_vp->fg_pattern;
int oldbgcolor = current_vp->bg_pattern;
/* make sure scrolling is turned off on the line we are updating */
lcd_scroll_info.lines &= ~(1 << y);
lcd_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length(str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length(str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
if (style & STYLE_COLORED) {
if (drawmode == DRMODE_SOLID)
fg_pattern = style & STYLE_COLOR_MASK;
if (current_vp->drawmode == DRMODE_SOLID)
current_vp->fg_pattern = style & STYLE_COLOR_MASK;
else
bg_pattern = style & STYLE_COLOR_MASK;
current_vp->bg_pattern = style & STYLE_COLOR_MASK;
}
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
if (style & STYLE_GRADIENT) {
drawmode = DRMODE_FG;
current_vp->drawmode = DRMODE_FG;
if (CURLN_UNPACK(style) == 0)
lcd_gradient_rect(xpos, LCD_WIDTH, ypos, h*NUMLN_UNPACK(style));
fg_pattern = lst_pattern;
lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style));
current_vp->fg_pattern = current_vp->lst_pattern;
}
else if (style & STYLE_COLORBAR) {
drawmode = DRMODE_FG;
fg_pattern = lss_pattern;
lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h);
fg_pattern = lst_pattern;
current_vp->drawmode = DRMODE_FG;
current_vp->fg_pattern = current_vp->lss_pattern;
lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
current_vp->fg_pattern = current_vp->lst_pattern;
}
else {
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
drawmode = (style & STYLE_INVERT) ?
lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
}
lcd_putsxyofs(xpos, ypos, offset, str);
drawmode = lastmode;
fg_pattern = oldfgcolor;
bg_pattern = oldbgcolor;
current_vp->drawmode = lastmode;
current_vp->fg_pattern = oldfgcolor;
current_vp->bg_pattern = oldbgcolor;
}
/*** scrolling ***/
@ -938,15 +1031,23 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offse
lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
}
/* Initialise a scrolling line at (x,y) in current viewport */
void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
int style, int offset)
{
struct scrollinfo* s;
int w, h;
if(y>=LCD_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_scroll_stop_line(current_vp, y);
if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
s->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style;
@ -954,7 +1055,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
lcd_getstringsize(string, &w, &h);
if (LCD_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -967,7 +1068,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_scroll_info.bidir_limit) / 100;
}
else
@ -980,17 +1081,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
}
end = strchr(s->line, '\0');
strncpy(end, string, LCD_WIDTH/2);
strncpy(end, string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length(string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;
s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false;
lcd_scroll_info.lines |= (1<<y);
lcd_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@ -1000,28 +1100,29 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
unsigned old_fgcolor = fg_pattern;
unsigned old_bgcolor = bg_pattern;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
unsigned old_fgcolor;
unsigned old_bgcolor;
struct viewport* old_vp = current_vp;
for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_set_viewport(s->vp);
old_fgcolor = current_vp->fg_pattern;
old_bgcolor = current_vp->bg_pattern;
if (s->style&STYLE_COLORED) {
if (s->style&STYLE_MODE_MASK) {
fg_pattern = old_fgcolor;
bg_pattern = s->style&STYLE_COLOR_MASK;
current_vp->fg_pattern = old_fgcolor;
current_vp->bg_pattern = s->style&STYLE_COLOR_MASK;
}
else {
fg_pattern = s->style&STYLE_COLOR_MASK;
bg_pattern = old_bgcolor;
current_vp->fg_pattern = s->style&STYLE_COLOR_MASK;
current_vp->bg_pattern = old_bgcolor;
}
}
@ -1030,9 +1131,9 @@ void lcd_scroll_fn(void)
else
s->offset += lcd_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -1041,9 +1142,9 @@ void lcd_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
@ -1054,35 +1155,36 @@ void lcd_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
lastmode = current_vp->drawmode;
switch (s->style&STYLE_MODE_MASK) {
case STYLE_INVERT:
drawmode = DRMODE_SOLID|DRMODE_INVERSEVID;
current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID;
break;
case STYLE_COLORBAR:
/* Solid colour line selector */
drawmode = DRMODE_FG;
fg_pattern = lss_pattern;
lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
fg_pattern = lst_pattern;
current_vp->drawmode = DRMODE_FG;
current_vp->fg_pattern = current_vp->lss_pattern;
lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height);
current_vp->fg_pattern = current_vp->lst_pattern;
break;
case STYLE_GRADIENT:
/* Gradient line selector */
drawmode = DRMODE_FG;
lcd_gradient_rect_scroll(xpos, LCD_WIDTH, ypos, (signed)pf->height,
current_vp->drawmode = DRMODE_FG;
lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height,
NUMLN_UNPACK(s->style),
CURLN_UNPACK(s->style));
fg_pattern = lst_pattern;
current_vp->fg_pattern = current_vp->lst_pattern;
break;
default:
drawmode = DRMODE_SOLID;
current_vp->drawmode = DRMODE_SOLID;
break;
}
lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
current_vp->fg_pattern = old_fgcolor;
current_vp->bg_pattern = old_bgcolor;
lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
}
fg_pattern = old_fgcolor;
bg_pattern = old_bgcolor;
lcd_set_viewport(old_vp);
}

View file

@ -35,10 +35,40 @@
unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH];
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
};
static struct viewport* current_vp = &default_vp;
/*** Viewports ***/
void lcd_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
}
void lcd_update_viewport(void)
{
lcd_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_update_viewport_rect(int x, int y, int width, int height)
{
lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/* LCD init */
void lcd_init(void)
@ -53,38 +83,48 @@ void lcd_init(void)
void lcd_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
int lcd_getwidth(void)
{
return current_vp->width;
}
int lcd_getheight(void)
{
return current_vp->height;
}
void lcd_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -187,17 +227,42 @@ lcd_blockfunc_type* const lcd_blockfuncs[8] = {
/* Clear the whole display */
void lcd_clear_display(void)
{
unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
lcd_scroll_info.lines = 0;
}
void lcd_clear_viewport(void)
{
int oldmode;
if (current_vp == &default_vp)
{
lcd_clear_display();
}
else
{
oldmode = current_vp->drawmode;
/* Invert the INVERSEVID bit and set basic mode to SOLID */
current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
DRMODE_SOLID;
lcd_fillrect(0, 0, current_vp->width, current_vp->height);
current_vp->drawmode = oldmode;
lcd_scroll_stop(current_vp);
}
}
/* Set a single pixel */
void lcd_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
lcd_pixelfuncs[drawmode](x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
}
/* Draw a line */
@ -209,7 +274,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -253,8 +318,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
pfunc(x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0)
{
@ -288,16 +354,22 @@ void lcd_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
|| (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_WIDTH)
x2 = LCD_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
bfunc = lcd_blockfuncs[drawmode];
/* adjust for viewport */
y += current_vp->y;
x1 += current_vp->x;
x2 += current_vp->x;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>3][x1];
mask = 1 << (y & 7);
@ -324,16 +396,22 @@ void lcd_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
|| (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_HEIGHT)
y2 = LCD_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
bfunc = lcd_blockfuncs[drawmode];
/* adjust for viewport */
y1 += current_vp->y;
y2 += current_vp->y;
x += current_vp->x;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7);
mask = 0xFFu << (y1 & 7);
@ -375,8 +453,8 @@ void lcd_fillrect(int x, int y, int width, int height)
bool fillopt = false;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -390,27 +468,31 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
if (drawmode & DRMODE_INVERSEVID)
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (drawmode & DRMODE_BG)
if (current_vp->drawmode & DRMODE_BG)
{
fillopt = true;
}
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = true;
bits = 0xFFu;
}
}
bfunc = lcd_blockfuncs[drawmode];
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>3][x];
ny = height - 1 + (y & 7);
mask = 0xFFu << (y & 7);
@ -470,8 +552,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_blockfunc_type *bfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -487,10 +569,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
@ -499,13 +585,13 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
shift = y & 7;
ny = height - 1 + shift + src_y;
bfunc = lcd_blockfuncs[drawmode];
bfunc = lcd_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7);
if (shift == 0)
{
bool copyopt = (drawmode == DRMODE_SOLID);
bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
for (; ny >= 8; ny -= 8)
{
@ -582,11 +668,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -639,24 +725,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
int style, int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int lastmode = current_vp->drawmode;
/* make sure scrolling is turned off on the line we are updating */
lcd_scroll_info.lines &= ~(1 << y);
lcd_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length(str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length(str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
drawmode = lastmode;
lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = lastmode;
}
/*** scrolling ***/
@ -682,9 +768,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s;
int w, h;
if(y>=LCD_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_scroll_stop_line(current_vp, y);
if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
s->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style;
@ -696,7 +788,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
lcd_getstringsize(string, &w, &h);
if (LCD_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -709,7 +801,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_scroll_info.bidir_limit) / 100;
}
else
@ -722,17 +814,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
}
end = strchr(s->line, '\0');
strncpy(end, string, LCD_WIDTH/2);
strncpy(end, string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length(string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;;
s->startx = current_vp->xmargin + x * s->width / s->len;;
s->backward = false;
lcd_scroll_info.lines |= (1<<y);
lcd_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@ -742,26 +833,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_set_viewport(s->vp);
if (s->backward)
s->offset -= lcd_scroll_info.step;
else
s->offset += lcd_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -770,9 +860,9 @@ void lcd_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
@ -783,11 +873,13 @@ void lcd_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
drawmode = (s->style&STYLE_INVERT) ?
lastmode = current_vp->drawmode;
current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
}
lcd_set_viewport(old_vp);
}

View file

@ -46,52 +46,92 @@ static const unsigned char pixmask[4] ICONST_ATTR = {
static fb_data* lcd_backdrop = NULL;
static long lcd_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */
static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
.fg_pattern = LCD_DEFAULT_FG,
.bg_pattern = LCD_DEFAULT_BG
};
static struct viewport* current_vp IBSS_ATTR;
static unsigned fg_pattern IBSS_ATTR;
static unsigned bg_pattern IBSS_ATTR;
/* LCD init */
void lcd_init(void)
{
/* Initialise the viewport */
lcd_set_viewport(NULL);
lcd_clear_display();
/* Call device specific init */
lcd_init_device();
scroll_init();
}
/*** Viewports ***/
void lcd_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
}
void lcd_update_viewport(void)
{
lcd_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_update_viewport_rect(int x, int y, int width, int height)
{
lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/*** parameter handling ***/
void lcd_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_set_foreground(unsigned brightness)
{
current_vp->fg_pattern = brightness;
fg_pattern = 0x55 * (~brightness & 3);
}
unsigned lcd_get_foreground(void)
{
return ~fg_pattern & 3;
return current_vp->fg_pattern;
}
void lcd_set_background(unsigned brightness)
{
current_vp->bg_pattern = brightness;
bg_pattern = 0x55 * (~brightness & 3);
}
unsigned lcd_get_background(void)
{
return ~bg_pattern & 3;
return current_vp->bg_pattern;
}
void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
@ -103,28 +143,38 @@ void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
void lcd_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
int lcd_getwidth(void)
{
return current_vp->width;
}
int lcd_getheight(void)
{
return current_vp->height;
}
void lcd_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -345,7 +395,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
/* Clear the whole display */
void lcd_clear_display(void)
{
if (drawmode & DRMODE_INVERSEVID)
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
}
@ -360,11 +410,37 @@ void lcd_clear_display(void)
lcd_scroll_info.lines = 0;
}
/* Clear the current viewport */
void lcd_clear_viewport(void)
{
int lastmode;
if (current_vp == &default_vp)
{
lcd_clear_display();
}
else
{
lastmode = current_vp->drawmode;
/* Invert the INVERSEVID bit and set basic mode to SOLID */
current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
DRMODE_SOLID;
lcd_fillrect(0, 0, current_vp->width, current_vp->height);
current_vp->drawmode = lastmode;
lcd_scroll_stop(current_vp);
}
}
/* Set a single pixel */
void lcd_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
lcd_pixelfuncs[drawmode](x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
}
/* Draw a line */
@ -376,7 +452,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -420,8 +496,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
pfunc(x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0)
{
@ -455,16 +532,22 @@ void lcd_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
|| (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_WIDTH)
x2 = LCD_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
bfunc = lcd_blockfuncs[drawmode];
/* adjust to viewport */
x1 += current_vp->x;
x2 += current_vp->x;
y += current_vp->y;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y][x1>>2];
nx = x2 - (x1 & ~3);
mask = 0xFFu >> (2 * (x1 & 3));
@ -496,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
|| (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_HEIGHT)
y2 = LCD_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
bfunc = lcd_blockfuncs[drawmode];
/* adjust for viewport */
y1 += current_vp->y;
y2 += current_vp->y;
x += current_vp->x;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y1][x>>2];
mask = pixmask[x & 3];
@ -542,7 +631,7 @@ void lcd_fillrect(int x, int y, int width, int height)
lcd_blockfunc_type *bfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height)
|| (x + width <= 0) || (y + height <= 0))
return;
@ -557,12 +646,16 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
bfunc = lcd_blockfuncs[drawmode];
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y][x>>2];
nx = width - 1 + (x & 3);
mask = 0xFFu >> (2 * (x & 3));
@ -616,8 +709,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_pixelfunc_type* bgfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -633,17 +726,21 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
src_end = src + width;
fgfunc = lcd_pixelfuncs[drawmode];
bgfunc = lcd_pixelfuncs[drawmode ^ DRMODE_INVERSEVID];
fgfunc = lcd_pixelfuncs[current_vp->drawmode];
bgfunc = lcd_pixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
nx = x;
do
{
@ -704,8 +801,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
unsigned mask, mask_right;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -721,10 +818,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
stride = (stride + 3) >> 2; /* convert to no. of bytes */
@ -781,11 +882,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -839,24 +940,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
int style, int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int lastmode = current_vp->drawmode;
/* make sure scrolling is turned off on the line we are updating */
lcd_scroll_info.lines &= ~(1 << y);
lcd_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
drawmode = lastmode;
lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = lastmode;
}
/*** scrolling ***/
@ -881,9 +982,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s;
int w, h;
if(y>=LCD_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_scroll_stop_line(current_vp, y);
if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
s->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style;
@ -895,7 +1002,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
lcd_getstringsize(string, &w, &h);
if (LCD_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -908,7 +1015,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_scroll_info.bidir_limit) / 100;
}
else
@ -921,17 +1028,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
}
end = strchr(s->line, '\0');
strncpy(end, (char *)string, LCD_WIDTH/2);
strncpy(end, (char *)string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length((char *)string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;;
s->startx = current_vp->xmargin + x * s->width / s->len;;
s->backward = false;
lcd_scroll_info.lines |= (1<<y);
lcd_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@ -941,26 +1047,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_set_viewport(s->vp);
if (s->backward)
s->offset -= lcd_scroll_info.step;
else
s->offset += lcd_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -969,9 +1074,9 @@ void lcd_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
@ -982,11 +1087,13 @@ void lcd_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
drawmode = (s->style&STYLE_INVERT) ?
lastmode = current_vp->drawmode;
current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
}
lcd_set_viewport(old_vp);
}

View file

@ -48,52 +48,93 @@ static const unsigned char pixmask[4] ICONST_ATTR = {
static fb_data* lcd_backdrop = NULL;
static long lcd_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */
static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
.fg_pattern = LCD_DEFAULT_FG,
.bg_pattern = LCD_DEFAULT_BG
};
static struct viewport* current_vp IBSS_ATTR;
static unsigned fg_pattern IBSS_ATTR;
static unsigned bg_pattern IBSS_ATTR;
/* LCD init */
void lcd_init(void)
{
/* Initialise the viewport */
lcd_set_viewport(NULL);
lcd_clear_display();
/* Call device specific init */
lcd_init_device();
scroll_init();
}
/*** Viewports ***/
void lcd_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
}
void lcd_update_viewport(void)
{
lcd_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_update_viewport_rect(int x, int y, int width, int height)
{
lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/*** parameter handling ***/
void lcd_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_set_foreground(unsigned brightness)
{
current_vp->fg_pattern = brightness;
fg_pattern = 0x55 * (~brightness & 3);
}
unsigned lcd_get_foreground(void)
{
return ~fg_pattern & 3;
return current_vp->fg_pattern;
}
void lcd_set_background(unsigned brightness)
{
current_vp->fg_pattern = brightness;
bg_pattern = 0x55 * (~brightness & 3);
}
unsigned lcd_get_background(void)
{
return ~bg_pattern & 3;
return current_vp->bg_pattern;
}
void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
@ -105,28 +146,38 @@ void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
void lcd_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
int lcd_getwidth(void)
{
return current_vp->width;
}
int lcd_getheight(void)
{
return current_vp->height;
}
void lcd_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -347,7 +398,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
/* Clear the whole display */
void lcd_clear_display(void)
{
if (drawmode & DRMODE_INVERSEVID)
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
}
@ -362,11 +413,37 @@ void lcd_clear_display(void)
lcd_scroll_info.lines = 0;
}
/* Clear the current viewport */
void lcd_clear_viewport(void)
{
int lastmode;
if (current_vp == &default_vp)
{
lcd_clear_display();
}
else
{
lastmode = current_vp->drawmode;
/* Invert the INVERSEVID bit and set basic mode to SOLID */
current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
DRMODE_SOLID;
lcd_fillrect(0, 0, current_vp->width, current_vp->height);
current_vp->drawmode = lastmode;
lcd_scroll_stop(current_vp);
}
}
/* Set a single pixel */
void lcd_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
lcd_pixelfuncs[drawmode](x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
}
/* Draw a line */
@ -378,7 +455,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -422,8 +499,9 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
pfunc(x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0)
{
@ -444,6 +522,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
void lcd_hline(int x1, int x2, int y)
{
int x;
int width;
fb_data *dst, *dst_end;
unsigned mask;
lcd_blockfunc_type *bfunc;
@ -457,23 +536,30 @@ void lcd_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
|| (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_WIDTH)
x2 = LCD_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
bfunc = lcd_blockfuncs[drawmode];
width = x2 - x1 + 1;
/* adjust x1 and y to viewport */
x1 += current_vp->x;
y += current_vp->y;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>2][x1];
mask = pixmask[y & 3];
dst_end = dst + x2 - x1;
dst_end = dst + width;
do
bfunc(dst++, mask, 0xFFu);
while (dst <= dst_end);
while (dst < dst_end);
}
/* Draw a vertical line (optimised) */
@ -493,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
|| (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_HEIGHT)
y2 = LCD_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
bfunc = lcd_blockfuncs[drawmode];
/* adjust for viewport */
y1 += current_vp->y;
y2 += current_vp->y;
x += current_vp->x;
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y1>>2][x];
ny = y2 - (y1 & ~3);
mask = 0xFFu << (2 * (y1 & 3));
@ -544,8 +636,8 @@ void lcd_fillrect(int x, int y, int width, int height)
bool fillopt = false;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -559,14 +651,18 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
if (drawmode & DRMODE_INVERSEVID)
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if ((drawmode & DRMODE_BG) && !lcd_backdrop)
if ((current_vp->drawmode & DRMODE_BG) && !lcd_backdrop)
{
fillopt = true;
bits = bg_pattern;
@ -574,13 +670,13 @@ void lcd_fillrect(int x, int y, int width, int height)
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = true;
bits = fg_pattern;
}
}
bfunc = lcd_blockfuncs[drawmode];
bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>2][x];
ny = height - 1 + (y & 3);
mask = 0xFFu << (2 * (y & 3));
@ -640,8 +736,8 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_blockfunc_type *bfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -657,10 +753,14 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
@ -669,7 +769,7 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
shift = y & 3;
ny = height - 1 + shift + src_y;
bfunc = lcd_blockfuncs[drawmode];
bfunc = lcd_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7);
@ -807,8 +907,8 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
unsigned mask, mask_bottom;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
|| (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -824,10 +924,14 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_WIDTH)
width = LCD_WIDTH - x;
if (y + height > LCD_HEIGHT)
height = LCD_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 2) + src_x; /* move starting point */
src_y &= 3;
@ -916,11 +1020,11 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -974,24 +1078,24 @@ void lcd_puts_style_offset(int x, int y, const unsigned char *str,
int style, int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int lastmode = current_vp->drawmode;
/* make sure scrolling is turned off on the line we are updating */
lcd_scroll_info.lines &= ~(1 << y);
lcd_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
drawmode = lastmode;
lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = lastmode;
}
/*** scrolling ***/
@ -1017,9 +1121,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s;
int w, h;
if(y>=LCD_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_scroll_stop_line(current_vp, y);
if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
s->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style;
@ -1031,7 +1141,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
lcd_getstringsize(string, &w, &h);
if (LCD_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -1044,7 +1154,7 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_scroll_info.bidir_limit) / 100;
}
else
@ -1057,17 +1167,17 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
}
end = strchr(s->line, '\0');
strncpy(end, (char *)string, LCD_WIDTH/2);
strncpy(end, (char *)string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length((char *)string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;
s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false;
lcd_scroll_info.lines |= (1<<y);
lcd_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@ -1077,26 +1187,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_set_viewport(s->vp);
if (s->backward)
s->offset -= lcd_scroll_info.step;
else
s->offset += lcd_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -1105,9 +1214,9 @@ void lcd_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
@ -1118,11 +1227,14 @@ void lcd_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
drawmode = (s->style&STYLE_INVERT) ?
lastmode = current_vp->drawmode;
current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
lcd_update_viewport_rect(xpos, ypos,
current_vp->width - xpos, pf->height);
}
lcd_set_viewport(old_vp);
}

View file

@ -52,8 +52,17 @@ static unsigned char xfont_variable[VARIABLE_XCHARS][HW_PATTERN_SIZE];
static bool xfont_variable_locked[VARIABLE_XCHARS];
static int xspace; /* stores xhcar id of ' ' - often needed */
static int xmargin = 0;
static int ymargin = 0;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.xmargin = 0,
.ymargin = 0,
};
static struct viewport* current_vp = &default_vp;
/* LCD init */
void lcd_init (void)
@ -66,22 +75,47 @@ void lcd_init (void)
scroll_init();
}
/* Viewports */
void lcd_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
}
void lcd_update_viewport(void)
{
lcd_update();
}
/** parameter handling **/
void lcd_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
int lcd_getwidth(void)
{
return current_vp->width;
}
int lcd_getheight(void)
{
return current_vp->height;
}
int lcd_getstringsize(const unsigned char *str, int *w, int *h)
@ -225,7 +259,13 @@ static int map_xchar(int xchar, unsigned char *substitute)
static void lcd_putxchar(int x, int y, int xchar)
{
int lcd_char = lcd_charbuffer[y][x];
int lcd_char;
/* Adjust for viewport */
x += current_vp->x;
y += current_vp->y;
lcd_char = lcd_charbuffer[y][x];
if (lcd_char < lcd_pattern_count) /* old char was soft */
lcd_patterns[lcd_char].count--; /* decrease old reference count */
@ -283,19 +323,55 @@ void lcd_define_pattern(unsigned long ucs, const char *pattern)
void lcd_clear_display(void)
{
int x, y;
struct viewport* old_vp = current_vp;
lcd_stop_scroll();
lcd_scroll_info.lines = 0;
lcd_remove_cursor();
/* Set the default viewport - required for lcd_putxchar */
current_vp = &default_vp;
for (x = 0; x < LCD_WIDTH; x++)
for (y = 0; y < LCD_HEIGHT; y++)
lcd_putxchar(x, y, xspace);
current_vp = old_vp;
}
/* Clear the current viewport */
void lcd_clear_viewport(void)
{
int x, y;
if (current_vp == &default_vp)
{
lcd_clear_display();
}
else
{
/* Remove the cursor if it is within the current viewport */
if (lcd_cursor.enabled &&
(lcd_cursor.x >= current_vp->x) &&
(lcd_cursor.x <= current_vp->x + current_vp->width) &&
(lcd_cursor.y >= current_vp->y) &&
(lcd_cursor.y <= current_vp->y + current_vp->height))
{
lcd_remove_cursor();
}
for (x = 0; x < current_vp->width; x++)
for (y = 0; y < current_vp->height; y++)
lcd_putxchar(x, y, xspace);
lcd_scroll_stop(current_vp);
}
}
/* Put an unicode character at the given position */
void lcd_putc(int x, int y, unsigned long ucs)
{
if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT)
if ((unsigned)x >= (unsigned)current_vp->width ||
(unsigned)y >= (unsigned)current_vp->height)
return;
lcd_putxchar(x, y, find_xchar(ucs));
@ -304,15 +380,16 @@ void lcd_putc(int x, int y, unsigned long ucs)
/* Show cursor (alternating with existing character) at the given position */
void lcd_put_cursor(int x, int y, unsigned long cursor_ucs)
{
if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT
|| lcd_cursor.enabled)
if ((unsigned)x >= (unsigned)current_vp->width ||
(unsigned)y >= (unsigned)current_vp->height ||
lcd_cursor.enabled)
return;
lcd_cursor.enabled = true;
lcd_cursor.visible = false;
lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char);
lcd_cursor.x = x;
lcd_cursor.y = y;
lcd_cursor.x = current_vp->x + x;
lcd_cursor.y = current_vp->y + y;
lcd_cursor.downcount = 0;
lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1);
}
@ -335,7 +412,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
unsigned short ucs;
const unsigned char *utf8 = str;
while (*utf8 && x < LCD_WIDTH)
while (*utf8 && x < current_vp->width)
{
utf8 = utf8decode(utf8, &ucs);
@ -352,7 +429,7 @@ static int lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
/* Put a string at a given position */
void lcd_putsxy(int x, int y, const unsigned char *str)
{
if ((unsigned)y >= LCD_HEIGHT)
if ((unsigned)y >= (unsigned)current_vp->height)
return;
lcd_putsxyofs(x, y, 0, str);
@ -369,17 +446,14 @@ void lcd_puts(int x, int y, const unsigned char *str)
/* Put a string at a given char position, skipping first offset chars */
void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
{
x += xmargin;
y += ymargin;
if ((unsigned)y >= LCD_HEIGHT)
if ((unsigned)y >= (unsigned)current_vp->height)
return;
/* make sure scrolling is turned off on the line we are updating */
lcd_scroll_info.lines &= ~(1 << y);
lcd_scroll_stop_line(current_vp, y);
x = lcd_putsxyofs(x, y, offset, str);
while (x < LCD_WIDTH)
while (x < current_vp->width)
lcd_putxchar(x++, y, xspace);
}
@ -395,16 +469,22 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s;
int len;
if(y>=LCD_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_scroll_stop_line(current_vp, y);
if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
s->start_tick = current_tick + lcd_scroll_info.delay;
lcd_puts_offset(x, y, string, offset);
len = utf8length(string);
if (LCD_WIDTH - x - xmargin < len)
if (current_vp->width - x - current_vp->xmargin < len)
{
/* prepare scroll line */
char *end;
@ -418,7 +498,7 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
/* scroll bidirectional or forward only depending on the string width */
if (lcd_scroll_info.bidir_limit)
{
s->bidir = s->len < (LCD_WIDTH - xmargin) *
s->bidir = s->len < (current_vp->width - current_vp->xmargin) *
(100 + lcd_scroll_info.bidir_limit) / 100;
}
else
@ -432,16 +512,15 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
}
end = strchr(s->line, '\0');
strncpy(end, string, utf8seek(s->line, LCD_WIDTH));
strncpy(end, string, utf8seek(s->line, current_vp->width));
s->vp = current_vp;
s->y = y;
s->offset = offset;
s->startx = xmargin + x;
s->startx = current_vp->xmargin + x;
s->backward = false;
lcd_scroll_info.lines |= (1<<y);
lcd_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_scroll_info.lines &= ~(1<<y);
}
void lcd_scroll_fn(void)
@ -450,27 +529,25 @@ void lcd_scroll_fn(void)
int index;
int xpos, ypos;
bool update;
struct viewport* old_vp = current_vp;
update = false;
for (index = 0; index < LCD_SCROLLABLE_LINES; index++)
{
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
s = &lcd_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_set_viewport(s->vp);
if (s->backward)
s->offset--;
else
s->offset++;
xpos = s->startx;
ypos = ymargin + index;
ypos = current_vp->ymargin + s->y;
if (s->bidir) /* scroll bidirectional */
{
@ -480,9 +557,9 @@ void lcd_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
if (s->offset >= s->len - (LCD_WIDTH - xpos)) {
if (s->offset >= s->len - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->len - (LCD_WIDTH - xpos);
s->offset = s->len - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2;
}
@ -497,6 +574,8 @@ void lcd_scroll_fn(void)
update = true;
}
lcd_set_viewport(old_vp);
if (lcd_cursor.enabled)
{
if (--lcd_cursor.downcount <= 0)

View file

@ -38,47 +38,88 @@
fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]
IBSS_ATTR;
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_REMOTE_WIDTH,
.height = LCD_REMOTE_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
};
static struct viewport* current_vp IDATA_ATTR = &default_vp;
/*** Viewports ***/
void lcd_remote_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
}
void lcd_remote_update_viewport(void)
{
lcd_remote_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_remote_update_viewport_rect(int x, int y, int width, int height)
{
lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/*** parameter handling ***/
void lcd_remote_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_remote_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_remote_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_remote_getwidth(void)
{
return current_vp->width;
}
int lcd_remote_getheight(void)
{
return current_vp->height;
}
int lcd_remote_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_remote_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
void lcd_remote_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -181,17 +222,44 @@ lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
/* Clear the whole display */
void lcd_remote_clear_display(void)
{
unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
lcd_remote_scroll_info.lines = 0;
}
/* Clear the current viewport */
void lcd_remote_clear_viewport(void)
{
int oldmode;
if (current_vp == &default_vp)
{
lcd_remote_clear_display();
}
else
{
oldmode = current_vp->drawmode;
/* Invert the INVERSEVID bit and set basic mode to SOLID */
current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
DRMODE_SOLID;
lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height);
current_vp->drawmode = oldmode;
lcd_remote_scroll_stop(current_vp);
}
}
/* Set a single pixel */
void lcd_remote_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
lcd_remote_pixelfuncs[drawmode](x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
}
/* Draw a line */
@ -203,7 +271,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode];
lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -247,8 +315,8 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
pfunc(x, y);
if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
pfunc(x + current_vp->x, y + current_vp->y);
if (d < 0)
{
@ -268,7 +336,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
/* Draw a horizontal line (optimised) */
void lcd_remote_hline(int x1, int x2, int y)
{
int x;
int x, width;
fb_remote_data *dst, *dst_end;
unsigned mask;
lcd_remote_blockfunc_type *bfunc;
@ -282,24 +350,30 @@ void lcd_remote_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH)
if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
|| (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_REMOTE_WIDTH)
x2 = LCD_REMOTE_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
bfunc = lcd_remote_blockfuncs[drawmode];
width = x2 - x1 + 1;
/* Adjust x1 and y to viewport */
x1 += current_vp->x;
y += current_vp->y;
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x1];
mask = 1 << (y & 7);
dst_end = dst + x2 - x1;
dst_end = dst + width;
do
bfunc(dst++, mask, 0xFFu);
while (dst <= dst_end);
while (dst < dst_end);
}
/* Draw a vertical line (optimised) */
@ -319,17 +393,22 @@ void lcd_remote_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT)
if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
|| (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_REMOTE_HEIGHT)
y2 = LCD_REMOTE_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
bfunc = lcd_remote_blockfuncs[drawmode];
/* adjust for viewport */
y1 += current_vp->y;
y2 += current_vp->y;
x += current_vp->x;
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7);
mask = 0xFFu << (y1 & 7);
@ -371,8 +450,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
bool fillopt = false;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -386,27 +465,32 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_REMOTE_WIDTH)
width = LCD_REMOTE_WIDTH - x;
if (y + height > LCD_REMOTE_HEIGHT)
height = LCD_REMOTE_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
if (drawmode & DRMODE_INVERSEVID)
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if (drawmode & DRMODE_BG)
if (current_vp->drawmode & DRMODE_BG)
{
fillopt = true;
}
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = true;
bits = 0xFFu;
}
}
bfunc = lcd_remote_blockfuncs[drawmode];
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x];
ny = height - 1 + (y & 7);
mask = 0xFFu << (y & 7);
@ -466,8 +550,8 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_remote_blockfunc_type *bfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -483,10 +567,14 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_REMOTE_WIDTH)
width = LCD_REMOTE_WIDTH - x;
if (y + height > LCD_REMOTE_HEIGHT)
height = LCD_REMOTE_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewports */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
@ -495,13 +583,13 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
shift = y & 7;
ny = height - 1 + shift + src_y;
bfunc = lcd_remote_blockfuncs[drawmode];
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7);
if (shift == 0)
{
bool copyopt = (drawmode == DRMODE_SOLID);
bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
for (; ny >= 8; ny -= 8)
{
@ -579,11 +667,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -637,24 +725,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
int style, int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int lastmode = current_vp->drawmode;
/* make sure scrolling is turned off on the line we are updating */
lcd_remote_scroll_info.lines &= ~(1 << y);
lcd_remote_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_remote_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h);
drawmode = lastmode;
lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = lastmode;
}
/*** scrolling ***/
@ -680,9 +768,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
struct scrollinfo* s;
int w, h;
if(y>=LCD_REMOTE_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_remote_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_remote_scroll_stop_line(current_vp, y);
if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return;
s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines];
s->start_tick = current_tick + lcd_remote_scroll_info.delay;
s->style = style;
@ -694,7 +788,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
lcd_remote_getstringsize(string, &w, &h);
if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -707,7 +801,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_remote_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_remote_scroll_info.bidir_limit) / 100;
}
else
@ -720,17 +814,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
}
end = strchr(s->line, '\0');
strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
strncpy(end, (char *)string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length((char *)string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;;
s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false;
lcd_remote_scroll_info.lines |= (1<<y);
lcd_remote_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_remote_scroll_info.lines &= ~(1<<y);
}
void lcd_remote_scroll_fn(void)
@ -740,26 +834,25 @@ void lcd_remote_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
s = &lcd_remote_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_remote_set_viewport(s->vp);
if (s->backward)
s->offset -= lcd_remote_scroll_info.step;
else
s->offset += lcd_remote_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -768,9 +861,9 @@ void lcd_remote_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
}
if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_REMOTE_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
}
@ -781,13 +874,16 @@ void lcd_remote_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
drawmode = (s->style&STYLE_INVERT) ?
lastmode = current_vp->drawmode;
current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
lcd_remote_update_viewport_rect(xpos, ypos,
current_vp->width - xpos, pf->height);
}
lcd_remote_set_viewport(old_vp);
}
/* LCD init */

View file

@ -46,12 +46,48 @@ static const fb_remote_data patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
static fb_remote_data* remote_backdrop = NULL;
static long remote_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFFFF; /* initially black */
static unsigned bg_pattern IDATA_ATTR = 0x0000; /* initially white */
static int drawmode = DRMODE_SOLID;
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
static struct viewport default_vp =
{
.x = 0,
.y = 0,
.width = LCD_REMOTE_WIDTH,
.height = LCD_REMOTE_HEIGHT,
.font = FONT_SYSFIXED,
.drawmode = DRMODE_SOLID,
.xmargin = 0,
.ymargin = 0,
.fg_pattern = LCD_REMOTE_DEFAULT_FG,
.bg_pattern = LCD_REMOTE_DEFAULT_BG
};
static unsigned fg_pattern IBSS_ATTR;
static unsigned bg_pattern IBSS_ATTR;
static struct viewport* current_vp IBSS_ATTR;;
/*** Viewports ***/
void lcd_remote_set_viewport(struct viewport* vp)
{
if (vp == NULL)
current_vp = &default_vp;
else
current_vp = vp;
fg_pattern = patterns[current_vp->fg_pattern & 3];
bg_pattern = patterns[current_vp->bg_pattern & 3];
}
void lcd_remote_update_viewport(void)
{
lcd_remote_update_rect(current_vp->x, current_vp->y,
current_vp->width, current_vp->height);
}
void lcd_remote_update_viewport_rect(int x, int y, int width, int height)
{
lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height);
}
/*** parameter handling ***/
unsigned lcd_remote_color_to_native(unsigned color)
@ -69,32 +105,34 @@ unsigned lcd_remote_color_to_native(unsigned color)
void lcd_remote_set_drawmode(int mode)
{
drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
}
int lcd_remote_get_drawmode(void)
{
return drawmode;
return current_vp->drawmode;
}
void lcd_remote_set_foreground(unsigned brightness)
{
current_vp->fg_pattern = brightness;
fg_pattern = patterns[brightness & 3];
}
unsigned lcd_remote_get_foreground(void)
{
return (~fg_pattern >> 7) & 3;
return current_vp->fg_pattern;
}
void lcd_remote_set_background(unsigned brightness)
{
current_vp->bg_pattern = brightness;
bg_pattern = patterns[brightness & 3];
}
unsigned lcd_remote_get_background(void)
{
return (~bg_pattern >> 7) & 3;
return current_vp->bg_pattern;
}
void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness,
@ -105,30 +143,40 @@ void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness,
lcd_remote_set_background(bg_brightness);
}
int lcd_remote_getwidth(void)
{
return current_vp->width;
}
int lcd_remote_getheight(void)
{
return current_vp->height;
}
void lcd_remote_setmargins(int x, int y)
{
xmargin = x;
ymargin = y;
current_vp->xmargin = x;
current_vp->ymargin = y;
}
int lcd_remote_getxmargin(void)
{
return xmargin;
return current_vp->xmargin;
}
int lcd_remote_getymargin(void)
{
return ymargin;
return current_vp->ymargin;
}
void lcd_remote_setfont(int newfont)
{
curfont = newfont;
current_vp->font = newfont;
}
int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
{
return font_getstringsize(str, w, h, curfont);
return font_getstringsize(str, w, h, current_vp->font);
}
/*** low-level drawing functions ***/
@ -351,9 +399,9 @@ static inline void setblock(fb_remote_data *address, unsigned mask, unsigned bit
/* Clear the whole display */
void lcd_remote_clear_display(void)
{
if (drawmode & DRMODE_INVERSEVID)
if (default_vp.drawmode & DRMODE_INVERSEVID)
{
memset(lcd_remote_framebuffer, fg_pattern,
memset(lcd_remote_framebuffer, patterns[default_vp.fg_pattern & 3],
sizeof lcd_remote_framebuffer);
}
else
@ -362,18 +410,44 @@ void lcd_remote_clear_display(void)
memcpy(lcd_remote_framebuffer, remote_backdrop,
sizeof lcd_remote_framebuffer);
else
memset(lcd_remote_framebuffer, bg_pattern,
memset(lcd_remote_framebuffer, patterns[default_vp.bg_pattern & 3],
sizeof lcd_remote_framebuffer);
}
lcd_remote_scroll_info.lines = 0;
}
/* Clear the current viewport */
void lcd_remote_clear_viewport(void)
{
int lastmode;
if (current_vp == &default_vp)
{
lcd_remote_clear_display();
}
else
{
lastmode = current_vp->drawmode;
/* Invert the INVERSEVID bit and set basic mode to SOLID */
current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
DRMODE_SOLID;
lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height);
current_vp->drawmode = lastmode;
lcd_remote_scroll_stop(current_vp);
}
}
/* Set a single pixel */
void lcd_remote_drawpixel(int x, int y)
{
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
lcd_remote_pixelfuncs[drawmode](x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
}
/* Draw a line */
@ -385,7 +459,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode];
lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
@ -429,8 +503,9 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
for (i = 0; i < numpixels; i++)
{
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
pfunc(x, y);
if (((unsigned)x < (unsigned)current_vp->width) &&
((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0)
{
@ -451,6 +526,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
void lcd_remote_hline(int x1, int x2, int y)
{
int x;
int width;
fb_remote_data *dst, *dst_end;
unsigned mask;
lcd_remote_blockfunc_type *bfunc;
@ -464,24 +540,30 @@ void lcd_remote_hline(int x1, int x2, int y)
}
/* nothing to draw? */
if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH)
if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
|| (x2 < 0))
return;
/* clipping */
if (x1 < 0)
x1 = 0;
if (x2 >= LCD_REMOTE_WIDTH)
x2 = LCD_REMOTE_WIDTH-1;
if (x2 >= current_vp->width)
x2 = current_vp->width-1;
bfunc = lcd_remote_blockfuncs[drawmode];
width = x2 - x1 + 1;
/* adjust x1 and y to viewport */
x1 += current_vp->x;
y += current_vp->y;
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x1];
mask = 0x0101 << (y & 7);
dst_end = dst + x2 - x1;
dst_end = dst + width;
do
bfunc(dst++, mask, 0xFFFFu);
while (dst <= dst_end);
while (dst < dst_end);
}
/* Draw a vertical line (optimised) */
@ -501,17 +583,22 @@ void lcd_remote_vline(int x, int y1, int y2)
}
/* nothing to draw? */
if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT)
if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
|| (y2 < 0))
return;
/* clipping */
if (y1 < 0)
y1 = 0;
if (y2 >= LCD_REMOTE_HEIGHT)
y2 = LCD_REMOTE_HEIGHT-1;
if (y2 >= current_vp->height)
y2 = current_vp->height-1;
bfunc = lcd_remote_blockfuncs[drawmode];
/* adjust for viewport */
y1 += current_vp->y;
y2 += current_vp->y;
x += current_vp->x;
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7);
mask = (0xFFu << (y1 & 7)) & 0xFFu;
@ -555,8 +642,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
bool fillopt = false;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -570,14 +657,18 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
height += y;
y = 0;
}
if (x + width > LCD_REMOTE_WIDTH)
width = LCD_REMOTE_WIDTH - x;
if (y + height > LCD_REMOTE_HEIGHT)
height = LCD_REMOTE_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
if (drawmode & DRMODE_INVERSEVID)
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
if (current_vp->drawmode & DRMODE_INVERSEVID)
{
if ((drawmode & DRMODE_BG) && !remote_backdrop)
if ((current_vp->drawmode & DRMODE_BG) && !remote_backdrop)
{
fillopt = true;
bits = bg_pattern;
@ -585,13 +676,13 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
}
else
{
if (drawmode & DRMODE_FG)
if (current_vp->drawmode & DRMODE_FG)
{
fillopt = true;
bits = fg_pattern;
}
}
bfunc = lcd_remote_blockfuncs[drawmode];
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x];
ny = height - 1 + (y & 7);
mask = (0xFFu << (y & 7)) & 0xFFu;
@ -653,8 +744,8 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
lcd_remote_blockfunc_type *bfunc;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
(y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -670,10 +761,14 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_REMOTE_WIDTH)
width = LCD_REMOTE_WIDTH - x;
if (y + height > LCD_REMOTE_HEIGHT)
height = LCD_REMOTE_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
@ -682,7 +777,7 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
shift = y & 7;
ny = height - 1 + shift + src_y;
bfunc = lcd_remote_blockfuncs[drawmode];
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y);
/* not byte-doubled here because shift+src_y can be > 7 */
mask_bottom = 0xFFu >> (~ny & 7);
@ -793,8 +888,8 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y,
unsigned mask, mask_bottom;
/* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return;
/* clipping */
@ -810,10 +905,14 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y,
src_y -= y;
y = 0;
}
if (x + width > LCD_REMOTE_WIDTH)
width = LCD_REMOTE_WIDTH - x;
if (y + height > LCD_REMOTE_HEIGHT)
height = LCD_REMOTE_HEIGHT - y;
if (x + width > current_vp->width)
width = current_vp->width - x;
if (y + height > current_vp->height)
height = current_vp->height - y;
/* adjust for viewport */
x += current_vp->x;
y += current_vp->y;
src += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7;
@ -917,11 +1016,11 @@ void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
{
unsigned short ch;
unsigned short *ucs;
struct font* pf = font_get(curfont);
struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
while ((ch = *ucs++) != 0 && x < current_vp->width)
{
int width;
const unsigned char *bits;
@ -975,24 +1074,24 @@ void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
int style, int offset)
{
int xpos,ypos,w,h,xrect;
int lastmode = drawmode;
int lastmode = current_vp->drawmode;
/* make sure scrolling is turned off on the line we are updating */
lcd_remote_scroll_info.lines &= ~(1 << y);
lcd_remote_scroll_stop_line(current_vp, y);
if(!str || !str[0])
return;
lcd_remote_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h;
drawmode = (style & STYLE_INVERT) ?
xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = current_vp->ymargin + y*h;
current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID;
current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0);
lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h);
drawmode = lastmode;
lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
current_vp->drawmode = lastmode;
}
/*** scrolling ***/
@ -1017,9 +1116,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
struct scrollinfo* s;
int w, h;
if(y>=LCD_REMOTE_SCROLLABLE_LINES) return;
if ((unsigned)y >= (unsigned)current_vp->height)
return;
s = &lcd_remote_scroll_info.scroll[y];
/* remove any previously scrolling line at the same location */
lcd_remote_scroll_stop_line(current_vp, y);
if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return;
s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines];
s->start_tick = current_tick + lcd_remote_scroll_info.delay;
s->style = style;
@ -1031,7 +1136,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
lcd_remote_getstringsize(string, &w, &h);
if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) {
if (current_vp->width - x * 8 - current_vp->xmargin < w) {
/* prepare scroll line */
char *end;
@ -1044,7 +1149,7 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
/* scroll bidirectional or forward only depending on the string
width */
if ( lcd_remote_scroll_info.bidir_limit ) {
s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) *
s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
(100 + lcd_remote_scroll_info.bidir_limit) / 100;
}
else
@ -1057,17 +1162,17 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
}
end = strchr(s->line, '\0');
strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
strncpy(end, (char *)string, current_vp->width/2);
s->vp = current_vp;
s->y = y;
s->len = utf8length((char *)string);
s->offset = offset;
s->startx = xmargin + x * s->width / s->len;;
s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false;
lcd_remote_scroll_info.lines |= (1<<y);
lcd_remote_scroll_info.lines++;
}
else
/* force a bit switch-off since it doesn't scroll */
lcd_remote_scroll_info.lines &= ~(1<<y);
}
void lcd_remote_scroll_fn(void)
@ -1077,26 +1182,25 @@ void lcd_remote_scroll_fn(void)
int index;
int xpos, ypos;
int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) {
/* really scroll? */
if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
continue;
for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
s = &lcd_remote_scroll_info.scroll[index];
/* check pause */
if (TIME_BEFORE(current_tick, s->start_tick))
continue;
lcd_remote_set_viewport(s->vp);
if (s->backward)
s->offset -= lcd_remote_scroll_info.step;
else
s->offset += lcd_remote_scroll_info.step;
pf = font_get(curfont);
pf = font_get(current_vp->font);
xpos = s->startx;
ypos = ymargin + index * pf->height;
ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) {
@ -1105,9 +1209,9 @@ void lcd_remote_scroll_fn(void)
s->backward = false;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
}
if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) {
if (s->offset >= s->width - (current_vp->width - xpos)) {
/* at end of line */
s->offset = s->width - (LCD_REMOTE_WIDTH - xpos);
s->offset = s->width - (current_vp->width - xpos);
s->backward = true;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
}
@ -1118,18 +1222,24 @@ void lcd_remote_scroll_fn(void)
s->offset %= s->width;
}
lastmode = drawmode;
drawmode = (s->style&STYLE_INVERT) ?
lastmode = current_vp->drawmode;
current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode;
lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height);
current_vp->drawmode = lastmode;
lcd_remote_update_viewport_rect(xpos, ypos,
current_vp->width - xpos, pf->height);
}
lcd_remote_set_viewport(old_vp);
}
/* LCD init */
void lcd_remote_init(void)
{
/* Initialise the viewport */
lcd_remote_set_viewport(NULL);
#ifndef SIMULATOR
/* Call device specific init */
lcd_remote_init_device();

View file

@ -24,6 +24,7 @@
#include "cpu.h"
#include "config.h"
#include "adc.h"
#include "lcd.h"
#ifdef HAVE_REMOTE_LCD
@ -109,7 +110,9 @@ extern void lcd_remote_init(void);
extern int lcd_remote_default_contrast(void);
extern void lcd_remote_set_contrast(int val);
extern void lcd_remote_set_viewport(struct viewport* vp);
extern void lcd_remote_clear_display(void);
extern void lcd_remote_clear_viewport(void);
extern void lcd_remote_puts(int x, int y, const unsigned char *str);
extern void lcd_remote_puts_style(int x, int y, const unsigned char *str,
int style);
@ -132,6 +135,8 @@ extern void lcd_remote_puts_scroll_style_offset(int x, int y,
extern void lcd_remote_update(void);
extern void lcd_remote_update_rect(int x, int y, int width, int height);
extern void lcd_remote_update_viewport(void);
extern void lcd_remote_update_viewport_rect(int x, int y, int width, int height);
extern void lcd_remote_set_invert_display(bool yesno);
extern void lcd_remote_set_flip(bool yesno);
@ -141,6 +146,8 @@ extern int lcd_remote_get_drawmode(void);
extern void lcd_remote_setmargins(int xmargin, int ymargin);
extern int lcd_remote_getxmargin(void);
extern int lcd_remote_getymargin(void);
extern int lcd_remote_getwidth(void);
extern int lcd_remote_getheight(void);
extern void lcd_remote_setfont(int font);
extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h);

View file

@ -24,6 +24,28 @@
#include "cpu.h"
#include "config.h"
struct viewport {
int x;
int y;
int width;
int height;
#ifdef HAVE_LCD_BITMAP
int font;
int drawmode;
#endif
int xmargin; /* During the transition only - to be removed */
int ymargin; /* During the transition only - to be removed */
#if LCD_DEPTH > 1
unsigned fg_pattern;
unsigned bg_pattern;
#ifdef HAVE_LCD_COLOR
unsigned lss_pattern;
unsigned lse_pattern;
unsigned lst_pattern;
#endif
#endif
};
#define STYLE_DEFAULT 0x00000000
#define STYLE_COLORED 0x10000000
#define STYLE_INVERT 0x20000000
@ -76,9 +98,14 @@ extern void lcd_set_contrast(int val);
extern void lcd_setmargins(int xmargin, int ymargin);
extern int lcd_getxmargin(void);
extern int lcd_getymargin(void);
extern int lcd_getwidth(void);
extern int lcd_getheight(void);
extern int lcd_getstringsize(const unsigned char *str, int *w, int *h);
extern void lcd_set_viewport(struct viewport* vp);
extern void lcd_update(void);
extern void lcd_update_viewport(void);
extern void lcd_clear_viewport(void);
extern void lcd_clear_display(void);
extern void lcd_putsxy(int x, int y, const unsigned char *string);
extern void lcd_puts(int x, int y, const unsigned char *string);
@ -119,6 +146,7 @@ extern void lcd_blit(const fb_data* data, int x, int by, int width,
/* update a fraction of the screen */
extern void lcd_update_rect(int x, int y, int width, int height);
extern void lcd_update_viewport_rect(int x, int y, int width, int height);
#ifdef HAVE_REMOTE_LCD
extern void lcd_remote_update(void);

View file

@ -23,9 +23,17 @@
#ifndef __SCROLL_ENGINE_H__
#define __SCROLL_ENGINE_H__
#include <lcd.h>
void scroll_init(void);
void lcd_scroll_stop(struct viewport* vp);
void lcd_scroll_stop_line(struct viewport* vp, int y);
void lcd_scroll_fn(void);
#ifdef HAVE_REMOTE_LCD
void lcd_remote_scroll_fn(void);
void lcd_remote_scroll_stop(struct viewport* vp);
void lcd_remote_scroll_stop_line(struct viewport* vp, int y);
#endif
/* internal usage, but in multiple drivers */
#define SCROLL_SPACING 3
@ -37,8 +45,10 @@ void lcd_remote_scroll_fn(void);
struct scrollinfo
{
struct viewport* vp;
char line[SCROLL_LINE_SIZE];
int len; /* length of line in chars */
int y; /* Position of the line on the screen (char co-ordinates) */
int offset;
int startx;
#ifdef HAVE_LCD_BITMAP
@ -54,7 +64,7 @@ struct scroll_screen_info
{
struct scrollinfo * const scroll;
const int num_scroll; /* number of scrollable lines (also number of scroll structs) */
int lines; /* Bitpattern of which lines are scrolling */
int lines; /* Number of currently scrolling lines */
long ticks; /* # of ticks between updates*/
long delay; /* ticks delay before start */
int bidir_limit; /* percent */
@ -74,7 +84,7 @@ struct scroll_screen_info
#ifdef HAVE_LCD_BITMAP
#define LCD_SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32)
#else
#define LCD_SCROLLABLE_LINES LCD_HEIGHT
#define LCD_SCROLLABLE_LINES LCD_HEIGHT * 2
#endif
extern struct scroll_screen_info lcd_scroll_info;

View file

@ -82,6 +82,40 @@ void lcd_stop_scroll(void)
lcd_scroll_info.lines = 0;
}
/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
void lcd_scroll_stop_line(struct viewport* current_vp, int y)
{
int i = 0;
while (i < lcd_scroll_info.lines)
{
if ((lcd_scroll_info.scroll[i].vp == current_vp) &&
((y < 0) || (lcd_scroll_info.scroll[i].y == y)))
{
/* If i is not the last active line in the array, then move
the last item to position i */
if ((i + 1) != lcd_scroll_info.lines)
{
lcd_scroll_info.scroll[i] = lcd_scroll_info.scroll[lcd_scroll_info.lines-1];
}
lcd_scroll_info.lines--;
/* A line can only appear once, so we're done. */
return ;
}
else
{
i++;
}
}
}
/* Stop all scrolling lines in the specified viewport */
void lcd_scroll_stop(struct viewport* vp)
{
lcd_scroll_stop_line(vp, -1);
}
void lcd_scroll_speed(int speed)
{
lcd_scroll_info.ticks = scroll_tick_table[speed];
@ -122,6 +156,40 @@ void lcd_remote_stop_scroll(void)
lcd_remote_scroll_info.lines = 0;
}
/* Stop scrolling line y in the specified viewport, or all lines if y < 0 */
void lcd_remote_scroll_stop_line(struct viewport* current_vp, int y)
{
int i = 0;
while (i < lcd_remote_scroll_info.lines)
{
if ((lcd_remote_scroll_info.scroll[i].vp == current_vp) &&
((y < 0) || (lcd_remote_scroll_info.scroll[i].y == y)))
{
/* If i is not the last active line in the array, then move
the last item to position i */
if ((i + 1) != lcd_remote_scroll_info.lines)
{
lcd_remote_scroll_info.scroll[i] = lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines-1];
}
lcd_remote_scroll_info.lines--;
/* A line can only appear once, so we're done. */
return ;
}
else
{
i++;
}
}
}
/* Stop all scrolling lines in the specified viewport */
void lcd_remote_scroll_stop(struct viewport* vp)
{
lcd_remote_scroll_stop_line(vp, -1);
}
void lcd_remote_scroll_speed(int speed)
{
lcd_remote_scroll_info.ticks = scroll_tick_table[speed];

View file

@ -11,10 +11,9 @@ static volatile bool lcd_on = true;
volatile bool lcd_poweroff = false;
static unsigned lcd_yuv_options = 0;
/*
** These are imported from lcd-16bit.c
** This is imported from lcd-16bit.c
*/
extern unsigned fg_pattern;
extern unsigned bg_pattern;
extern struct viewport* current_vp;
/* Copies a rectangle from one framebuffer to another. Can be used in
single transfer mode with width = num pixels, and height = 1 which
@ -245,7 +244,7 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y,
[dstp]"r"(LCD_WIDTH - width),
[transcolor]"r"(TRANSPARENT_COLOR),
[fgcolor]"r"(REPLACEWITHFG_COLOR),
[fgpat]"r"(fg_pattern)
[fgpat]"r"(current_vp->fg_pattern)
);
}