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

View file

@ -35,10 +35,40 @@
unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]; unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH];
static int drawmode = DRMODE_SOLID; static struct viewport default_vp =
static int xmargin = 0; {
static int ymargin = 0; .x = 0,
static int curfont = FONT_SYSFIXED; .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 */ /* LCD init */
void lcd_init(void) void lcd_init(void)
@ -53,38 +83,48 @@ void lcd_init(void)
void lcd_set_drawmode(int mode) 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) int lcd_get_drawmode(void)
{ {
return drawmode; return current_vp->drawmode;
} }
void lcd_setmargins(int x, int y) void lcd_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; current_vp->ymargin = y;
} }
int lcd_getxmargin(void) int lcd_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_getymargin(void) 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) void lcd_setfont(int newfont)
{ {
curfont = newfont; current_vp->font = newfont;
} }
int lcd_getstringsize(const unsigned char *str, int *w, int *h) 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 ***/ /*** low-level drawing functions ***/
@ -187,17 +227,42 @@ lcd_blockfunc_type* const lcd_blockfuncs[8] = {
/* Clear the whole display */ /* Clear the whole display */
void lcd_clear_display(void) 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); memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
lcd_scroll_info.lines = 0; 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 */ /* Set a single pixel */
void lcd_drawpixel(int x, int y) void lcd_drawpixel(int x, int y)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
lcd_pixelfuncs[drawmode](x, y); ((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
} }
/* Draw a line */ /* Draw a line */
@ -209,7 +274,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2; int d, dinc1, dinc2;
int x, xinc1, xinc2; int x, xinc1, xinc2;
int y, yinc1, yinc2; int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1); deltax = abs(x2 - x1);
deltay = abs(y2 - y1); 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++) for (i = 0; i < numpixels; i++)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
pfunc(x, y); ((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0) if (d < 0)
{ {
@ -288,16 +354,22 @@ void lcd_hline(int x1, int x2, int y)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (x1 < 0) if (x1 < 0)
x1 = 0; x1 = 0;
if (x2 >= LCD_WIDTH) if (x2 >= current_vp->width)
x2 = LCD_WIDTH-1; 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]; dst = &lcd_framebuffer[y>>3][x1];
mask = 1 << (y & 7); mask = 1 << (y & 7);
@ -324,16 +396,22 @@ void lcd_vline(int x, int y1, int y2)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (y1 < 0) if (y1 < 0)
y1 = 0; y1 = 0;
if (y2 >= LCD_HEIGHT) if (y2 >= current_vp->height)
y2 = LCD_HEIGHT-1; 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]; dst = &lcd_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7); ny = y2 - (y1 & ~7);
mask = 0xFFu << (y1 & 7); mask = 0xFFu << (y1 & 7);
@ -375,8 +453,8 @@ void lcd_fillrect(int x, int y, int width, int height)
bool fillopt = false; bool fillopt = false;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -390,27 +468,31 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y; height += y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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; fillopt = true;
} }
} }
else else
{ {
if (drawmode & DRMODE_FG) if (current_vp->drawmode & DRMODE_FG)
{ {
fillopt = true; fillopt = true;
bits = 0xFFu; bits = 0xFFu;
} }
} }
bfunc = lcd_blockfuncs[drawmode]; bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>3][x]; dst = &lcd_framebuffer[y>>3][x];
ny = height - 1 + (y & 7); ny = height - 1 + (y & 7);
mask = 0xFFu << (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; lcd_blockfunc_type *bfunc;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -487,10 +569,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; src_y &= 7;
@ -499,13 +585,13 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
shift = y & 7; shift = y & 7;
ny = height - 1 + shift + src_y; ny = height - 1 + shift + src_y;
bfunc = lcd_blockfuncs[drawmode]; bfunc = lcd_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y); mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7); mask_bottom = 0xFFu >> (~ny & 7);
if (shift == 0) if (shift == 0)
{ {
bool copyopt = (drawmode == DRMODE_SOLID); bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
for (; ny >= 8; ny -= 8) 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 ch;
unsigned short *ucs; unsigned short *ucs;
struct font* pf = font_get(curfont); struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1); ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH) while ((ch = *ucs++) != 0 && x < current_vp->width)
{ {
int width; int width;
const unsigned char *bits; 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 style, int offset)
{ {
int xpos,ypos,w,h,xrect; 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 */ /* 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]) if(!str || !str[0])
return; return;
lcd_getstringsize(str, &w, &h); lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length(str); xpos = current_vp->xmargin + x*w / utf8length(str);
ypos = ymargin + y*h; ypos = current_vp->ymargin + y*h;
drawmode = (style & STYLE_INVERT) ? current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str); lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID; current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0); xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
drawmode = lastmode; current_vp->drawmode = lastmode;
} }
/*** scrolling ***/ /*** scrolling ***/
@ -682,9 +768,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s; struct scrollinfo* s;
int w, h; 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->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style; 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); 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 */ /* prepare scroll line */
char *end; 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 /* scroll bidirectional or forward only depending on the string
width */ width */
if ( lcd_scroll_info.bidir_limit ) { 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; (100 + lcd_scroll_info.bidir_limit) / 100;
} }
else else
@ -722,17 +814,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
} }
end = strchr(s->line, '\0'); 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->len = utf8length(string);
s->offset = offset; s->offset = offset;
s->startx = xmargin + x * s->width / s->len;; s->startx = current_vp->xmargin + x * s->width / s->len;;
s->backward = false; 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) void lcd_scroll_fn(void)
@ -742,26 +833,25 @@ void lcd_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
int lastmode; int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_scroll_info.scroll[index]; s = &lcd_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset -= lcd_scroll_info.step; s->offset -= lcd_scroll_info.step;
else else
s->offset += lcd_scroll_info.step; s->offset += lcd_scroll_info.step;
pf = font_get(curfont); pf = font_get(current_vp->font);
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index * pf->height; ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */ if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) { if (s->offset <= 0) {
@ -770,9 +860,9 @@ void lcd_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; 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 */ /* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos); s->offset = s->width - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; s->start_tick = current_tick + lcd_scroll_info.delay * 2;
} }
@ -783,11 +873,13 @@ void lcd_scroll_fn(void)
s->offset %= s->width; s->offset %= s->width;
} }
lastmode = drawmode; lastmode = current_vp->drawmode;
drawmode = (s->style&STYLE_INVERT) ? current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line); lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode; current_vp->drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 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 fb_data* lcd_backdrop = NULL;
static long lcd_backdrop_offset IDATA_ATTR = 0; static long lcd_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ static struct viewport default_vp =
static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ {
static int drawmode = DRMODE_SOLID; .x = 0,
static int xmargin = 0; .y = 0,
static int ymargin = 0; .width = LCD_WIDTH,
static int curfont = FONT_SYSFIXED; .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 */ /* LCD init */
void lcd_init(void) void lcd_init(void)
{ {
/* Initialise the viewport */
lcd_set_viewport(NULL);
lcd_clear_display(); lcd_clear_display();
/* Call device specific init */ /* Call device specific init */
lcd_init_device(); lcd_init_device();
scroll_init(); 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 ***/ /*** parameter handling ***/
void lcd_set_drawmode(int mode) 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) int lcd_get_drawmode(void)
{ {
return drawmode; return current_vp->drawmode;
} }
void lcd_set_foreground(unsigned brightness) void lcd_set_foreground(unsigned brightness)
{ {
current_vp->fg_pattern = brightness;
fg_pattern = 0x55 * (~brightness & 3); fg_pattern = 0x55 * (~brightness & 3);
} }
unsigned lcd_get_foreground(void) unsigned lcd_get_foreground(void)
{ {
return ~fg_pattern & 3; return current_vp->fg_pattern;
} }
void lcd_set_background(unsigned brightness) void lcd_set_background(unsigned brightness)
{ {
current_vp->bg_pattern = brightness;
bg_pattern = 0x55 * (~brightness & 3); bg_pattern = 0x55 * (~brightness & 3);
} }
unsigned lcd_get_background(void) 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) 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) void lcd_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; current_vp->ymargin = y;
} }
int lcd_getxmargin(void) int lcd_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_getymargin(void) 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) void lcd_setfont(int newfont)
{ {
curfont = newfont; current_vp->font = newfont;
} }
int lcd_getstringsize(const unsigned char *str, int *w, int *h) 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 ***/ /*** low-level drawing functions ***/
@ -345,7 +395,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
/* Clear the whole display */ /* Clear the whole display */
void lcd_clear_display(void) void lcd_clear_display(void)
{ {
if (drawmode & DRMODE_INVERSEVID) if (current_vp->drawmode & DRMODE_INVERSEVID)
{ {
memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
} }
@ -360,11 +410,37 @@ void lcd_clear_display(void)
lcd_scroll_info.lines = 0; 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 */ /* Set a single pixel */
void lcd_drawpixel(int x, int y) void lcd_drawpixel(int x, int y)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
lcd_pixelfuncs[drawmode](x, y); ((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
} }
/* Draw a line */ /* Draw a line */
@ -376,7 +452,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2; int d, dinc1, dinc2;
int x, xinc1, xinc2; int x, xinc1, xinc2;
int y, yinc1, yinc2; int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1); deltax = abs(x2 - x1);
deltay = abs(y2 - y1); 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++) for (i = 0; i < numpixels; i++)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
pfunc(x, y); ((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0) if (d < 0)
{ {
@ -455,16 +532,22 @@ void lcd_hline(int x1, int x2, int y)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (x1 < 0) if (x1 < 0)
x1 = 0; x1 = 0;
if (x2 >= LCD_WIDTH) if (x2 >= current_vp->width)
x2 = LCD_WIDTH-1; 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]; dst = &lcd_framebuffer[y][x1>>2];
nx = x2 - (x1 & ~3); nx = x2 - (x1 & ~3);
mask = 0xFFu >> (2 * (x1 & 3)); mask = 0xFFu >> (2 * (x1 & 3));
@ -496,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (y1 < 0) if (y1 < 0)
y1 = 0; y1 = 0;
if (y2 >= LCD_HEIGHT) if (y2 >= current_vp->height)
y2 = LCD_HEIGHT-1; 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]; dst = &lcd_framebuffer[y1][x>>2];
mask = pixmask[x & 3]; mask = pixmask[x & 3];
@ -542,7 +631,7 @@ void lcd_fillrect(int x, int y, int width, int height)
lcd_blockfunc_type *bfunc; lcd_blockfunc_type *bfunc;
/* nothing to draw? */ /* 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)) || (x + width <= 0) || (y + height <= 0))
return; return;
@ -557,12 +646,16 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y; height += y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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]; dst = &lcd_framebuffer[y][x>>2];
nx = width - 1 + (x & 3); nx = width - 1 + (x & 3);
mask = 0xFFu >> (2 * (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; lcd_pixelfunc_type* bgfunc;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
|| (x + width <= 0) || (y + height <= 0)) (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -633,17 +726,21 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; src_y &= 7;
src_end = src + width; src_end = src + width;
fgfunc = lcd_pixelfuncs[drawmode]; fgfunc = lcd_pixelfuncs[current_vp->drawmode];
bgfunc = lcd_pixelfuncs[drawmode ^ DRMODE_INVERSEVID]; bgfunc = lcd_pixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
nx = x; nx = x;
do do
{ {
@ -704,8 +801,8 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
unsigned mask, mask_right; unsigned mask, mask_right;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
|| (x + width <= 0) || (y + height <= 0)) (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -721,10 +818,14 @@ void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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 */ 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 ch;
unsigned short *ucs; unsigned short *ucs;
struct font* pf = font_get(curfont); struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1); ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH) while ((ch = *ucs++) != 0 && x < current_vp->width)
{ {
int width; int width;
const unsigned char *bits; 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 style, int offset)
{ {
int xpos,ypos,w,h,xrect; 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 */ /* 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]) if(!str || !str[0])
return; return;
lcd_getstringsize(str, &w, &h); lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str); xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h; ypos = current_vp->ymargin + y*h;
drawmode = (style & STYLE_INVERT) ? current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str); lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID; current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0); xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
drawmode = lastmode; current_vp->drawmode = lastmode;
} }
/*** scrolling ***/ /*** scrolling ***/
@ -881,9 +982,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s; struct scrollinfo* s;
int w, h; 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->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style; 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); 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 */ /* prepare scroll line */
char *end; 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 /* scroll bidirectional or forward only depending on the string
width */ width */
if ( lcd_scroll_info.bidir_limit ) { 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; (100 + lcd_scroll_info.bidir_limit) / 100;
} }
else else
@ -921,17 +1028,16 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
} }
end = strchr(s->line, '\0'); 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->len = utf8length((char *)string);
s->offset = offset; s->offset = offset;
s->startx = xmargin + x * s->width / s->len;; s->startx = current_vp->xmargin + x * s->width / s->len;;
s->backward = false; 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) void lcd_scroll_fn(void)
@ -941,26 +1047,25 @@ void lcd_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
int lastmode; int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_scroll_info.scroll[index]; s = &lcd_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset -= lcd_scroll_info.step; s->offset -= lcd_scroll_info.step;
else else
s->offset += lcd_scroll_info.step; s->offset += lcd_scroll_info.step;
pf = font_get(curfont); pf = font_get(current_vp->font);
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index * pf->height; ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */ if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) { if (s->offset <= 0) {
@ -969,9 +1074,9 @@ void lcd_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; 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 */ /* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos); s->offset = s->width - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; s->start_tick = current_tick + lcd_scroll_info.delay * 2;
} }
@ -982,11 +1087,13 @@ void lcd_scroll_fn(void)
s->offset %= s->width; s->offset %= s->width;
} }
lastmode = drawmode; lastmode = current_vp->drawmode;
drawmode = (s->style&STYLE_INVERT) ? current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line); lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode; current_vp->drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 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 fb_data* lcd_backdrop = NULL;
static long lcd_backdrop_offset IDATA_ATTR = 0; static long lcd_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ static struct viewport default_vp =
static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ {
static int drawmode = DRMODE_SOLID; .x = 0,
static int xmargin = 0; .y = 0,
static int ymargin = 0; .width = LCD_WIDTH,
static int curfont = FONT_SYSFIXED; .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 */ /* LCD init */
void lcd_init(void) void lcd_init(void)
{ {
/* Initialise the viewport */
lcd_set_viewport(NULL);
lcd_clear_display(); lcd_clear_display();
/* Call device specific init */ /* Call device specific init */
lcd_init_device(); lcd_init_device();
scroll_init(); 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 ***/ /*** parameter handling ***/
void lcd_set_drawmode(int mode) 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) int lcd_get_drawmode(void)
{ {
return drawmode; return current_vp->drawmode;
} }
void lcd_set_foreground(unsigned brightness) void lcd_set_foreground(unsigned brightness)
{ {
current_vp->fg_pattern = brightness;
fg_pattern = 0x55 * (~brightness & 3); fg_pattern = 0x55 * (~brightness & 3);
} }
unsigned lcd_get_foreground(void) unsigned lcd_get_foreground(void)
{ {
return ~fg_pattern & 3; return current_vp->fg_pattern;
} }
void lcd_set_background(unsigned brightness) void lcd_set_background(unsigned brightness)
{ {
current_vp->fg_pattern = brightness;
bg_pattern = 0x55 * (~brightness & 3); bg_pattern = 0x55 * (~brightness & 3);
} }
unsigned lcd_get_background(void) 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) 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) void lcd_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; current_vp->ymargin = y;
} }
int lcd_getxmargin(void) int lcd_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_getymargin(void) 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) void lcd_setfont(int newfont)
{ {
curfont = newfont; current_vp->font = newfont;
} }
int lcd_getstringsize(const unsigned char *str, int *w, int *h) 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 ***/ /*** low-level drawing functions ***/
@ -347,7 +398,7 @@ static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
/* Clear the whole display */ /* Clear the whole display */
void lcd_clear_display(void) void lcd_clear_display(void)
{ {
if (drawmode & DRMODE_INVERSEVID) if (current_vp->drawmode & DRMODE_INVERSEVID)
{ {
memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer); memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
} }
@ -362,11 +413,37 @@ void lcd_clear_display(void)
lcd_scroll_info.lines = 0; 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 */ /* Set a single pixel */
void lcd_drawpixel(int x, int y) void lcd_drawpixel(int x, int y)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
lcd_pixelfuncs[drawmode](x, y); ((unsigned)y < (unsigned)current_vp->height))
lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
} }
/* Draw a line */ /* Draw a line */
@ -378,7 +455,7 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2; int d, dinc1, dinc2;
int x, xinc1, xinc2; int x, xinc1, xinc2;
int y, yinc1, yinc2; int y, yinc1, yinc2;
lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
deltax = abs(x2 - x1); deltax = abs(x2 - x1);
deltay = abs(y2 - y1); 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++) for (i = 0; i < numpixels; i++)
{ {
if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
pfunc(x, y); ((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0) 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) void lcd_hline(int x1, int x2, int y)
{ {
int x; int x;
int width;
fb_data *dst, *dst_end; fb_data *dst, *dst_end;
unsigned mask; unsigned mask;
lcd_blockfunc_type *bfunc; lcd_blockfunc_type *bfunc;
@ -457,23 +536,30 @@ void lcd_hline(int x1, int x2, int y)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (x1 < 0) if (x1 < 0)
x1 = 0; x1 = 0;
if (x2 >= LCD_WIDTH) if (x2 >= current_vp->width)
x2 = LCD_WIDTH-1; 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]; dst = &lcd_framebuffer[y>>2][x1];
mask = pixmask[y & 3]; mask = pixmask[y & 3];
dst_end = dst + x2 - x1; dst_end = dst + width;
do do
bfunc(dst++, mask, 0xFFu); bfunc(dst++, mask, 0xFFu);
while (dst <= dst_end); while (dst < dst_end);
} }
/* Draw a vertical line (optimised) */ /* Draw a vertical line (optimised) */
@ -493,16 +579,22 @@ void lcd_vline(int x, int y1, int y2)
} }
/* nothing to draw? */ /* 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; return;
/* clipping */ /* clipping */
if (y1 < 0) if (y1 < 0)
y1 = 0; y1 = 0;
if (y2 >= LCD_HEIGHT) if (y2 >= current_vp->height)
y2 = LCD_HEIGHT-1; 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]; dst = &lcd_framebuffer[y1>>2][x];
ny = y2 - (y1 & ~3); ny = y2 - (y1 & ~3);
mask = 0xFFu << (2 * (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; bool fillopt = false;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -559,14 +651,18 @@ void lcd_fillrect(int x, int y, int width, int height)
height += y; height += y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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; fillopt = true;
bits = bg_pattern; bits = bg_pattern;
@ -574,13 +670,13 @@ void lcd_fillrect(int x, int y, int width, int height)
} }
else else
{ {
if (drawmode & DRMODE_FG) if (current_vp->drawmode & DRMODE_FG)
{ {
fillopt = true; fillopt = true;
bits = fg_pattern; bits = fg_pattern;
} }
} }
bfunc = lcd_blockfuncs[drawmode]; bfunc = lcd_blockfuncs[current_vp->drawmode];
dst = &lcd_framebuffer[y>>2][x]; dst = &lcd_framebuffer[y>>2][x];
ny = height - 1 + (y & 3); ny = height - 1 + (y & 3);
mask = 0xFFu << (2 * (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; lcd_blockfunc_type *bfunc;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
|| (x + width <= 0) || (y + height <= 0)) (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -657,10 +753,14 @@ void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; 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; shift = y & 3;
ny = height - 1 + shift + src_y; ny = height - 1 + shift + src_y;
bfunc = lcd_blockfuncs[drawmode]; bfunc = lcd_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y); mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7); 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; unsigned mask, mask_bottom;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -824,10 +924,14 @@ void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_WIDTH) if (x + width > current_vp->width)
width = LCD_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_HEIGHT) if (y + height > current_vp->height)
height = LCD_HEIGHT - y; 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 += stride * (src_y >> 2) + src_x; /* move starting point */
src_y &= 3; 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 ch;
unsigned short *ucs; unsigned short *ucs;
struct font* pf = font_get(curfont); struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1); ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_WIDTH) while ((ch = *ucs++) != 0 && x < current_vp->width)
{ {
int width; int width;
const unsigned char *bits; 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 style, int offset)
{ {
int xpos,ypos,w,h,xrect; 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 */ /* 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]) if(!str || !str[0])
return; return;
lcd_getstringsize(str, &w, &h); lcd_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str); xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h; ypos = current_vp->ymargin + y*h;
drawmode = (style & STYLE_INVERT) ? current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, offset, str); lcd_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID; current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0); xrect = xpos + MAX(w - offset, 0);
lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
drawmode = lastmode; current_vp->drawmode = lastmode;
} }
/*** scrolling ***/ /*** scrolling ***/
@ -1017,9 +1121,15 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
struct scrollinfo* s; struct scrollinfo* s;
int w, h; 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->start_tick = current_tick + lcd_scroll_info.delay;
s->style = style; 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); 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 */ /* prepare scroll line */
char *end; 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 /* scroll bidirectional or forward only depending on the string
width */ width */
if ( lcd_scroll_info.bidir_limit ) { 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; (100 + lcd_scroll_info.bidir_limit) / 100;
} }
else else
@ -1057,17 +1167,17 @@ void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
} }
end = strchr(s->line, '\0'); 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->len = utf8length((char *)string);
s->offset = offset; s->offset = offset;
s->startx = xmargin + x * s->width / s->len; s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false; 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) void lcd_scroll_fn(void)
@ -1077,26 +1187,25 @@ void lcd_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
int lastmode; int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_SCROLLABLE_LINES; index++ ) { for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_scroll_info.scroll[index]; s = &lcd_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset -= lcd_scroll_info.step; s->offset -= lcd_scroll_info.step;
else else
s->offset += lcd_scroll_info.step; s->offset += lcd_scroll_info.step;
pf = font_get(curfont); pf = font_get(current_vp->font);
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index * pf->height; ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */ if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) { if (s->offset <= 0) {
@ -1105,9 +1214,9 @@ void lcd_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; 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 */ /* at end of line */
s->offset = s->width - (LCD_WIDTH - xpos); s->offset = s->width - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; s->start_tick = current_tick + lcd_scroll_info.delay * 2;
} }
@ -1118,11 +1227,14 @@ void lcd_scroll_fn(void)
s->offset %= s->width; s->offset %= s->width;
} }
lastmode = drawmode; lastmode = current_vp->drawmode;
drawmode = (s->style&STYLE_INVERT) ? current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_putsxyofs(xpos, ypos, s->offset, s->line); lcd_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode; current_vp->drawmode = lastmode;
lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); 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 bool xfont_variable_locked[VARIABLE_XCHARS];
static int xspace; /* stores xhcar id of ' ' - often needed */ static int xspace; /* stores xhcar id of ' ' - often needed */
static int xmargin = 0; static struct viewport default_vp =
static int ymargin = 0; {
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.xmargin = 0,
.ymargin = 0,
};
static struct viewport* current_vp = &default_vp;
/* LCD init */ /* LCD init */
void lcd_init (void) void lcd_init (void)
@ -66,22 +75,47 @@ void lcd_init (void)
scroll_init(); 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 **/ /** parameter handling **/
void lcd_setmargins(int x, int y) void lcd_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; current_vp->ymargin = y;
} }
int lcd_getxmargin(void) int lcd_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_getymargin(void) 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) 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) 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 */ if (lcd_char < lcd_pattern_count) /* old char was soft */
lcd_patterns[lcd_char].count--; /* decrease old reference count */ 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) void lcd_clear_display(void)
{ {
int x, y; int x, y;
struct viewport* old_vp = current_vp;
lcd_stop_scroll(); lcd_scroll_info.lines = 0;
lcd_remove_cursor(); lcd_remove_cursor();
/* Set the default viewport - required for lcd_putxchar */
current_vp = &default_vp;
for (x = 0; x < LCD_WIDTH; x++) for (x = 0; x < LCD_WIDTH; x++)
for (y = 0; y < LCD_HEIGHT; y++) for (y = 0; y < LCD_HEIGHT; y++)
lcd_putxchar(x, y, xspace); 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 */ /* Put an unicode character at the given position */
void lcd_putc(int x, int y, unsigned long ucs) 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; return;
lcd_putxchar(x, y, find_xchar(ucs)); 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 */ /* Show cursor (alternating with existing character) at the given position */
void lcd_put_cursor(int x, int y, unsigned long cursor_ucs) void lcd_put_cursor(int x, int y, unsigned long cursor_ucs)
{ {
if ((unsigned)x >= LCD_WIDTH || (unsigned)y >= LCD_HEIGHT if ((unsigned)x >= (unsigned)current_vp->width ||
|| lcd_cursor.enabled) (unsigned)y >= (unsigned)current_vp->height ||
lcd_cursor.enabled)
return; return;
lcd_cursor.enabled = true; lcd_cursor.enabled = true;
lcd_cursor.visible = false; lcd_cursor.visible = false;
lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char); lcd_cursor.hw_char = map_xchar(find_xchar(cursor_ucs), &lcd_cursor.subst_char);
lcd_cursor.x = x; lcd_cursor.x = current_vp->x + x;
lcd_cursor.y = y; lcd_cursor.y = current_vp->y + y;
lcd_cursor.downcount = 0; lcd_cursor.downcount = 0;
lcd_cursor.divider = MAX((HZ/2) / lcd_scroll_info.ticks, 1); 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; unsigned short ucs;
const unsigned char *utf8 = str; const unsigned char *utf8 = str;
while (*utf8 && x < LCD_WIDTH) while (*utf8 && x < current_vp->width)
{ {
utf8 = utf8decode(utf8, &ucs); 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 */ /* Put a string at a given position */
void lcd_putsxy(int x, int y, const unsigned char *str) void lcd_putsxy(int x, int y, const unsigned char *str)
{ {
if ((unsigned)y >= LCD_HEIGHT) if ((unsigned)y >= (unsigned)current_vp->height)
return; return;
lcd_putsxyofs(x, y, 0, str); 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 */ /* 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) void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
{ {
x += xmargin; if ((unsigned)y >= (unsigned)current_vp->height)
y += ymargin;
if ((unsigned)y >= LCD_HEIGHT)
return; return;
/* make sure scrolling is turned off on the line we are updating */ /* 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); x = lcd_putsxyofs(x, y, offset, str);
while (x < LCD_WIDTH) while (x < current_vp->width)
lcd_putxchar(x++, y, xspace); 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; struct scrollinfo* s;
int len; 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; s->start_tick = current_tick + lcd_scroll_info.delay;
lcd_puts_offset(x, y, string, offset); lcd_puts_offset(x, y, string, offset);
len = utf8length(string); len = utf8length(string);
if (LCD_WIDTH - x - xmargin < len) if (current_vp->width - x - current_vp->xmargin < len)
{ {
/* prepare scroll line */ /* prepare scroll line */
char *end; 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 */ /* scroll bidirectional or forward only depending on the string width */
if (lcd_scroll_info.bidir_limit) 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; (100 + lcd_scroll_info.bidir_limit) / 100;
} }
else else
@ -432,16 +512,15 @@ void lcd_puts_scroll_offset(int x, int y, const unsigned char *string,
} }
end = strchr(s->line, '\0'); 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->offset = offset;
s->startx = xmargin + x; s->startx = current_vp->xmargin + x;
s->backward = false; 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) void lcd_scroll_fn(void)
@ -450,27 +529,25 @@ void lcd_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
bool update; bool update;
struct viewport* old_vp = current_vp;
update = false; update = false;
for (index = 0; index < LCD_SCROLLABLE_LINES; index++) for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
{
/* really scroll? */
if ((lcd_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_scroll_info.scroll[index]; s = &lcd_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset--; s->offset--;
else else
s->offset++; s->offset++;
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index; ypos = current_vp->ymargin + s->y;
if (s->bidir) /* scroll bidirectional */ if (s->bidir) /* scroll bidirectional */
{ {
@ -480,9 +557,9 @@ void lcd_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; 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 */ /* at end of line */
s->offset = s->len - (LCD_WIDTH - xpos); s->offset = s->len - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_scroll_info.delay * 2; s->start_tick = current_tick + lcd_scroll_info.delay * 2;
} }
@ -497,6 +574,8 @@ void lcd_scroll_fn(void)
update = true; update = true;
} }
lcd_set_viewport(old_vp);
if (lcd_cursor.enabled) if (lcd_cursor.enabled)
{ {
if (--lcd_cursor.downcount <= 0) if (--lcd_cursor.downcount <= 0)

View file

@ -38,47 +38,88 @@
fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]
IBSS_ATTR; IBSS_ATTR;
static int drawmode = DRMODE_SOLID; static struct viewport default_vp =
static int xmargin = 0; {
static int ymargin = 0; .x = 0,
static int curfont = FONT_SYSFIXED; .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 ***/ /*** parameter handling ***/
void lcd_remote_set_drawmode(int mode) 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) int lcd_remote_get_drawmode(void)
{ {
return drawmode; return current_vp->drawmode;
} }
void lcd_remote_setmargins(int x, int y) void lcd_remote_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; 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) int lcd_remote_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_remote_getymargin(void) int lcd_remote_getymargin(void)
{ {
return ymargin; return current_vp->ymargin;
} }
void lcd_remote_setfont(int newfont) void lcd_remote_setfont(int newfont)
{ {
curfont = newfont; current_vp->font = newfont;
} }
int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) 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 ***/ /*** low-level drawing functions ***/
@ -181,17 +222,44 @@ lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
/* Clear the whole display */ /* Clear the whole display */
void lcd_remote_clear_display(void) 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); memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
lcd_remote_scroll_info.lines = 0; 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 */ /* Set a single pixel */
void lcd_remote_drawpixel(int x, int y) void lcd_remote_drawpixel(int x, int y)
{ {
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
lcd_remote_pixelfuncs[drawmode](x, y); ((unsigned)y < (unsigned)current_vp->height))
lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
} }
/* Draw a line */ /* Draw a line */
@ -203,7 +271,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2; int d, dinc1, dinc2;
int x, xinc1, xinc2; int x, xinc1, xinc2;
int y, yinc1, yinc2; 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); deltax = abs(x2 - x1);
deltay = abs(y2 - y1); 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++) for (i = 0; i < numpixels; i++)
{ {
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
pfunc(x, y); pfunc(x + current_vp->x, y + current_vp->y);
if (d < 0) if (d < 0)
{ {
@ -268,7 +336,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
/* Draw a horizontal line (optimised) */ /* Draw a horizontal line (optimised) */
void lcd_remote_hline(int x1, int x2, int y) void lcd_remote_hline(int x1, int x2, int y)
{ {
int x; int x, width;
fb_remote_data *dst, *dst_end; fb_remote_data *dst, *dst_end;
unsigned mask; unsigned mask;
lcd_remote_blockfunc_type *bfunc; lcd_remote_blockfunc_type *bfunc;
@ -282,24 +350,30 @@ void lcd_remote_hline(int x1, int x2, int y)
} }
/* nothing to draw? */ /* 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)) || (x2 < 0))
return; return;
/* clipping */ /* clipping */
if (x1 < 0) if (x1 < 0)
x1 = 0; x1 = 0;
if (x2 >= LCD_REMOTE_WIDTH) if (x2 >= current_vp->width)
x2 = LCD_REMOTE_WIDTH-1; 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]; dst = &lcd_remote_framebuffer[y>>3][x1];
mask = 1 << (y & 7); mask = 1 << (y & 7);
dst_end = dst + x2 - x1; dst_end = dst + width;
do do
bfunc(dst++, mask, 0xFFu); bfunc(dst++, mask, 0xFFu);
while (dst <= dst_end); while (dst < dst_end);
} }
/* Draw a vertical line (optimised) */ /* Draw a vertical line (optimised) */
@ -319,17 +393,22 @@ void lcd_remote_vline(int x, int y1, int y2)
} }
/* nothing to draw? */ /* 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)) || (y2 < 0))
return; return;
/* clipping */ /* clipping */
if (y1 < 0) if (y1 < 0)
y1 = 0; y1 = 0;
if (y2 >= LCD_REMOTE_HEIGHT) if (y2 >= current_vp->height)
y2 = LCD_REMOTE_HEIGHT-1; 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]; dst = &lcd_remote_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7); ny = y2 - (y1 & ~7);
mask = 0xFFu << (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; bool fillopt = false;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -386,27 +465,32 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
height += y; height += y;
y = 0; y = 0;
} }
if (x + width > LCD_REMOTE_WIDTH) if (x + width > current_vp->width)
width = LCD_REMOTE_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_REMOTE_HEIGHT) if (y + height > current_vp->height)
height = LCD_REMOTE_HEIGHT - y; 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; fillopt = true;
} }
} }
else else
{ {
if (drawmode & DRMODE_FG) if (current_vp->drawmode & DRMODE_FG)
{ {
fillopt = true; fillopt = true;
bits = 0xFFu; bits = 0xFFu;
} }
} }
bfunc = lcd_remote_blockfuncs[drawmode];
bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x]; dst = &lcd_remote_framebuffer[y>>3][x];
ny = height - 1 + (y & 7); ny = height - 1 + (y & 7);
mask = 0xFFu << (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; lcd_remote_blockfunc_type *bfunc;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -483,10 +567,14 @@ void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_REMOTE_WIDTH) if (x + width > current_vp->width)
width = LCD_REMOTE_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_REMOTE_HEIGHT) if (y + height > current_vp->height)
height = LCD_REMOTE_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; 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; shift = y & 7;
ny = height - 1 + shift + src_y; ny = height - 1 + shift + src_y;
bfunc = lcd_remote_blockfuncs[drawmode]; bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y); mask = 0xFFu << (shift + src_y);
mask_bottom = 0xFFu >> (~ny & 7); mask_bottom = 0xFFu >> (~ny & 7);
if (shift == 0) if (shift == 0)
{ {
bool copyopt = (drawmode == DRMODE_SOLID); bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
for (; ny >= 8; ny -= 8) 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 ch;
unsigned short *ucs; unsigned short *ucs;
struct font* pf = font_get(curfont); struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1); ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) while ((ch = *ucs++) != 0 && x < current_vp->width)
{ {
int width; int width;
const unsigned char *bits; 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 style, int offset)
{ {
int xpos,ypos,w,h,xrect; 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 */ /* 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]) if(!str || !str[0])
return; return;
lcd_remote_getstringsize(str, &w, &h); lcd_remote_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str); xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h; ypos = current_vp->ymargin + y*h;
drawmode = (style & STYLE_INVERT) ? current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, offset, str); lcd_remote_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID; current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0); xrect = xpos + MAX(w - offset, 0);
lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
drawmode = lastmode; current_vp->drawmode = lastmode;
} }
/*** scrolling ***/ /*** scrolling ***/
@ -680,9 +768,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
struct scrollinfo* s; struct scrollinfo* s;
int w, h; 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->start_tick = current_tick + lcd_remote_scroll_info.delay;
s->style = style; 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); 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 */ /* prepare scroll line */
char *end; 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 /* scroll bidirectional or forward only depending on the string
width */ width */
if ( lcd_remote_scroll_info.bidir_limit ) { 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; (100 + lcd_remote_scroll_info.bidir_limit) / 100;
} }
else 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'); 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->len = utf8length((char *)string);
s->offset = offset; s->offset = offset;
s->startx = xmargin + x * s->width / s->len;; s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false; 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) void lcd_remote_scroll_fn(void)
@ -740,26 +834,25 @@ void lcd_remote_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
int lastmode; int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) { for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
/* really scroll? */
if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_remote_scroll_info.scroll[index]; s = &lcd_remote_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_remote_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset -= lcd_remote_scroll_info.step; s->offset -= lcd_remote_scroll_info.step;
else else
s->offset += lcd_remote_scroll_info.step; s->offset += lcd_remote_scroll_info.step;
pf = font_get(curfont); pf = font_get(current_vp->font);
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index * pf->height; ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */ if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) { if (s->offset <= 0) {
@ -768,9 +861,9 @@ void lcd_remote_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 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 */ /* at end of line */
s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); s->offset = s->width - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 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; s->offset %= s->width;
} }
lastmode = drawmode; lastmode = current_vp->drawmode;
drawmode = (s->style&STYLE_INVERT) ? current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode; current_vp->drawmode = lastmode;
lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); lcd_remote_update_viewport_rect(xpos, ypos,
current_vp->width - xpos, pf->height);
} }
lcd_remote_set_viewport(old_vp);
} }
/* LCD init */ /* 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 fb_remote_data* remote_backdrop = NULL;
static long remote_backdrop_offset IDATA_ATTR = 0; static long remote_backdrop_offset IDATA_ATTR = 0;
static unsigned fg_pattern IDATA_ATTR = 0xFFFF; /* initially black */ static struct viewport default_vp =
static unsigned bg_pattern IDATA_ATTR = 0x0000; /* initially white */ {
static int drawmode = DRMODE_SOLID; .x = 0,
static int xmargin = 0; .y = 0,
static int ymargin = 0; .width = LCD_REMOTE_WIDTH,
static int curfont = FONT_SYSFIXED; .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 ***/ /*** parameter handling ***/
unsigned lcd_remote_color_to_native(unsigned color) 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) 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) int lcd_remote_get_drawmode(void)
{ {
return drawmode; return current_vp->drawmode;
} }
void lcd_remote_set_foreground(unsigned brightness) void lcd_remote_set_foreground(unsigned brightness)
{ {
current_vp->fg_pattern = brightness;
fg_pattern = patterns[brightness & 3]; fg_pattern = patterns[brightness & 3];
} }
unsigned lcd_remote_get_foreground(void) unsigned lcd_remote_get_foreground(void)
{ {
return (~fg_pattern >> 7) & 3; return current_vp->fg_pattern;
} }
void lcd_remote_set_background(unsigned brightness) void lcd_remote_set_background(unsigned brightness)
{ {
current_vp->bg_pattern = brightness;
bg_pattern = patterns[brightness & 3]; bg_pattern = patterns[brightness & 3];
} }
unsigned lcd_remote_get_background(void) 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, 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); 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) void lcd_remote_setmargins(int x, int y)
{ {
xmargin = x; current_vp->xmargin = x;
ymargin = y; current_vp->ymargin = y;
} }
int lcd_remote_getxmargin(void) int lcd_remote_getxmargin(void)
{ {
return xmargin; return current_vp->xmargin;
} }
int lcd_remote_getymargin(void) int lcd_remote_getymargin(void)
{ {
return ymargin; return current_vp->ymargin;
} }
void lcd_remote_setfont(int newfont) void lcd_remote_setfont(int newfont)
{ {
curfont = newfont; current_vp->font = newfont;
} }
int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) 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 ***/ /*** low-level drawing functions ***/
@ -351,9 +399,9 @@ static inline void setblock(fb_remote_data *address, unsigned mask, unsigned bit
/* Clear the whole display */ /* Clear the whole display */
void lcd_remote_clear_display(void) 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); sizeof lcd_remote_framebuffer);
} }
else else
@ -362,18 +410,44 @@ void lcd_remote_clear_display(void)
memcpy(lcd_remote_framebuffer, remote_backdrop, memcpy(lcd_remote_framebuffer, remote_backdrop,
sizeof lcd_remote_framebuffer); sizeof lcd_remote_framebuffer);
else else
memset(lcd_remote_framebuffer, bg_pattern, memset(lcd_remote_framebuffer, patterns[default_vp.bg_pattern & 3],
sizeof lcd_remote_framebuffer); sizeof lcd_remote_framebuffer);
} }
lcd_remote_scroll_info.lines = 0; 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 */ /* Set a single pixel */
void lcd_remote_drawpixel(int x, int y) void lcd_remote_drawpixel(int x, int y)
{ {
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
lcd_remote_pixelfuncs[drawmode](x, y); ((unsigned)y < (unsigned)current_vp->height))
lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
} }
/* Draw a line */ /* Draw a line */
@ -385,7 +459,7 @@ void lcd_remote_drawline(int x1, int y1, int x2, int y2)
int d, dinc1, dinc2; int d, dinc1, dinc2;
int x, xinc1, xinc2; int x, xinc1, xinc2;
int y, yinc1, yinc2; 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); deltax = abs(x2 - x1);
deltay = abs(y2 - y1); 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++) for (i = 0; i < numpixels; i++)
{ {
if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT)) if (((unsigned)x < (unsigned)current_vp->width) &&
pfunc(x, y); ((unsigned)y < (unsigned)current_vp->height))
pfunc(current_vp->x + x, current_vp->y + y);
if (d < 0) 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) void lcd_remote_hline(int x1, int x2, int y)
{ {
int x; int x;
int width;
fb_remote_data *dst, *dst_end; fb_remote_data *dst, *dst_end;
unsigned mask; unsigned mask;
lcd_remote_blockfunc_type *bfunc; lcd_remote_blockfunc_type *bfunc;
@ -464,24 +540,30 @@ void lcd_remote_hline(int x1, int x2, int y)
} }
/* nothing to draw? */ /* 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)) || (x2 < 0))
return; return;
/* clipping */ /* clipping */
if (x1 < 0) if (x1 < 0)
x1 = 0; x1 = 0;
if (x2 >= LCD_REMOTE_WIDTH) if (x2 >= current_vp->width)
x2 = LCD_REMOTE_WIDTH-1; 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]; dst = &lcd_remote_framebuffer[y>>3][x1];
mask = 0x0101 << (y & 7); mask = 0x0101 << (y & 7);
dst_end = dst + x2 - x1; dst_end = dst + width;
do do
bfunc(dst++, mask, 0xFFFFu); bfunc(dst++, mask, 0xFFFFu);
while (dst <= dst_end); while (dst < dst_end);
} }
/* Draw a vertical line (optimised) */ /* Draw a vertical line (optimised) */
@ -501,17 +583,22 @@ void lcd_remote_vline(int x, int y1, int y2)
} }
/* nothing to draw? */ /* 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)) || (y2 < 0))
return; return;
/* clipping */ /* clipping */
if (y1 < 0) if (y1 < 0)
y1 = 0; y1 = 0;
if (y2 >= LCD_REMOTE_HEIGHT) if (y2 >= current_vp->height)
y2 = LCD_REMOTE_HEIGHT-1; 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]; dst = &lcd_remote_framebuffer[y1>>3][x];
ny = y2 - (y1 & ~7); ny = y2 - (y1 & ~7);
mask = (0xFFu << (y1 & 7)) & 0xFFu; mask = (0xFFu << (y1 & 7)) & 0xFFu;
@ -555,8 +642,8 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
bool fillopt = false; bool fillopt = false;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -570,14 +657,18 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
height += y; height += y;
y = 0; y = 0;
} }
if (x + width > LCD_REMOTE_WIDTH) if (x + width > current_vp->width)
width = LCD_REMOTE_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_REMOTE_HEIGHT) if (y + height > current_vp->height)
height = LCD_REMOTE_HEIGHT - y; 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; fillopt = true;
bits = bg_pattern; bits = bg_pattern;
@ -585,13 +676,13 @@ void lcd_remote_fillrect(int x, int y, int width, int height)
} }
else else
{ {
if (drawmode & DRMODE_FG) if (current_vp->drawmode & DRMODE_FG)
{ {
fillopt = true; fillopt = true;
bits = fg_pattern; bits = fg_pattern;
} }
} }
bfunc = lcd_remote_blockfuncs[drawmode]; bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
dst = &lcd_remote_framebuffer[y>>3][x]; dst = &lcd_remote_framebuffer[y>>3][x];
ny = height - 1 + (y & 7); ny = height - 1 + (y & 7);
mask = (0xFFu << (y & 7)) & 0xFFu; 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; lcd_remote_blockfunc_type *bfunc;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -670,10 +761,14 @@ void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_REMOTE_WIDTH) if (x + width > current_vp->width)
width = LCD_REMOTE_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_REMOTE_HEIGHT) if (y + height > current_vp->height)
height = LCD_REMOTE_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; 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; shift = y & 7;
ny = height - 1 + shift + src_y; ny = height - 1 + shift + src_y;
bfunc = lcd_remote_blockfuncs[drawmode]; bfunc = lcd_remote_blockfuncs[current_vp->drawmode];
mask = 0xFFu << (shift + src_y); mask = 0xFFu << (shift + src_y);
/* not byte-doubled here because shift+src_y can be > 7 */ /* not byte-doubled here because shift+src_y can be > 7 */
mask_bottom = 0xFFu >> (~ny & 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; unsigned mask, mask_bottom;
/* nothing to draw? */ /* nothing to draw? */
if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH) if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
|| (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0)) || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
return; return;
/* clipping */ /* clipping */
@ -810,10 +905,14 @@ void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y,
src_y -= y; src_y -= y;
y = 0; y = 0;
} }
if (x + width > LCD_REMOTE_WIDTH) if (x + width > current_vp->width)
width = LCD_REMOTE_WIDTH - x; width = current_vp->width - x;
if (y + height > LCD_REMOTE_HEIGHT) if (y + height > current_vp->height)
height = LCD_REMOTE_HEIGHT - y; 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 += stride * (src_y >> 3) + src_x; /* move starting point */
src_y &= 7; 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 ch;
unsigned short *ucs; unsigned short *ucs;
struct font* pf = font_get(curfont); struct font* pf = font_get(current_vp->font);
ucs = bidi_l2v(str, 1); ucs = bidi_l2v(str, 1);
while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH) while ((ch = *ucs++) != 0 && x < current_vp->width)
{ {
int width; int width;
const unsigned char *bits; 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 style, int offset)
{ {
int xpos,ypos,w,h,xrect; 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 */ /* 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]) if(!str || !str[0])
return; return;
lcd_remote_getstringsize(str, &w, &h); lcd_remote_getstringsize(str, &w, &h);
xpos = xmargin + x*w / utf8length((char *)str); xpos = current_vp->xmargin + x*w / utf8length((char *)str);
ypos = ymargin + y*h; ypos = current_vp->ymargin + y*h;
drawmode = (style & STYLE_INVERT) ? current_vp->drawmode = (style & STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, offset, str); lcd_remote_putsxyofs(xpos, ypos, offset, str);
drawmode ^= DRMODE_INVERSEVID; current_vp->drawmode ^= DRMODE_INVERSEVID;
xrect = xpos + MAX(w - offset, 0); xrect = xpos + MAX(w - offset, 0);
lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h); lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h);
drawmode = lastmode; current_vp->drawmode = lastmode;
} }
/*** scrolling ***/ /*** scrolling ***/
@ -1017,9 +1116,15 @@ void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *stri
struct scrollinfo* s; struct scrollinfo* s;
int w, h; 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->start_tick = current_tick + lcd_remote_scroll_info.delay;
s->style = style; 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); 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 */ /* prepare scroll line */
char *end; 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 /* scroll bidirectional or forward only depending on the string
width */ width */
if ( lcd_remote_scroll_info.bidir_limit ) { 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; (100 + lcd_remote_scroll_info.bidir_limit) / 100;
} }
else 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'); 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->len = utf8length((char *)string);
s->offset = offset; s->offset = offset;
s->startx = xmargin + x * s->width / s->len;; s->startx = current_vp->xmargin + x * s->width / s->len;
s->backward = false; 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) void lcd_remote_scroll_fn(void)
@ -1077,26 +1182,25 @@ void lcd_remote_scroll_fn(void)
int index; int index;
int xpos, ypos; int xpos, ypos;
int lastmode; int lastmode;
struct viewport* old_vp = current_vp;
for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) { for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) {
/* really scroll? */
if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
continue;
s = &lcd_remote_scroll_info.scroll[index]; s = &lcd_remote_scroll_info.scroll[index];
/* check pause */ /* check pause */
if (TIME_BEFORE(current_tick, s->start_tick)) if (TIME_BEFORE(current_tick, s->start_tick))
continue; continue;
lcd_remote_set_viewport(s->vp);
if (s->backward) if (s->backward)
s->offset -= lcd_remote_scroll_info.step; s->offset -= lcd_remote_scroll_info.step;
else else
s->offset += lcd_remote_scroll_info.step; s->offset += lcd_remote_scroll_info.step;
pf = font_get(curfont); pf = font_get(current_vp->font);
xpos = s->startx; xpos = s->startx;
ypos = ymargin + index * pf->height; ypos = current_vp->ymargin + s->y * pf->height;
if (s->bidir) { /* scroll bidirectional */ if (s->bidir) { /* scroll bidirectional */
if (s->offset <= 0) { if (s->offset <= 0) {
@ -1105,9 +1209,9 @@ void lcd_remote_scroll_fn(void)
s->backward = false; s->backward = false;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 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 */ /* at end of line */
s->offset = s->width - (LCD_REMOTE_WIDTH - xpos); s->offset = s->width - (current_vp->width - xpos);
s->backward = true; s->backward = true;
s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; 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; s->offset %= s->width;
} }
lastmode = drawmode; lastmode = current_vp->drawmode;
drawmode = (s->style&STYLE_INVERT) ? current_vp->drawmode = (s->style&STYLE_INVERT) ?
(DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
drawmode = lastmode; current_vp->drawmode = lastmode;
lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height); lcd_remote_update_viewport_rect(xpos, ypos,
current_vp->width - xpos, pf->height);
} }
lcd_remote_set_viewport(old_vp);
} }
/* LCD init */ /* LCD init */
void lcd_remote_init(void) void lcd_remote_init(void)
{ {
/* Initialise the viewport */
lcd_remote_set_viewport(NULL);
#ifndef SIMULATOR #ifndef SIMULATOR
/* Call device specific init */ /* Call device specific init */
lcd_remote_init_device(); lcd_remote_init_device();

View file

@ -24,6 +24,7 @@
#include "cpu.h" #include "cpu.h"
#include "config.h" #include "config.h"
#include "adc.h" #include "adc.h"
#include "lcd.h"
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
@ -109,7 +110,9 @@ extern void lcd_remote_init(void);
extern int lcd_remote_default_contrast(void); extern int lcd_remote_default_contrast(void);
extern void lcd_remote_set_contrast(int val); 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_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(int x, int y, const unsigned char *str);
extern void lcd_remote_puts_style(int x, int y, const unsigned char *str, extern void lcd_remote_puts_style(int x, int y, const unsigned char *str,
int style); 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(void);
extern void lcd_remote_update_rect(int x, int y, int width, int height); 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_invert_display(bool yesno);
extern void lcd_remote_set_flip(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 void lcd_remote_setmargins(int xmargin, int ymargin);
extern int lcd_remote_getxmargin(void); extern int lcd_remote_getxmargin(void);
extern int lcd_remote_getymargin(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 void lcd_remote_setfont(int font);
extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h); extern int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h);

View file

@ -24,6 +24,28 @@
#include "cpu.h" #include "cpu.h"
#include "config.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_DEFAULT 0x00000000
#define STYLE_COLORED 0x10000000 #define STYLE_COLORED 0x10000000
#define STYLE_INVERT 0x20000000 #define STYLE_INVERT 0x20000000
@ -76,9 +98,14 @@ extern void lcd_set_contrast(int val);
extern void lcd_setmargins(int xmargin, int ymargin); extern void lcd_setmargins(int xmargin, int ymargin);
extern int lcd_getxmargin(void); extern int lcd_getxmargin(void);
extern int lcd_getymargin(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 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(void);
extern void lcd_update_viewport(void);
extern void lcd_clear_viewport(void);
extern void lcd_clear_display(void); extern void lcd_clear_display(void);
extern void lcd_putsxy(int x, int y, const unsigned char *string); extern void lcd_putsxy(int x, int y, const unsigned char *string);
extern void lcd_puts(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 */ /* update a fraction of the screen */
extern void lcd_update_rect(int x, int y, int width, int height); 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 #ifdef HAVE_REMOTE_LCD
extern void lcd_remote_update(void); extern void lcd_remote_update(void);

View file

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

View file

@ -82,6 +82,40 @@ void lcd_stop_scroll(void)
lcd_scroll_info.lines = 0; 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) void lcd_scroll_speed(int speed)
{ {
lcd_scroll_info.ticks = scroll_tick_table[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; 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) void lcd_remote_scroll_speed(int speed)
{ {
lcd_remote_scroll_info.ticks = scroll_tick_table[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; volatile bool lcd_poweroff = false;
static unsigned lcd_yuv_options = 0; 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 struct viewport* current_vp;
extern unsigned bg_pattern;
/* Copies a rectangle from one framebuffer to another. Can be used in /* Copies a rectangle from one framebuffer to another. Can be used in
single transfer mode with width = num pixels, and height = 1 which 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), [dstp]"r"(LCD_WIDTH - width),
[transcolor]"r"(TRANSPARENT_COLOR), [transcolor]"r"(TRANSPARENT_COLOR),
[fgcolor]"r"(REPLACEWITHFG_COLOR), [fgcolor]"r"(REPLACEWITHFG_COLOR),
[fgpat]"r"(fg_pattern) [fgpat]"r"(current_vp->fg_pattern)
); );
} }