summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/lib/grey.h28
-rw-r--r--apps/plugins/lib/grey_core.c9
-rw-r--r--apps/plugins/lib/grey_draw.c300
-rw-r--r--apps/plugins/lib/grey_parm.c161
-rw-r--r--apps/plugins/lib/grey_scroll.c50
-rw-r--r--apps/plugins/lib/mylcd.h11
-rw-r--r--apps/plugins/lib/osd.c778
-rw-r--r--apps/plugins/lib/osd.h62
-rw-r--r--apps/plugins/oscilloscope.c11
9 files changed, 1057 insertions, 353 deletions
diff --git a/apps/plugins/lib/grey.h b/apps/plugins/lib/grey.h
index 7c990ad..d63d19e 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 c2e0747..047e4cc 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 3b81694..171d273 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;
-
- pfunc = _grey_pixelfuncs[_grey_info.drawmode];
- dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y1) + x];
-
- dst_end = dst + _GREY_MULUQ(_grey_info.width, y2 - y1);
+ if (y1 < _grey_info.clip_t)
+ y1 = _grey_info.clip_t;
+ if (y2 >= _grey_info.clip_b)
+ y2 = _grey_info.clip_b - 1;
+
+ 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(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 00193e1..9b4ba8c 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.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)
{
- return rb->font_getstringsize(str, w, h, _grey_info.curfont);
+ 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 35f73b7..78e5725 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 48e8ca1..e363111 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 ff0533a..598a767 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 */
+ if (w == 0 || ((flags & OSD_INIT_MINOR_MIN) && w < osd->maxwidth))
+ {
+ DEBUGF("OSD: not enough buffer\n");
+ return NULL; /* not enough buffer */
+ }
+
+ if ((flags & OSD_INIT_MINOR_MAX) && w > osd->maxwidth)
+ w = osd->maxwidth;
+ }
+ else /* OSD_INIT_MAJOR_WIDTH implied */
+ {
+ 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;
+ }
}
-#else
- int w = LCD_BYTES2WIDTH(LCD_WIDTH2BYTES(LCD_WIDTH));
- int h = bufsize / LCD_WIDTH2BYTES(w);
- if (h == 0)
+ 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);
+
+ if (flags & OSD_INIT_MAJOR_HEIGHT)
{
- DEBUGF("OSD: not enough buffer\n");
- return NULL; /* not enough buffer */
+ if (h == 0 || h < osd->maxheight)
+ {
+ DEBUGF("OSD: not enough buffer\n");
+ return NULL;
+ }
+ else if (h > osd->maxheight)
+ {
+ h = osd->maxheight;
+ }
}
-#endif
+ 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;
+ }
- DEBUGF("fbw:%d fbh:%d\n", w, h);
+ if ((flags & OSD_INIT_MINOR_MAX) && h > osd->maxheight)
+ h = osd->maxheight;
+ }
- *width = w;
- *height = h;
-
- return (fb_data *)buf;
-}
+ 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 */
-static inline void osd_set_vp_pos(int x, int y, int width, int height)
-{
- osd.vp.x = x;
- osd.vp.y = y;
- osd.vp.width = width;
- osd.vp.height = height;
+ 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;
}
-/* Sync the backbuffer to the on-screen image */
-static void osd_lcd_update_back_buffer(void)
+/* Set viewport coordinates */
+static void _osd_lcd_viewport_set_pos(
+ struct viewport *vp, int x, int y, int width, int height)
{
- 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);
+ vp->x = x;
+ vp->y = y;
+ vp->width = width;
+ vp->height = height;
}
-/* 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);
+}
-/* Initialized the OSD and set its backbuffer */
-bool osd_init(void *backbuf, size_t backbuf_size,
- osd_draw_cb_fn_t draw_cb)
+/* Erase the OSD to restore the framebuffer image */
+static void _osd_erase_osd(struct osd *osd)
{
- osd_show(OSD_HIDE);
+ 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);
+}
- 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;
+/* Initialized the OSD and set its backbuffer */
+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_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 ((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 (!backfb)
+ 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;
-
- /* 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 (bufused)
+ *bufused = backbuf_size + (backbuf_orig - backbuf);
- DEBUGF("FB:%p BB:%p\n", osd.lcd_bitmap.data, osd.back_bitmap.data);
+ if (width)
+ *width = osd->maxwidth;
+
+ 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;
+
+ 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 == osd.vp.x && y == osd.vp.y &&
- width == osd.vp.width && height == 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 89441ae..b5bf63d 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 4fbf969..c418f12 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();