summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/osd.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib/osd.c')
-rw-r--r--apps/plugins/lib/osd.c778
1 files changed, 580 insertions, 198 deletions
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 */