diff --git a/apps/plugin.c b/apps/plugin.c index baf6a2a256..9992d85620 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -799,7 +799,6 @@ static const struct plugin_api rockbox_api = { lcd_set_viewport, viewport_set_fullscreen, lcd_set_framebuffer, - lcd_bmp_part, #endif }; diff --git a/apps/plugin.h b/apps/plugin.h index b8ed7a9084..b34a5cf0de 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -155,12 +155,12 @@ void* plugin_get_buffer(size_t *buffer_size); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 221 +#define PLUGIN_API_VERSION 222 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 220 +#define PLUGIN_MIN_API_VERSION 222 /* plugin return codes */ /* internal returns start at 0x100 to make exit(1..255) work */ @@ -970,8 +970,6 @@ struct plugin_api { void (*viewport_set_fullscreen)(struct viewport *vp, const enum screen_type screen); void (*lcd_set_framebuffer)(fb_data *fb); - void (*lcd_bmp_part)(const struct bitmap *bm, int src_x, int src_y, - int x, int y, int width, int height); #endif }; diff --git a/apps/plugins/lib/grey.h b/apps/plugins/lib/grey.h index 7c990ad792..d63d19ee4a 100644 --- a/apps/plugins/lib/grey.h +++ b/apps/plugins/lib/grey.h @@ -60,6 +60,16 @@ void grey_release(void); void grey_show(bool enable); void grey_deferred_lcd_update(void); +/* Viewports and framebuffers */ +void grey_clear_viewport(void); +void grey_set_viewport(struct viewport *vp); +void grey_viewport_set_fullscreen(struct viewport *vp, + const enum screen_type screen); +void grey_viewport_set_pos(struct viewport *vp, + int x, int y, int width, int height); +void grey_set_framebuffer(unsigned char *buffer); +void grey_framebuffer_set_pos(int x, int y, int width, int height); + /* Update functions */ void grey_update(void); void grey_update_rect(int x, int y, int width, int height); @@ -175,13 +185,23 @@ struct _grey_info unsigned char *values; /* start of greyscale pixel values */ unsigned char *phases; /* start of greyscale pixel phases */ unsigned char *buffer; /* start of chunky pixel buffer (for buffered mode) */ + unsigned char *curbuffer; /* start of current framebuffer (for buffered mode) */ + int cb_x; /* horizontal position of current framebuffer (for buffered mode) */ + int cb_y; /* vertical position of current framebuffer (for buffered mode) */ + int cb_width; /* width of current framebuffer (for buffered mode) */ + int cb_height; /* height of current framebuffer (for buffered mode) */ + int clip_l; + int clip_t; + int clip_r; + int clip_b; unsigned char gvalue[256]; /* calculated brightness -> greyvalue table */ - int fg_brightness; /* current foreground brightness */ - int bg_brightness; /* current background brightness */ - int drawmode; /* current draw mode */ - int curfont; /* current selected font */ + struct viewport *vp; /* current viewport in use */ }; +/* Stuff these here for now. LCD depth of 1 has no 'pattern' members. */ +#define _GREY_FG_BRIGHTNESS(vp) ((vp)->flags) +#define _GREY_BG_BRIGHTNESS(vp) ((vp)->line_height) + /* Global variable, defined in the plugin */ extern struct _grey_info _grey_info; diff --git a/apps/plugins/lib/grey_core.c b/apps/plugins/lib/grey_core.c index c2e0747718..047e4cc160 100644 --- a/apps/plugins/lib/grey_core.c +++ b/apps/plugins/lib/grey_core.c @@ -677,10 +677,11 @@ bool grey_init(unsigned char *gbuf, long gbuf_size, _grey_info.bheight = bdim; #endif _grey_info.flags = features & 0xff; - _grey_info.fg_brightness = 0; - _grey_info.bg_brightness = 255; - _grey_info.drawmode = DRMODE_SOLID; - _grey_info.curfont = FONT_SYSFIXED; + + /* default viewport and settings */ + grey_set_viewport(NULL); + grey_viewport_set_fullscreen(NULL, SCREEN_MAIN); + grey_set_framebuffer(NULL); /* precalculate the value -> pattern index conversion table, taking linearisation and gamma correction into account */ diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c index 3b81694426..171d2734cf 100644 --- a/apps/plugins/lib/grey_draw.c +++ b/apps/plugins/lib/grey_draw.c @@ -28,16 +28,18 @@ #include "plugin.h" #include "grey.h" +extern struct viewport _grey_default_vp; + /*** low-level drawing functions ***/ static void setpixel(unsigned char *address) { - *address = _grey_info.fg_brightness; + *address = _GREY_FG_BRIGHTNESS(_grey_info.vp); } static void clearpixel(unsigned char *address) { - *address = _grey_info.bg_brightness; + *address = _GREY_BG_BRIGHTNESS(_grey_info.vp); } static void flippixel(unsigned char *address) @@ -57,35 +59,56 @@ void (* const _grey_pixelfuncs[8])(unsigned char *address) = { /*** Drawing functions ***/ +/* Clear the current viewport */ +void grey_clear_viewport(void) +{ + struct viewport *vp = _grey_info.vp; + int drawmode = vp->drawmode; + vp->drawmode = DRMODE_SOLID | DRMODE_INVERSEVID; + grey_fillrect(0, 0, vp->width, vp->height); + vp->drawmode = drawmode; +} + /* Clear the whole display */ void grey_clear_display(void) { - int value = (_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : _grey_info.bg_brightness; + struct viewport *vp = &_grey_default_vp; - rb->memset(_grey_info.buffer, value, - _GREY_MULUQ(_grey_info.width, _grey_info.height)); + int value = (vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : _GREY_BG_BRIGHTNESS(vp); + + rb->memset(_grey_info.curbuffer, value, + _GREY_MULUQ(_grey_info.cb_width, _grey_info.cb_height)); } /* Set a single pixel */ void grey_drawpixel(int x, int y) { - if (((unsigned)x < (unsigned)_grey_info.width) - && ((unsigned)y < (unsigned)_grey_info.height)) - _grey_pixelfuncs[_grey_info.drawmode](&_grey_info.buffer[_GREY_MULUQ( - _grey_info.width, y) + x]); + if (x >= _grey_info.clip_l && x < _grey_info.clip_r && + y >= _grey_info.clip_t && y < _grey_info.clip_b) + { + int dst_stride = _grey_info.cb_width; + struct viewport *vp = _grey_info.vp; + _grey_pixelfuncs[vp->drawmode]( + &_grey_info.curbuffer[ + _GREY_MULUQ(dst_stride, vp->y - _grey_info.cb_y + y) + + vp->x - _grey_info.cb_x + x]); + } } /* Draw a line */ void grey_drawline(int x1, int y1, int x2, int y2) { + struct viewport *vp = _grey_info.vp; int numpixels; int i; int deltax, deltay; int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; - void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[_grey_info.drawmode]; + void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[vp->drawmode]; + int dwidth; + int xoffs, yoffs; deltax = abs(x2 - x1); deltay = abs(y2 - y1); @@ -127,11 +150,18 @@ void grey_drawline(int x1, int y1, int x2, int y2) x = x1; y = y1; + dwidth = _grey_info.cb_width; + xoffs = vp->x - _grey_info.cb_x; + yoffs = vp->y - _grey_info.cb_y; + for (i = 0; i < numpixels; i++) { - if (((unsigned)x < (unsigned)_grey_info.width) - && ((unsigned)y < (unsigned)_grey_info.height)) - pfunc(&_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]); + if (x >= _grey_info.clip_l && x < _grey_info.clip_r && + y >= _grey_info.clip_t && y < _grey_info.clip_b) + { + pfunc(&_grey_info.curbuffer[_GREY_MULUQ(dwidth, yoffs + y) + + xoffs + x]); + } if (d < 0) { @@ -151,10 +181,12 @@ void grey_drawline(int x1, int y1, int x2, int y2) /* Draw a horizontal line (optimised) */ void grey_hline(int x1, int x2, int y) { + struct viewport *vp = _grey_info.vp; int x; int value = 0; unsigned char *dst; bool fillopt = false; + int dwidth; /* direction flip */ if (x2 < x1) @@ -165,37 +197,40 @@ void grey_hline(int x1, int x2, int y) } /* nothing to draw? */ - if (((unsigned)y >= (unsigned)_grey_info.height) - || (x1 >= _grey_info.width) || (x2 < 0)) + if (y < _grey_info.clip_t || y >= _grey_info.clip_b || + x1 >= _grey_info.clip_r || x2 < _grey_info.clip_l) return; /* drawmode and optimisation */ - if (_grey_info.drawmode & DRMODE_INVERSEVID) + if (vp->drawmode & DRMODE_INVERSEVID) { - if (_grey_info.drawmode & DRMODE_BG) + if (vp->drawmode & DRMODE_BG) { fillopt = true; - value = _grey_info.bg_brightness; + value = _GREY_BG_BRIGHTNESS(vp); } } else { - if (_grey_info.drawmode & DRMODE_FG) + if (vp->drawmode & DRMODE_FG) { fillopt = true; - value = _grey_info.fg_brightness; + value = _GREY_FG_BRIGHTNESS(vp); } } - if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT) + if (!fillopt && vp->drawmode != DRMODE_COMPLEMENT) return; /* clipping */ - if (x1 < 0) - x1 = 0; - if (x2 >= _grey_info.width) - x2 = _grey_info.width - 1; + if (x1 < _grey_info.clip_l) + x1 = _grey_info.clip_l; + if (x2 >= _grey_info.clip_r) + x2 = _grey_info.clip_r - 1; - dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x1]; + dwidth = _grey_info.cb_width; + dst = &_grey_info.curbuffer[ + _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y) + + vp->x - _grey_info.cb_x + x1]; if (fillopt) rb->memset(dst, value, x2 - x1 + 1); @@ -211,9 +246,11 @@ void grey_hline(int x1, int x2, int y) /* Draw a vertical line (optimised) */ void grey_vline(int x, int y1, int y2) { + struct viewport *vp = _grey_info.vp; int y; unsigned char *dst, *dst_end; void (*pfunc)(unsigned char *address); + int dwidth; /* direction flip */ if (y2 < y1) @@ -224,24 +261,27 @@ void grey_vline(int x, int y1, int y2) } /* nothing to draw? */ - if (((unsigned)x >= (unsigned)_grey_info.width) - || (y1 >= _grey_info.height) || (y2 < 0)) + if (x < _grey_info.clip_l || x >= _grey_info.clip_r || + y1 >= _grey_info.clip_b || y2 < _grey_info.clip_t) return; /* clipping */ - if (y1 < 0) - y1 = 0; - if (y2 >= _grey_info.height) - y2 = _grey_info.height - 1; + if (y1 < _grey_info.clip_t) + y1 = _grey_info.clip_t; + if (y2 >= _grey_info.clip_b) + y2 = _grey_info.clip_b - 1; - pfunc = _grey_pixelfuncs[_grey_info.drawmode]; - dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y1) + x]; + dwidth = _grey_info.cb_width; + pfunc = _grey_pixelfuncs[vp->drawmode]; + dst = &_grey_info.curbuffer[ + _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y1) + + vp->x - _grey_info.cb_x + x]; - dst_end = dst + _GREY_MULUQ(_grey_info.width, y2 - y1); + dst_end = dst + _GREY_MULUQ(dwidth, y2 - y1); do { pfunc(dst); - dst += _grey_info.width; + dst += dwidth; } while (dst <= dst_end); } @@ -334,53 +374,63 @@ void grey_drawrect(int x, int y, int width, int height) /* Fill a rectangular area */ void grey_fillrect(int x, int y, int width, int height) { + struct viewport *vp = _grey_info.vp; int value = 0; unsigned char *dst, *dst_end; bool fillopt = false; - - /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) - || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) - return; + int dwidth; /* drawmode and optimisation */ - if (_grey_info.drawmode & DRMODE_INVERSEVID) + if (vp->drawmode & DRMODE_INVERSEVID) { - if (_grey_info.drawmode & DRMODE_BG) + if (vp->drawmode & DRMODE_BG) { fillopt = true; - value = _grey_info.bg_brightness; + value = _GREY_BG_BRIGHTNESS(vp); } } else { - if (_grey_info.drawmode & DRMODE_FG) + if (vp->drawmode & DRMODE_FG) { fillopt = true; - value = _grey_info.fg_brightness; + value = _GREY_FG_BRIGHTNESS(vp); + } } - if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT) + if (!fillopt && vp->drawmode != DRMODE_COMPLEMENT) return; /* clipping */ - if (x < 0) + if (x < _grey_info.clip_l) { - width += x; - x = 0; + width += x - _grey_info.clip_l; + x = _grey_info.clip_l; } - if (y < 0) + + if (x + width > _grey_info.clip_r) + width = _grey_info.clip_r - x; + + if (width <= 0) + return; + + if (y < _grey_info.clip_t) { - height += y; - y = 0; + height += y - _grey_info.clip_t; + y = _grey_info.clip_t; } - if (x + width > _grey_info.width) - width = _grey_info.width - x; - if (y + height > _grey_info.height) - height = _grey_info.height - y; + + if (y + height > _grey_info.clip_b) + height = _grey_info.clip_b - y; + + if (height <= 0) + return; - dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]; - dst_end = dst + _GREY_MULUQ(_grey_info.width, height); + dwidth = _grey_info.cb_width; + dst = &_grey_info.curbuffer[ + _GREY_MULUQ(dwidth, _grey_info.vp->y - _grey_info.cb_y + y) + + _grey_info.vp->x - _grey_info.cb_x + x]; + dst_end = dst + _GREY_MULUQ(dwidth, height); do { @@ -395,7 +445,7 @@ void grey_fillrect(int x, int y, int width, int height) *dst_row = ~(*dst_row); while (++dst_row < row_end); } - dst += _grey_info.width; + dst += dwidth; } while (dst < dst_end); } @@ -413,40 +463,49 @@ void grey_fillrect(int x, int y, int width, int height) void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, int stride, int x, int y, int width, int height) { + struct viewport *vp = _grey_info.vp; const unsigned char *src_end; unsigned char *dst, *dst_end; unsigned dmask = 0x100; /* bit 8 == sentinel */ - int drmode = _grey_info.drawmode; + int drmode = vp->drawmode; int dwidth; - /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) - || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) - return; - /* clipping */ - if (x < 0) + if (x < _grey_info.clip_l) { - width += x; - src_x -= x; - x = 0; + int dx = x - _grey_info.clip_l; + width += dx; + src_x -= dx; + x = _grey_info.clip_l; } - if (y < 0) + + if (x + width > _grey_info.clip_r) + width = _grey_info.clip_r - x; + + if (width <= 0) + return; + + if (y < _grey_info.clip_t) { - height += y; - src_y -= y; - y = 0; + int dy = y - _grey_info.clip_t; + height += dy; + src_y += dy; + y = _grey_info.clip_t; } - if (x + width > _grey_info.width) - width = _grey_info.width - x; - if (y + height > _grey_info.height) - height = _grey_info.height - y; + + if (y + height > _grey_info.clip_b) + height = _grey_info.clip_b - y; + + if (height <= 0) + return; src += _GREY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */ src_y &= 7; src_end = src + width; - dwidth = _grey_info.width; - dst = &_grey_info.buffer[_GREY_MULUQ(dwidth, y) + x]; + dwidth = _grey_info.cb_width; + dst = &_grey_info.curbuffer[ + _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y) + + vp->x - _grey_info.cb_x + x]; dst_end = dst + _GREY_MULUQ(dwidth, height); if (drmode & DRMODE_INVERSEVID) @@ -485,7 +544,7 @@ void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, break; case DRMODE_BG: - bg = _grey_info.bg_brightness; + bg = _GREY_BG_BRIGHTNESS(vp); do { if (!(data & 0x01)) @@ -498,7 +557,7 @@ void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, break; case DRMODE_FG: - fg = _grey_info.fg_brightness; + fg = _GREY_FG_BRIGHTNESS(vp); do { if (data & 0x01) @@ -511,8 +570,8 @@ void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, break; case DRMODE_SOLID: - fg = _grey_info.fg_brightness; - bg = _grey_info.bg_brightness; + fg = _GREY_FG_BRIGHTNESS(vp); + bg = _GREY_BG_BRIGHTNESS(vp); do { *dst_col = (data & 0x01) ? fg : bg; @@ -537,38 +596,48 @@ void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y, int stride, int x, int y, int width, int height) { unsigned char *dst, *dst_end; - - /* nothing to draw? */ - if ((width <= 0) || (height <= 0) || (x >= _grey_info.width) - || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0)) - return; + int dwidth; /* clipping */ - if (x < 0) + if (x < _grey_info.clip_l) { - width += x; - src_x -= x; - x = 0; + int dx = x - _grey_info.clip_l; + width += dx; + src_x -= dx; + x = _grey_info.clip_l; } + + if (x + width > _grey_info.clip_r) + width = _grey_info.clip_r - x; + + if (width <= 0) + return; + if (y < 0) { - height += y; - src_y -= y; - y = 0; + int dy = y - _grey_info.clip_t; + height += dy; + src_y -= dy; + y = _grey_info.clip_t; } - if (x + width > _grey_info.width) - width = _grey_info.width - x; - if (y + height > _grey_info.height) - height = _grey_info.height - y; - src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */ - dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x]; - dst_end = dst + _GREY_MULUQ(_grey_info.width, height); + if (y + height > _grey_info.clip_b) + height = _grey_info.clip_b - y; + + if (height <= 0) + return; + + dwidth = _grey_info.cb_width; + src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */ + dst = &_grey_info.curbuffer[ + _GREY_MULUQ(dwidth, _grey_info.vp->y - _grey_info.cb_y + y) + + _grey_info.vp->x - _grey_info.cb_x + x]; + dst_end = dst + _GREY_MULUQ(dwidth, height); do { rb->memcpy(dst, src, width); - dst += _grey_info.width; + dst += dwidth; src += stride; } while (dst < dst_end); @@ -586,11 +655,15 @@ void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str) { int ch; unsigned short *ucs; - struct font* pf = rb->font_get(_grey_info.curfont); - + struct font* pf; + + if (_grey_info.clip_b <= _grey_info.clip_t) + return; + + pf = rb->font_get(_grey_info.vp->font); ucs = rb->bidi_l2v(str, 1); - while ((ch = *ucs++) != 0 && x < _grey_info.width) + while ((ch = *ucs++) != 0 && x < _grey_info.clip_r) { int width; const unsigned char *bits; @@ -624,9 +697,10 @@ void grey_putsxy(int x, int y, const unsigned char *str) /* Clear the greyscale display (sets all pixels to white) */ void grey_ub_clear_display(void) { - int value = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : - _grey_info.bg_brightness]; + struct viewport *vp = &_grey_default_vp; + int value = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : + _GREY_BG_BRIGHTNESS(vp)]; rb->memset(_grey_info.values, value, _GREY_MULUQ(_grey_info.width, _grey_info.height)); diff --git a/apps/plugins/lib/grey_parm.c b/apps/plugins/lib/grey_parm.c index 00193e12f2..9b4ba8c5f6 100644 --- a/apps/plugins/lib/grey_parm.c +++ b/apps/plugins/lib/grey_parm.c @@ -28,6 +28,9 @@ #include "plugin.h" #include "grey.h" +/* Default greylib viewport struct */ +struct viewport _grey_default_vp; + /* Set position of the top left corner of the greyscale overlay Note that depending on the target LCD, either x or y gets rounded to the nearest multiple of 4 or 8 */ @@ -64,37 +67,37 @@ void grey_set_position(int x, int y) /* Set the draw mode for subsequent drawing operations */ void grey_set_drawmode(int mode) { - _grey_info.drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); + _grey_info.vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); } /* Return the current draw mode */ int grey_get_drawmode(void) { - return _grey_info.drawmode; + return _grey_info.vp->drawmode; } /* Set the foreground shade for subsequent drawing operations */ void grey_set_foreground(unsigned brightness) { - _grey_info.fg_brightness = brightness; + _GREY_FG_BRIGHTNESS(_grey_info.vp) = brightness; } /* Return the current foreground shade */ unsigned grey_get_foreground(void) { - return _grey_info.fg_brightness; + return _GREY_FG_BRIGHTNESS(_grey_info.vp); } /* Set the background shade for subsequent drawing operations */ void grey_set_background(unsigned brightness) { - _grey_info.bg_brightness = brightness; + _GREY_BG_BRIGHTNESS(_grey_info.vp) = brightness; } /* Return the current background shade */ unsigned grey_get_background(void) { - return _grey_info.bg_brightness; + return _GREY_BG_BRIGHTNESS(_grey_info.vp); } /* Set draw mode, foreground and background shades at once */ @@ -108,11 +111,151 @@ void grey_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) /* Set font for the text output routines */ void grey_setfont(int newfont) { - _grey_info.curfont = newfont; + _grey_info.vp->font = newfont; } /* Get width and height of a text when printed with the current font */ -int grey_getstringsize(const unsigned char *str, int *w, int *h) +int grey_getstringsize(const unsigned char *str, int *w, int *h) { - return rb->font_getstringsize(str, w, h, _grey_info.curfont); + return rb->font_getstringsize(str, w, h, _grey_info.vp->font); } + +/* Helper to establish visible area between viewport and framebuffer */ +static void grey_update_clip_rect(void) +{ + if (!(_grey_info.flags & GREY_BUFFERED)) + return; /* no chunky buffer */ + + struct viewport *vp = _grey_info.vp; + + if (!vp || !_grey_info.curbuffer) + return; + + /* Get overall intersection of framebuffer and viewport in viewport + coordinates so that later clipping of drawing is kept as simple as + possible. If l <= r and/or b <= t after intersecting, draw routines + will see this as an empty area. */ + _grey_info.clip_l = _grey_info.cb_x - vp->x; + _grey_info.clip_t = _grey_info.cb_y - vp->y; + _grey_info.clip_r = _grey_info.clip_l + _grey_info.cb_width; + _grey_info.clip_b = _grey_info.clip_t + _grey_info.cb_height; + + if (_grey_info.clip_l < 0) + _grey_info.clip_l = 0; + + if (_grey_info.clip_t < 0) + _grey_info.clip_t = 0; + + if (_grey_info.clip_r > vp->width) + _grey_info.clip_r = vp->width; + + if (_grey_info.clip_b > vp->height) + _grey_info.clip_b = vp->height; +} + +/* Set current grey viewport for draw routines */ +void grey_set_viewport(struct viewport *vp) +{ + if (vp == NULL) + vp = &_grey_default_vp; + + if (_grey_info.vp != vp) + { + _grey_info.vp = vp; + grey_update_clip_rect(); + } +} + +/* Set viewport to default settings */ +void grey_viewport_set_fullscreen(struct viewport *vp, + const enum screen_type screen) +{ + if (vp == NULL) + vp = &_grey_default_vp; + + vp->x = 0; + vp->y = 0; + vp->width = _grey_info.width; + vp->height = _grey_info.height; + _GREY_FG_BRIGHTNESS(vp) = 0; + _GREY_BG_BRIGHTNESS(vp) = 255; + vp->drawmode = DRMODE_SOLID; + vp->font = FONT_SYSFIXED; + + if (vp == _grey_info.vp) + grey_update_clip_rect(); /* is current one in use */ + + (void)screen; +} + +void grey_viewport_set_pos(struct viewport *vp, + int x, int y, int width, int height) +{ + if (vp == NULL || vp == &_grey_default_vp) + return; /* Cannot be moved or resized */ + + if (width < 0) + width = 0; /* 'tis okay */ + + if (height < 0) + height = 0; + + vp->x = x; + vp->y = y; + vp->width = width; + vp->height = height; + + if (vp == _grey_info.vp) + grey_update_clip_rect(); /* is current one in use */ +} + +/* Set current grey chunky buffer for draw routines */ +void grey_set_framebuffer(unsigned char *buffer) +{ + if (!(_grey_info.flags & GREY_BUFFERED)) + return; /* no chunky buffer */ + + if (buffer == NULL) + buffer = _grey_info.buffer; /* Default */ + + if (buffer != _grey_info.curbuffer) + { + _grey_info.curbuffer = buffer; + + if (buffer == _grey_info.buffer) + { + /* Setting to default fb resets dimensions */ + grey_framebuffer_set_pos(0, 0, 0, 0); + } + } +} + +/* Specify the dimensions of the current framebuffer */ +void grey_framebuffer_set_pos(int x, int y, int width, int height) +{ + if (!(_grey_info.flags & GREY_BUFFERED)) + return; /* no chunky buffer */ + + if (_grey_info.curbuffer == _grey_info.buffer) + { + /* This cannot be moved or resized */ + x = 0; + y = 0; + width = _grey_info.width; + height = _grey_info.height; + } + else if (width <= 0 || height <= 0) + return; + + if (x == _grey_info.cb_x && y == _grey_info.cb_y && + width == _grey_info.cb_width && height == _grey_info.cb_height) + return; /* No change */ + + _grey_info.cb_x = x; + _grey_info.cb_y = y; + _grey_info.cb_width = width; + _grey_info.cb_height = height; + + grey_update_clip_rect(); +} + diff --git a/apps/plugins/lib/grey_scroll.c b/apps/plugins/lib/grey_scroll.c index 35f73b70c4..78e5725d05 100644 --- a/apps/plugins/lib/grey_scroll.c +++ b/apps/plugins/lib/grey_scroll.c @@ -28,11 +28,14 @@ #include "plugin.h" #include "grey.h" +extern struct viewport _grey_default_vp; + /*** Scrolling ***/ /* Scroll left */ void grey_scroll_left(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *data, *data_end; int length, blank; @@ -45,8 +48,8 @@ void grey_scroll_left(int count) data = _grey_info.buffer; data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); length = _grey_info.width - count; - blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : _grey_info.bg_brightness; + blank = (vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : _GREY_BG_BRIGHTNESS(vp); do { @@ -61,6 +64,7 @@ void grey_scroll_left(int count) /* Scroll right */ void grey_scroll_right(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *data, *data_end; int length, blank; @@ -73,8 +77,8 @@ void grey_scroll_right(int count) data = _grey_info.buffer; data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); length = _grey_info.width - count; - blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : _grey_info.bg_brightness; + blank = (vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : _GREY_BG_BRIGHTNESS(vp); do { @@ -88,6 +92,7 @@ void grey_scroll_right(int count) /* Scroll up */ void grey_scroll_up(int count) { + struct viewport *vp = &_grey_default_vp; long shift, length; int blank; @@ -99,8 +104,8 @@ void grey_scroll_up(int count) shift = _GREY_MULUQ(_grey_info.width, count); length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count); - blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : _grey_info.bg_brightness; + blank = (vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : _GREY_BG_BRIGHTNESS(vp); rb->memmove(_grey_info.buffer, _grey_info.buffer + shift, length); @@ -110,6 +115,7 @@ void grey_scroll_up(int count) /* Scroll down */ void grey_scroll_down(int count) { + struct viewport *vp = &_grey_default_vp; long shift, length; int blank; @@ -121,8 +127,8 @@ void grey_scroll_down(int count) shift = _GREY_MULUQ(_grey_info.width, count); length = _GREY_MULUQ(_grey_info.width, _grey_info.height - count); - blank = (_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : _grey_info.bg_brightness; + blank = (vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : _GREY_BG_BRIGHTNESS(vp); rb->memmove(_grey_info.buffer + shift, _grey_info.buffer, length); @@ -134,6 +140,7 @@ void grey_scroll_down(int count) /* Scroll left */ void grey_ub_scroll_left(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *data, *data_end; int blank, length; @@ -147,9 +154,9 @@ void grey_ub_scroll_left(int count) data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); length = (_grey_info.width - count) << _GREY_BSHIFT; count <<= _GREY_BSHIFT; - blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : - _grey_info.bg_brightness]; + blank = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : + _GREY_BG_BRIGHTNESS(vp)]; do { rb->memmove(data, data + count, length); @@ -167,6 +174,7 @@ void grey_ub_scroll_left(int count) /* Scroll right */ void grey_ub_scroll_right(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *data, *data_end; int blank, length; @@ -180,9 +188,9 @@ void grey_ub_scroll_right(int count) data_end = data + _GREY_MULUQ(_grey_info.width, _grey_info.height); length = (_grey_info.width - count) << _GREY_BSHIFT; count <<= _GREY_BSHIFT; - blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : - _grey_info.bg_brightness]; + blank = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : + _GREY_BG_BRIGHTNESS(vp)]; do { rb->memmove(data + count, data, length); @@ -199,6 +207,7 @@ void grey_ub_scroll_right(int count) /* Scroll up */ void grey_ub_scroll_up(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *dst, *end, *src; int blank; @@ -210,9 +219,9 @@ void grey_ub_scroll_up(int count) dst = _grey_info.values; end = dst + _GREY_MULUQ(_grey_info.height, _grey_info.width); - blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : - _grey_info.bg_brightness]; + blank = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : + _GREY_BG_BRIGHTNESS(vp)]; #if (LCD_PIXELFORMAT == VERTICAL_PACKING) \ || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) @@ -274,6 +283,7 @@ void grey_ub_scroll_up(int count) /* Scroll down */ void grey_ub_scroll_down(int count) { + struct viewport *vp = &_grey_default_vp; unsigned char *start, *dst; int blank; @@ -285,9 +295,9 @@ void grey_ub_scroll_down(int count) start = _grey_info.values; dst = start + _GREY_MULUQ(_grey_info.height, _grey_info.width); - blank = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ? - _grey_info.fg_brightness : - _grey_info.bg_brightness]; + blank = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ? + _GREY_FG_BRIGHTNESS(vp) : + _GREY_BG_BRIGHTNESS(vp)]; #if (LCD_PIXELFORMAT == VERTICAL_PACKING) \ || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) diff --git a/apps/plugins/lib/mylcd.h b/apps/plugins/lib/mylcd.h index 48e8ca1d47..e363111c71 100644 --- a/apps/plugins/lib/mylcd.h +++ b/apps/plugins/lib/mylcd.h @@ -40,12 +40,13 @@ #define mylcd_(fn) pgfx_##fn #define mylcd_ub_(fn) pgfx_##fn -#elif defined (HAVE_LCD_BITMAP) && (LCD_DEPTH < 8) && defined(__GREY_H__) +#elif defined (HAVE_LCD_BITMAP) && (LCD_DEPTH < 4) && defined(__GREY_H__) #define MYLCD_CFG_GREYLIB /* using greylib */ #define mylcd_(fn) grey_##fn #define myxlcd_(fn) grey_##fn #define mylcd_ub_(fn) grey_ub_##fn #define myxlcd_ub_(fn) grey_ub_##fn +#define mylcd_viewport_(fn) grey_viewport_##fn /* Common colors */ #define MYLCD_BLACK GREY_BLACK @@ -61,6 +62,7 @@ #define myxlcd_(fn) xlcd_##fn #define mylcd_ub_(fn) rb->lcd_##fn #define myxlcd_ub_(fn) xlcd_##fn +#define mylcd_viewport_(fn) rb->viewport_##fn /* Common colors */ #define MYLCD_BLACK LCD_BLACK @@ -180,4 +182,11 @@ static inline void mylcd_ub_update_rect(int x, int y, int w, int h) #define mylcd_ub_scroll_down myxlcd_ub_(scroll_down) #endif /* HAVE_LCD_BITMAP */ +/* Viewports */ +#ifdef HAVE_LCD_BITMAP +#define mylcd_clear_viewport mylcd_(clear_viewport) +#define mylcd_set_viewport mylcd_(set_viewport) +#define mylcd_viewport_set_fullscreen mylcd_viewport_(set_fullscreen) +#endif /* HAVE_LCD_BITMAP */ + #endif /* MYLCD_H */ diff --git a/apps/plugins/lib/osd.c b/apps/plugins/lib/osd.c index ff0533a898..598a76759c 100644 --- a/apps/plugins/lib/osd.c +++ b/apps/plugins/lib/osd.c @@ -21,6 +21,7 @@ * ****************************************************************************/ #include "plugin.h" +#include "grey.h" #include "osd.h" #if 1 @@ -28,10 +29,20 @@ #define DEBUGF(...) #endif +#if defined(SIMULATOR) && LCD_DEPTH < 4 +/* Sim isn't using --ffunction-sections thus greylib references will happen + here even if not using this with greylib on a grayscale display, which + demands that a struct _grey_info exist. */ +#ifndef _WIN32 +__attribute__((weak)) +#endif /* _WIN32 */ + struct _grey_info _grey_info; +#endif /* defined(SIMULATOR) && LCD_DEPTH < 4 */ + /* At this time: assumes use of the default viewport for normal drawing */ /* If multiple OSD's are wanted, could convert to caller-allocated */ -static struct osd +struct osd { enum osd_status { @@ -41,152 +52,314 @@ static struct osd OSD_ERASED, /* Erased in preparation for regular drawing */ } status; /* View status */ struct viewport vp; /* Clipping viewport */ - struct bitmap lcd_bitmap; /* The main LCD fb bitmap */ - struct bitmap back_bitmap; /* The OSD backbuffer fb bitmap */ + int lcd_bitmap_stride; /* Stride of LCD bitmap */ + void *lcd_bitmap_data; /* Backbuffer framebuffer data */ + int back_bitmap_stride; /* Stride of backbuffer bitmap */ + void *back_bitmap_data; /* LCD framebuffer data */ int maxwidth; /* How wide may it be at most? */ int maxheight; /* How high may it be at most? */ long timeout; /* Current popup stay duration */ long hide_tick; /* Tick when it should be hidden */ osd_draw_cb_fn_t draw_cb; /* Draw update callback */ -} osd; + /* Functions to factilitate interface compatibility of OSD types */ + void * (*init_buffers)(struct osd *osd, unsigned flags, void *buf, + size_t *bufsize); + void (*set_viewport_pos)(struct viewport *vp, int x, int y, int width, + int height); + void (*lcd_update)(void); + void (*lcd_update_rect)(int x, int y, int width, int height); + void (*lcd_set_viewport)(struct viewport *vp); + void (*lcd_set_framebuffer)(void *buf); + void (*lcd_framebuffer_set_pos)(int x, int y, int width, int height); + void (*lcd_bitmap_part)(const void *src, int src_x, int src_y, + int stride, int x, int y, int width, int height); +}; + +static struct osd native_osd; +#if LCD_DEPTH < 4 +static struct osd grey_osd; +#endif /* Framebuffer allocation macros */ #if LCD_DEPTH == 1 # if LCD_PIXELFORMAT == HORIZONTAL_PACKING -# define LCD_WIDTH2BYTES(w) (((w)+7)/8) -# define LCD_BYTES2WIDTH(b) ((b)*8) +# define _OSD_WIDTH2BYTES(w) (((w)+7)/8) +# define _OSD_BYTES2WIDTH(b) ((b)*8) # elif LCD_PIXELFORMAT == VERTICAL_PACKING -# define LCD_HEIGHT2BYTES(h) (((h)+7)/8) -# define LCD_BYTES2HEIGHT(b) ((b)*8) +# define _OSD_HEIGHT2BYTES(h) (((h)+7)/8) +# define _OSD_BYTES2HEIGHT(b) ((b)*8) # else # error Unknown 1-bit format; please define macros # endif /* LCD_PIXELFORMAT */ #elif LCD_DEPTH == 2 # if LCD_PIXELFORMAT == HORIZONTAL_PACKING -# define LCD_WIDTH2BYTES(w) (((w)+3)/4) -# define LCD_BYTES2WIDTH(b) ((b)*4) +# define _OSD_WIDTH2BYTES(w) (((w)+3)/4) +# define _OSD_BYTES2WIDTH(b) ((b)*4) # elif LCD_PIXELFORMAT == VERTICAL_PACKING -# define LCD_HEIGHT2BYTES(h) (((h)+3)/4) -# define LCD_BYTES2HEIGHT(b) ((b)*4) +# define _OSD_HEIGHT2BYTES(h) (((h)+3)/4) +# define _OSD_BYTES2HEIGHT(b) ((b)*4) # elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED -# define LCD_WIDTH2BYTES(w) ((w)*2) -# define LCD_BYTES2WIDTH(b) ((b)/2) -# define LCD_HEIGHT2BYTES(h) (((h)+7)/8*2) -# define LCD_BYTES2HEIGHT(b) ((b)/2*8) +# define _OSD_HEIGHT2BYTES(h) (((h)+7)/8*2) +# define _OSD_BYTES2HEIGHT(b) ((b)/2*8) # else # error Unknown 2-bit format; please define macros # endif /* LCD_PIXELFORMAT */ #elif LCD_DEPTH == 16 -# define LCD_WIDTH2BYTES(w) ((w)*2) -# define LCD_BYTES2WIDTH(b) ((b)/2) -#else +# if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +# define _OSD_HEIGHT2BYTES(h) ((h)*2) +# define _OSD_BYTES2HEIGHT(b) ((b)/2) +# else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */ +# define _OSD_WIDTH2BYTES(w) ((w)*2) +# define _OSD_BYTES2WIDTH(b) ((b)/2) +# endif /* end stride type selection */ +#else /* other LCD depth */ # error Unknown LCD depth; please define macros #endif /* LCD_DEPTH */ -/* Set defaults if not defined different yet. */ -#ifndef LCD_WIDTH2BYTES -# define LCD_WIDTH2BYTES(w) (w) +/* Set defaults if not defined differently */ +#ifndef _OSD_WIDTH2BYTES +# define _OSD_WIDTH2BYTES(w) (w) #endif -#ifndef LCD_BYTES2WIDTH -# define LCD_BYTES2WIDTH(b) (b) +#ifndef _OSD_BYTES2WIDTH +# define _OSD_BYTES2WIDTH(b) (b) #endif -#ifndef LCD_HEIGHT2BYTES -# define LCD_HEIGHT2BYTES(h) (h) +#ifndef _OSD_HEIGHT2BYTES +# define _OSD_HEIGHT2BYTES(h) (h) #endif -#ifndef LCD_BYTES2HEIGHT -# define LCD_BYTES2HEIGHT(b) (b) +#ifndef _OSD_BYTES2HEIGHT +# define _OSD_BYTES2HEIGHT(b) (b) +#endif +#ifndef _OSD_BUFSIZE +# define _OSD_BUFSIZE(w, h) (_OSD_WIDTH2BYTES(w)*_OSD_HEIGHT2BYTES(h)) #endif +static void _osd_destroy(struct osd *osd); +static bool _osd_show(struct osd *osd, unsigned flags); + + +/** Native LCD routines **/ + /* Create a bitmap framebuffer from a buffer */ -static fb_data * buf_to_fb_bitmap(void *buf, size_t bufsize, - int *width, int *height) +static void * _osd_lcd_init_buffers(struct osd *osd, unsigned flags, + void *buf, size_t *bufsize) { /* Used as dest, the LCD functions cannot deal with alternate strides as of now - the stride guides the calulations. If that is no longer the case, then width or height can be used instead (and less memory needed for a small surface!). + IOW: crappiness means one dimension is non-negotiable. */ - DEBUGF("buf: %p bufsize: %lu\n", buf, (unsigned long)bufsize); + DEBUGF("OSD: in(buf=%p bufsize=%lu)\n", buf, + (unsigned long)*bufsize); + + rb->viewport_set_fullscreen(&osd->vp, SCREEN_MAIN); #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE - int h = LCD_BYTES2HEIGHT(LCD_HEIGHT2BYTES(LCD_HEIGHT)); - int w = bufsize / LCD_HEIGHT2BYTES(h); + int colbytes = _OSD_HEIGHT2BYTES(LCD_HEIGHT); + int bytecols = *bufsize / colbytes; + int w = _OSD_BYTES2WIDTH(bytecols); + int h = _OSD_BYTES2HEIGHT(colbytes); - if (w == 0) + if (flags & OSD_INIT_MAJOR_HEIGHT) { - DEBUGF("OSD: not enough buffer\n"); - return NULL; /* not enough buffer */ - } -#else - int w = LCD_BYTES2WIDTH(LCD_WIDTH2BYTES(LCD_WIDTH)); - int h = bufsize / LCD_WIDTH2BYTES(w); + if (w == 0 || ((flags & OSD_INIT_MINOR_MIN) && w < osd->maxwidth)) + { + DEBUGF("OSD: not enough buffer\n"); + return NULL; /* not enough buffer */ + } - if (h == 0) + if ((flags & OSD_INIT_MINOR_MAX) && w > osd->maxwidth) + w = osd->maxwidth; + } + else /* OSD_INIT_MAJOR_WIDTH implied */ { - DEBUGF("OSD: not enough buffer\n"); - return NULL; /* not enough buffer */ + if (w == 0 || w < osd->maxwidth) + { + DEBUGF("OSD: not enough buffer\n"); + return NULL; /* not enough buffer */ + } + else if (w > osd->maxwidth) + { + w = osd->maxwidth; + } } -#endif - DEBUGF("fbw:%d fbh:%d\n", w, h); + w = _OSD_BYTES2WIDTH(_OSD_WIDTH2BYTES(w)); + osd->lcd_bitmap_stride = _OSD_BYTES2HEIGHT(_OSD_HEIGHT2BYTES(LCD_HEIGHT)); + osd->back_bitmap_stride = h; +#else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */ + int rowbytes = _OSD_WIDTH2BYTES(LCD_WIDTH); + int byterows = *bufsize / rowbytes; + int w = _OSD_BYTES2WIDTH(rowbytes); + int h = _OSD_BYTES2HEIGHT(byterows); - *width = w; - *height = h; - - return (fb_data *)buf; + if (flags & OSD_INIT_MAJOR_HEIGHT) + { + if (h == 0 || h < osd->maxheight) + { + DEBUGF("OSD: not enough buffer\n"); + return NULL; + } + else if (h > osd->maxheight) + { + h = osd->maxheight; + } + } + else /* OSD_INIT_MAJOR_WIDTH implied */ + { + if (h == 0 || ((flags & OSD_INIT_MINOR_MIN) && h < osd->maxheight)) + { + DEBUGF("OSD: not enough buffer\n"); + return NULL; + } + + if ((flags & OSD_INIT_MINOR_MAX) && h > osd->maxheight) + h = osd->maxheight; + } + + h = _OSD_BYTES2HEIGHT(_OSD_HEIGHT2BYTES(h)); + osd->lcd_bitmap_stride = _OSD_BYTES2WIDTH(_OSD_WIDTH2BYTES(LCD_WIDTH)); + osd->back_bitmap_stride = w; +#endif /* end stride type selection */ + + osd->lcd_bitmap_data = (void *)rb->lcd_framebuffer; + osd->back_bitmap_data = buf; + + osd->maxwidth = w; + osd->maxheight = h; + *bufsize = _OSD_BUFSIZE(w, h); + + DEBUGF("OSD: addr(fb=%p bb=%p)\n", osd->lcd_bitmap_data, + osd->back_bitmap_data); + DEBUGF("OSD: w=%d h=%d bufsz=%lu\n", w, h, (unsigned long)*bufsize); + + return buf; } -static inline void osd_set_vp_pos(int x, int y, int width, int height) +/* Set viewport coordinates */ +static void _osd_lcd_viewport_set_pos( + struct viewport *vp, int x, int y, int width, int height) { - osd.vp.x = x; - osd.vp.y = y; - osd.vp.width = width; - osd.vp.height = height; + vp->x = x; + vp->y = y; + vp->width = width; + vp->height = height; } -/* Sync the backbuffer to the on-screen image */ -static void osd_lcd_update_back_buffer(void) -{ - rb->lcd_set_framebuffer((fb_data *)osd.back_bitmap.data); - rb->lcd_bmp_part(&osd.lcd_bitmap, osd.vp.x, osd.vp.y, - 0, 0, osd.vp.width, osd.vp.height); - /* Assume it was on default framebuffer for now */ - rb->lcd_set_framebuffer(NULL); -} -/* Erase the OSD to restore the framebuffer */ -static void osd_lcd_erase(void) +#if LCD_DEPTH < 4 +/** Greylib LCD routines **/ + +/* Create a greylib bitmap framebuffer from a buffer */ +static void * _osd_grey_init_buffers(struct osd *osd, unsigned flags, + void *buf, size_t *bufsize) { - rb->lcd_bmp_part(&osd.back_bitmap, 0, 0, osd.vp.x, osd.vp.y, - osd.vp.width, osd.vp.height); + int w, h; + + DEBUGF("OSD (grey): in(buf=%p bufsize=%lu)\n", buf, + (unsigned long)*bufsize); + + grey_viewport_set_fullscreen(&osd->vp, SCREEN_MAIN); + + if (flags & OSD_INIT_MAJOR_HEIGHT) + { + h = osd->maxheight; + w = *bufsize / h; + + if (w == 0 || ((flags & OSD_INIT_MINOR_MIN) && w < osd->maxwidth)) + { + DEBUGF("OSD (grey): Not enough buffer\n"); + return NULL; + } + + if ((flags & OSD_INIT_MINOR_MAX) && w > osd->maxwidth) + w = osd->maxwidth; + } + else /* OSD_INIT_MAJOR_WIDTH implied */ + { + w = osd->maxwidth; + h = *bufsize / w; + + if (h == 0 || ((flags & OSD_INIT_MINOR_MIN) && h < osd->maxheight)) + { + DEBUGF("OSD (grey): Not enough buffer\n"); + return NULL; + } + + if ((flags & OSD_INIT_MINOR_MAX) && h > osd->maxheight) + h = osd->maxheight; + } + + /* Have to peek into _grey_info a bit */ + osd->lcd_bitmap_stride = _grey_info.width; + osd->lcd_bitmap_data = _grey_info.buffer; + osd->back_bitmap_stride = w; + osd->back_bitmap_data = buf; + + osd->maxwidth = w; + osd->maxheight = h; + *bufsize = w * h; + + DEBUGF("OSD (grey): addr(fb=%p bb=%p)\n", osd->lcd_bitmap_data, + osd->back_bitmap_data); + DEBUGF("OSD (grey): w=%d h=%d bufsz=%lu\n", w, h, (unsigned long)*bufsize); + + return buf; } +#endif /* LCD_DEPTH < 4*/ + + +/** Common LCD routines **/ /* Draw the OSD image portion using the callback */ -static void osd_lcd_draw_rect(int x, int y, int width, int height) +static void _osd_draw_osd_rect(struct osd *osd, int x, int y, + int width, int height) { - rb->lcd_set_viewport(&osd.vp); - osd.draw_cb(x, y, width, height); - rb->lcd_set_viewport(NULL); + osd->lcd_set_viewport(&osd->vp); + osd->draw_cb(x, y, width, height); + osd->lcd_set_viewport(NULL); } /* Draw the OSD image using the callback */ -static void osd_lcd_draw(void) +static void _osd_draw_osd(struct osd *osd) { - osd_lcd_draw_rect(0, 0, osd.vp.width, osd.vp.height); + _osd_draw_osd_rect(osd, 0, 0, osd->vp.width, osd->vp.height); } +static void _osd_update_viewport(struct osd *osd) +{ + osd->lcd_update_rect(osd->vp.x, osd->vp.y, osd->vp.width, + osd->vp.height); +} -/** Public APIs **/ +/* Sync the backbuffer to the framebuffer image */ +static void _osd_update_back_buffer(struct osd *osd) +{ + /* Assume it's starting with default viewport for now */ + osd->lcd_set_framebuffer(osd->back_bitmap_data); +#if LCD_DEPTH < 4 + if (osd->lcd_framebuffer_set_pos) + osd->lcd_framebuffer_set_pos(0, 0, osd->maxwidth, osd->maxheight); +#endif /* LCD_DEPTH < 4 */ + osd->lcd_bitmap_part(osd->lcd_bitmap_data, osd->vp.x, osd->vp.y, + osd->lcd_bitmap_stride, 0, 0, osd->vp.width, + osd->vp.height); + /* Assume it was on default framebuffer for now */ + osd->lcd_set_framebuffer(NULL); +} + +/* Erase the OSD to restore the framebuffer image */ +static void _osd_erase_osd(struct osd *osd) +{ + osd->lcd_bitmap_part(osd->back_bitmap_data, 0, 0, osd->back_bitmap_stride, + osd->vp.x, osd->vp.y, osd->vp.width, osd->vp.height); +} /* Initialized the OSD and set its backbuffer */ -bool osd_init(void *backbuf, size_t backbuf_size, - osd_draw_cb_fn_t draw_cb) +static bool _osd_init(struct osd *osd, unsigned flags, void *backbuf, + size_t backbuf_size, osd_draw_cb_fn_t draw_cb, + int *width, int *height, size_t *bufused) { - osd_show(OSD_HIDE); - - osd.status = OSD_DISABLED; /* Disabled unless all is okay */ - osd_set_vp_pos(0, 0, 0, 0); - osd.maxwidth = osd.maxheight = 0; - osd.timeout = 0; + _osd_destroy(osd); if (!draw_cb) return false; @@ -194,95 +367,133 @@ bool osd_init(void *backbuf, size_t backbuf_size, if (!backbuf) return false; - ALIGN_BUFFER(backbuf, backbuf_size, FB_DATA_SZ); + void *backbuf_orig = backbuf; /* Save in case of ptr advance */ + ALIGN_BUFFER(backbuf, backbuf_size, MAX(FB_DATA_SZ, 4)); if (!backbuf_size) return false; - rb->viewport_set_fullscreen(&osd.vp, SCREEN_MAIN); + if (flags & OSD_INIT_MAJOR_HEIGHT) + { + if (!height || *height <= 0) + return false; - fb_data *backfb = buf_to_fb_bitmap(backbuf, backbuf_size, - &osd.maxwidth, &osd.maxheight); + if ((flags & (OSD_INIT_MINOR_MIN | OSD_INIT_MINOR_MAX)) && + (!width || *width <= 0)) + { + return false; + } + } + else + { + if (!width || *width <= 0) + return false; - if (!backfb) + if ((flags & (OSD_INIT_MINOR_MIN | OSD_INIT_MINOR_MAX)) && + (!height || *height <= 0)) + { + return false; + } + } + + /* Store requested sizes in max(width|height) */ + if (width) + osd->maxwidth = *width; + else + osd->maxwidth = LCD_WIDTH; + + if (height) + osd->maxheight = *height; + else + osd->maxheight = LCD_HEIGHT; + + if (!osd->init_buffers(osd, flags, backbuf, &backbuf_size)) + { + osd->maxwidth = osd->maxheight = 0; return false; + } - osd.draw_cb = draw_cb; + osd->draw_cb = draw_cb; - /* LCD framebuffer bitmap */ - osd.lcd_bitmap.width = LCD_BYTES2WIDTH(LCD_WIDTH2BYTES(LCD_WIDTH)); - osd.lcd_bitmap.height = LCD_BYTES2HEIGHT(LCD_HEIGHT2BYTES(LCD_HEIGHT)); -#if LCD_DEPTH > 1 - osd.lcd_bitmap.format = FORMAT_NATIVE; - osd.lcd_bitmap.maskdata = NULL; -#endif -#ifdef HAVE_LCD_COLOR - osd.lcd_bitmap.alpha_offset = 0; -#endif - osd.lcd_bitmap.data = (void *)rb->lcd_framebuffer; + if (bufused) + *bufused = backbuf_size + (backbuf_orig - backbuf); - /* Backbuffer bitmap */ - osd.back_bitmap.width = osd.maxwidth; - osd.back_bitmap.height = osd.maxheight; -#if LCD_DEPTH > 1 - osd.back_bitmap.format = FORMAT_NATIVE; - osd.back_bitmap.maskdata = NULL; -#endif -#ifdef HAVE_LCD_COLOR - osd.back_bitmap.alpha_offset = 0; -#endif - osd.back_bitmap.data = (void *)backfb; + if (width) + *width = osd->maxwidth; - DEBUGF("FB:%p BB:%p\n", osd.lcd_bitmap.data, osd.back_bitmap.data); + if (height) + *height = osd->maxheight; /* Set the default position to the whole thing */ - osd_set_vp_pos(0, 0, osd.maxwidth, osd.maxheight); + osd->set_viewport_pos(&osd->vp, 0, 0, osd->maxwidth, osd->maxheight); - osd.status = OSD_HIDDEN; /* Ready when you are */ + osd->status = OSD_HIDDEN; /* Ready when you are */ + + return true; +} + +static void _osd_destroy(struct osd *osd) +{ + _osd_show(osd, OSD_HIDE); + + /* Set to essential defaults */ + osd->status = OSD_DISABLED; + osd->set_viewport_pos(&osd->vp, 0, 0, 0, 0); + osd->maxwidth = osd->maxheight = 0; + osd->timeout = 0; +} + +/* Redraw the entire OSD */ +static bool _osd_update(struct osd *osd) +{ + if (osd->status != OSD_VISIBLE) + return false; + + _osd_draw_osd(osd); + _osd_update_viewport(osd); return true; } /* Show/Hide the OSD on screen */ -bool osd_show(unsigned flags) +static bool _osd_show(struct osd *osd, unsigned flags) { if (flags & OSD_SHOW) { - switch (osd.status) + switch (osd->status) { case OSD_DISABLED: break; /* No change */ case OSD_HIDDEN: - osd_lcd_update_back_buffer(); - osd.status = OSD_VISIBLE; - osd_update(); - osd.hide_tick = *rb->current_tick + osd.timeout; + _osd_update_back_buffer(osd); + osd->status = OSD_VISIBLE; + _osd_update(osd); + osd->hide_tick = *rb->current_tick + osd->timeout; break; case OSD_VISIBLE: if (flags & OSD_UPDATENOW) - osd_update(); + _osd_update(osd); /* Fall-through */ case OSD_ERASED: - osd.hide_tick = *rb->current_tick + osd.timeout; + osd->hide_tick = *rb->current_tick + osd->timeout; return true; } } else { - switch (osd.status) + switch (osd->status) { case OSD_DISABLED: case OSD_HIDDEN: break; case OSD_VISIBLE: - osd_lcd_erase(); - rb->lcd_update_rect(osd.vp.x, osd.vp.y, osd.vp.width, - osd.vp.height); + _osd_erase_osd(osd); + _osd_update_viewport(osd); /* Fall-through */ case OSD_ERASED: - osd.status = OSD_HIDDEN; + osd->status = OSD_HIDDEN; return true; } } @@ -290,30 +501,20 @@ bool osd_show(unsigned flags) return false; } -/* Redraw the entire OSD */ -bool osd_update(void) -{ - if (osd.status != OSD_VISIBLE) - return false; - - osd_lcd_draw(); - - rb->lcd_update_rect(osd.vp.x, osd.vp.y, osd.vp.width, - osd.vp.height); - - return true; -} - /* Redraw part of the OSD (viewport-relative coordinates) */ -bool osd_update_rect(int x, int y, int width, int height) +static bool _osd_update_rect(struct osd *osd, int x, int y, int width, + int height) { - if (osd.status != OSD_VISIBLE) + if (osd->status != OSD_VISIBLE) return false; - osd_lcd_draw_rect(x, y, width, height); + _osd_draw_osd_rect(osd, x, y, width, height); - if (x + width > osd.vp.width) - width = osd.vp.width - x; + int vp_x = osd->vp.x; + int vp_w = osd->vp.width; + + if (x + width > vp_w) + width = vp_w - x; if (x < 0) { @@ -324,8 +525,11 @@ bool osd_update_rect(int x, int y, int width, int height) if (width <= 0) return false; - if (y + height > osd.vp.height) - height = osd.vp.height - y; + int vp_y = osd->vp.y; + int vp_h = osd->vp.height; + + if (y + height > vp_h) + height = vp_h - y; if (y < 0) { @@ -336,135 +540,313 @@ bool osd_update_rect(int x, int y, int width, int height) if (height <= 0) return false; - rb->lcd_update_rect(osd.vp.x + x, osd.vp.y + y, width, height); + osd->lcd_update_rect(vp_x + x, vp_y + y, width, height); return true; } /* Set a new screen location and size (screen coordinates) */ -bool osd_update_pos(int x, int y, int width, int height) +static bool _osd_update_pos(struct osd *osd, int x, int y, int width, + int height) { - if (osd.status == OSD_DISABLED) + if (osd->status == OSD_DISABLED) return false; if (width < 0) width = 0; - else if (width > osd.maxwidth) - width = osd.maxwidth; + else if (width > osd->maxwidth) + width = osd->maxwidth; if (height < 0) height = 0; - else if (height > osd.maxheight) - height = osd.maxheight; + else if (height > osd->maxheight) + height = osd->maxheight; - if (x == osd.vp.x && y == osd.vp.y && - width == osd.vp.width && height == osd.vp.height) + int vp_x = osd->vp.x; + int vp_y = osd->vp.y; + int vp_w = osd->vp.width; + int vp_h = osd->vp.height; + + if (x == vp_x && y == vp_y && width == vp_w && height == vp_h) return false; /* No change */ - if (osd.status != OSD_VISIBLE) + if (osd->status != OSD_VISIBLE) { /* Not visible - just update pos */ - osd_set_vp_pos(x, y, width, height); + osd->set_viewport_pos(&osd->vp, x, y, width, height); return false; } /* Visible area has changed */ - osd_lcd_erase(); + _osd_erase_osd(osd); /* Update the smallest rectangle that encloses both the old and new regions to make the change free of flicker (they may overlap) */ - int xu = MIN(osd.vp.x, x); - int yu = MIN(osd.vp.y, y); - int wu = MAX(osd.vp.x + osd.vp.width, x + width) - xu; - int hu = MAX(osd.vp.y + osd.vp.height, y + height) - yu; + int xu = MIN(vp_x, x); + int yu = MIN(vp_y, y); + int wu = MAX(vp_x + vp_w, x + width) - xu; + int hu = MAX(vp_y + vp_h, y + height) - yu; - osd_set_vp_pos(x, y, width, height); - osd_lcd_update_back_buffer(); - osd_lcd_draw(); + osd->set_viewport_pos(&osd->vp, x, y, width, height); + _osd_update_back_buffer(osd); + _osd_draw_osd(osd); + osd->lcd_update_rect(xu, yu, wu, hu); - rb->lcd_update_rect(xu, yu, wu, hu); return true; } /* Call periodically to have the OSD timeout and hide itself */ -void osd_monitor_timeout(void) +static void _osd_monitor_timeout(struct osd *osd) { - if (osd.status <= OSD_HIDDEN) + if (osd->status <= OSD_HIDDEN) return; /* Already hidden/disabled */ - if (osd.timeout > 0 && TIME_AFTER(*rb->current_tick, osd.hide_tick)) - osd_show(OSD_HIDE); + if (osd->timeout > 0 && TIME_AFTER(*rb->current_tick, osd->hide_tick)) + _osd_show(osd, OSD_HIDE); } /* Set the OSD timeout value. <= 0 = never timeout */ -void osd_set_timeout(long timeout) +static void _osd_set_timeout(struct osd *osd, long timeout) { - if (osd.status == OSD_DISABLED) + if (osd->status == OSD_DISABLED) return; - osd.timeout = timeout; - osd_monitor_timeout(); + osd->timeout = timeout; + _osd_monitor_timeout(osd); } /* Use the OSD viewport context */ -struct viewport * osd_get_viewport(void) +static inline struct viewport * _osd_get_viewport(struct osd *osd) { - return &osd.vp; + return &osd->vp; } /* Get the maximum dimensions calculated by osd_init() */ -void osd_get_max_dims(int *maxwidth, int *maxheight) +static void _osd_get_max_dims(struct osd *osd, + int *maxwidth, int *maxheight) { if (maxwidth) - *maxwidth = osd.maxwidth; + *maxwidth = osd->maxwidth; if (maxheight) - *maxheight = osd.maxheight; + *maxheight = osd->maxheight; } /* Is the OSD enabled? */ -bool osd_enabled(void) +static inline bool _osd_enabled(struct osd *osd) { - return osd.status != OSD_DISABLED; + return osd->status != OSD_DISABLED; } /** LCD update substitutes **/ /* Prepare LCD framebuffer for regular drawing */ -void osd_lcd_update_prepare(void) +static inline void _osd_lcd_update_prepare(struct osd *osd) { - if (osd.status == OSD_VISIBLE) + if (osd->status == OSD_VISIBLE) { - osd.status = OSD_ERASED; - osd_lcd_erase(); + osd->status = OSD_ERASED; + _osd_erase_osd(osd); } } /* Update the whole screen */ -void osd_lcd_update(void) +static inline void _osd_lcd_update(struct osd *osd) { - if (osd.status == OSD_ERASED) + if (osd->status == OSD_ERASED) { /* Save the screen image underneath and restore the OSD image */ - osd.status = OSD_VISIBLE; - osd_lcd_update_back_buffer(); - osd_lcd_draw(); + osd->status = OSD_VISIBLE; + _osd_update_back_buffer(osd); + _osd_draw_osd(osd); } - rb->lcd_update(); + osd->lcd_update(); } /* Update a part of the screen */ -void osd_lcd_update_rect(int x, int y, int width, int height) +static void _osd_lcd_update_rect(struct osd *osd, + int x, int y, int width, int height) { - if (osd.status == OSD_ERASED) + if (osd->status == OSD_ERASED) { /* Save the screen image underneath and restore the OSD image */ - osd.status = OSD_VISIBLE; - osd_lcd_update_back_buffer(); - osd_lcd_draw(); + osd->status = OSD_VISIBLE; + _osd_update_back_buffer(osd); + _osd_draw_osd(osd); } - rb->lcd_update_rect(x, y, width, height); + osd->lcd_update_rect(x, y, width, height); } + +/* Native LCD, public */ +bool osd_init(unsigned flags, void *backbuf, size_t backbuf_size, + osd_draw_cb_fn_t draw_cb, int *width, int *height, + size_t *bufused) +{ + native_osd.init_buffers = _osd_lcd_init_buffers; + native_osd.set_viewport_pos = _osd_lcd_viewport_set_pos; + native_osd.lcd_update = rb->lcd_update; + native_osd.lcd_update_rect = rb->lcd_update_rect; + native_osd.lcd_set_viewport = rb->lcd_set_viewport; + native_osd.lcd_set_framebuffer = (void *)rb->lcd_set_framebuffer; +#if LCD_DEPTH < 4 + native_osd.lcd_framebuffer_set_pos = NULL; +#endif /* LCD_DEPTH < 4 */ + native_osd.lcd_bitmap_part = (void *)rb->lcd_bitmap_part; + + return _osd_init(&native_osd, flags, backbuf, backbuf_size, draw_cb, + width, height, bufused); +} + +void osd_destroy(void) +{ + return _osd_destroy(&native_osd); +} + +bool osd_show(unsigned flags) +{ + return _osd_show(&native_osd, flags); +} + +bool osd_update(void) +{ + return _osd_update(&native_osd); +} + +bool osd_update_rect(int x, int y, int width, int height) +{ + return _osd_update_rect(&native_osd, x, y, width, height); +} + +bool osd_update_pos(int x, int y, int width, int height) +{ + return _osd_update_pos(&native_osd, x, y, width, height); +} + +void osd_monitor_timeout(void) +{ + _osd_monitor_timeout(&native_osd); +} + +void osd_set_timeout(long timeout) +{ + _osd_set_timeout(&native_osd, timeout); +} + +struct viewport * osd_get_viewport(void) +{ + return _osd_get_viewport(&native_osd); +} + +void osd_get_max_dims(int *maxwidth, int *maxheight) +{ + _osd_get_max_dims(&native_osd, maxwidth, maxheight); +} + +bool osd_enabled(void) +{ + return _osd_enabled(&native_osd); +} + +void osd_lcd_update_prepare(void) +{ + _osd_lcd_update_prepare(&native_osd); +} + + +void osd_lcd_update(void) +{ + _osd_lcd_update(&native_osd); +} + +void osd_lcd_update_rect(int x, int y, int width, int height) +{ + _osd_lcd_update_rect(&native_osd, x, y, width, height); +} + +#if LCD_DEPTH < 4 +/* Greylib LCD, public */ +bool osd_grey_init(unsigned flags, void *backbuf, size_t backbuf_size, + osd_draw_cb_fn_t draw_cb, int *width, int *height, + size_t *bufused) +{ + grey_osd.init_buffers = _osd_grey_init_buffers; + grey_osd.set_viewport_pos = grey_viewport_set_pos; + grey_osd.lcd_update = grey_update; + grey_osd.lcd_update_rect = grey_update_rect; + grey_osd.lcd_set_viewport = grey_set_viewport; + grey_osd.lcd_set_framebuffer = (void *)grey_set_framebuffer; + grey_osd.lcd_framebuffer_set_pos = grey_framebuffer_set_pos; + grey_osd.lcd_bitmap_part = (void *)grey_gray_bitmap_part; + + return _osd_init(&grey_osd, flags, backbuf, backbuf_size, draw_cb, + width, height, bufused); +} + +void osd_grey_destroy(void) +{ + return _osd_destroy(&grey_osd); +} + +bool osd_grey_show(unsigned flags) +{ + return _osd_show(&grey_osd, flags); +} + +bool osd_grey_update(void) +{ + return _osd_update(&grey_osd); +} + +bool osd_grey_update_rect(int x, int y, int width, int height) +{ + return _osd_update_rect(&grey_osd, x, y, width, height); +} + +bool osd_grey_update_pos(int x, int y, int width, int height) +{ + return _osd_update_pos(&grey_osd, x, y, width, height); +} + +void osd_grey_monitor_timeout(void) +{ + _osd_monitor_timeout(&grey_osd); +} + +void osd_grey_set_timeout(long timeout) +{ + _osd_set_timeout(&grey_osd, timeout); +} + +struct viewport * osd_grey_get_viewport(void) +{ + return _osd_get_viewport(&grey_osd); +} + +void osd_grey_get_max_dims(int *maxwidth, int *maxheight) +{ + _osd_get_max_dims(&grey_osd, maxwidth, maxheight); +} + +bool osd_grey_enabled(void) +{ + return _osd_enabled(&grey_osd); +} + +void osd_grey_lcd_update_prepare(void) +{ + _osd_lcd_update_prepare(&grey_osd); +} + +void osd_grey_lcd_update(void) +{ + _osd_lcd_update(&grey_osd); +} + +void osd_grey_lcd_update_rect(int x, int y, int width, int height) +{ + _osd_lcd_update_rect(&grey_osd, x, y, width, height); +} +#endif /* LCD_DEPTH < 4 */ diff --git a/apps/plugins/lib/osd.h b/apps/plugins/lib/osd.h index 89441ae273..b5bf63d9fe 100644 --- a/apps/plugins/lib/osd.h +++ b/apps/plugins/lib/osd.h @@ -23,6 +23,10 @@ #ifndef OSD_H #define OSD_H +#ifndef HAVE_LCD_BITMAP +#error OSD requires bitmapped LCD +#endif + /* At this time: assumes use of the default viewport for normal drawing */ /* Callback implemented by user. Paramters are OSD vp-relative coordinates */ @@ -30,8 +34,20 @@ typedef void (* osd_draw_cb_fn_t)(int x, int y, int width, int height); /* Initialize the OSD, set its backbuffer, update callback and enable it if * the call succeeded. */ -bool osd_init(void *backbuf, size_t backbuf_size, - osd_draw_cb_fn_t draw_cb); +enum osd_init_flags +{ + OSD_INIT_MAJOR_WIDTH = 0x0, /* Width guides buffer dims (default) */ + OSD_INIT_MAJOR_HEIGHT = 0x1, /* Height guides buffer dims */ + OSD_INIT_MINOR_MIN = 0x2, /* Treat minor axis dim as a minimum */ + OSD_INIT_MINOR_MAX = 0x4, /* Treat minor axis dim as a maximum */ + /* To get exact minor size, combine min/max flags */ +}; +bool osd_init(unsigned flags, void *backbuf, size_t backbuf_size, + osd_draw_cb_fn_t draw_cb, int *width, + int *height, size_t *bufused); + +/* Destroy the OSD, rendering it disabled */ +void osd_destroy(void); enum { @@ -91,4 +107,46 @@ void osd_lcd_update(void); /* Update a part of the screen and restore OSD if it is visible */ void osd_lcd_update_rect(int x, int y, int width, int height); +#if LCD_DEPTH < 4 +/* Like other functions but for greylib surface (requires GREY_BUFFERED) */ +bool osd_grey_init(unsigned flags, void *backbuf, size_t backbuf_size, + osd_draw_cb_fn_t draw_cb, int *width, + int *height, size_t *bufused); +void osd_grey_destroy(void); +bool osd_grey_show(unsigned flags); +bool osd_grey_update(void); +bool osd_grey_update_rect(int x, int y, int width, int height); +bool osd_grey_update_pos(int x, int y, int width, int height); +void osd_grey_monitor_timeout(void); +void osd_grey_set_timeout(long timeout); +struct viewport * osd_grey_get_viewport(void); +void osd_grey_get_max_dims(int *maxwidth, int *maxheight); +bool osd_grey_enabled(void); +void osd_grey_lcd_update_prepare(void); +void osd_grey_lcd_update(void); +void osd_grey_lcd_update_rect(int x, int y, int width, int height); +#endif /* LCD_DEPTH < 4 */ + +/* MYLCD-style helper defines to compile with different graphics libs */ +#ifdef __GREY_H__ +#define myosd_(fn) osd_grey_##fn +#else +#define myosd_(fn) osd_##fn +#endif + +#define myosd_init myosd_(init) +#define myosd_destroy myosd_(destroy) +#define myosd_show myosd_(show) +#define myosd_update myosd_(update) +#define myosd_update_rect myosd_(update_rect) +#define myosd_update_pos myosd_(update_pos) +#define myosd_monitor_timeout myosd_(monitor_timeout) +#define myosd_set_timeout myosd_(set_timeout) +#define myosd_get_viewport myosd_(get_viewport) +#define myosd_get_max_dims myosd_(get_max_dims) +#define myosd_enabled myosd_(enabled) +#define myosd_lcd_update_prepare myosd_(lcd_update_prepare) +#define myosd_lcd_update myosd_(lcd_update) +#define myosd_lcd_update_rect myosd_(lcd_update_rect) + #endif /* OSD_H */ diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index 4fbf96939d..c418f127fc 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -727,7 +727,14 @@ static void osc_osd_init(void) /* Grab the plugin buffer for the OSD back buffer */ size_t bufsize; void *buf = rb->plugin_get_buffer(&bufsize); - osd_init(buf, bufsize, osd_lcd_draw_cb); + + int width, height; + rb->lcd_setfont(FONT_UI); + rb->lcd_getstringsize("M", NULL, &height); + width = LCD_WIDTH; + height += 2 + 2*OSC_OSD_MARGIN_SIZE; + osd_init(OSD_INIT_MAJOR_HEIGHT | OSD_INIT_MINOR_MAX, buf, bufsize, + osd_lcd_draw_cb, &width, &height, NULL); } /* Format a message by ID and show the OSD */ @@ -1826,7 +1833,7 @@ static long oscilloscope_draw(void) static void osc_cleanup(void) { - osd_init(NULL, 0, NULL); + osd_destroy(); #ifdef OSCILLOSCOPE_GRAPHMODE anim_waveform_exit();