summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/osd.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2012-12-07 01:50:52 -0500
committerMichael Sevakis <jethead71@rockbox.org>2012-12-18 19:16:26 -0500
commit371c86bf3f4d1708fc40db2aa7fa572eb429d0b4 (patch)
treebe339c62eac616ac6938c2929349b72377c10ee2 /apps/plugins/lib/osd.c
parentf668c3624184fedc14d34f87ad7b5f1e43bc87a1 (diff)
downloadrockbox-371c86bf3f4d1708fc40db2aa7fa572eb429d0b4.tar.gz
rockbox-371c86bf3f4d1708fc40db2aa7fa572eb429d0b4.zip
Adapt OSD in plugin lib to be greylib compatible.
Requires addition of viewports and alternate framebuffers to greylib which are essentially similar to the core implementation except that the framebuffer can be any size and relationship to a viewport. Drawing is always fully clipped to the intersecting area. Adapt oscilloscope.c to the API change. FFT will use the new features (later update). Get rid of silly and wrong lcd_bmp_part use in OSD. Remove it from plugin API (must be made incompatible now). Change-Id: Iafa5e2174148fb8ad11db6b9d4add0dcabc5c563
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 ff0533a898..598a76759c 100644
--- a/apps/plugins/lib/osd.c
+++ b/apps/plugins/lib/osd.c
@@ -21,6 +21,7 @@
21* 21*
22****************************************************************************/ 22****************************************************************************/
23#include "plugin.h" 23#include "plugin.h"
24#include "grey.h"
24#include "osd.h" 25#include "osd.h"
25 26
26#if 1 27#if 1
@@ -28,10 +29,20 @@
28#define DEBUGF(...) 29#define DEBUGF(...)
29#endif 30#endif
30 31
32#if defined(SIMULATOR) && LCD_DEPTH < 4
33/* Sim isn't using --ffunction-sections thus greylib references will happen
34 here even if not using this with greylib on a grayscale display, which
35 demands that a struct _grey_info exist. */
36#ifndef _WIN32
37__attribute__((weak))
38#endif /* _WIN32 */
39 struct _grey_info _grey_info;
40#endif /* defined(SIMULATOR) && LCD_DEPTH < 4 */
41
31/* At this time: assumes use of the default viewport for normal drawing */ 42/* At this time: assumes use of the default viewport for normal drawing */
32 43
33/* If multiple OSD's are wanted, could convert to caller-allocated */ 44/* If multiple OSD's are wanted, could convert to caller-allocated */
34static struct osd 45struct osd
35{ 46{
36 enum osd_status 47 enum osd_status
37 { 48 {
@@ -41,152 +52,314 @@ static struct osd
41 OSD_ERASED, /* Erased in preparation for regular drawing */ 52 OSD_ERASED, /* Erased in preparation for regular drawing */
42 } status; /* View status */ 53 } status; /* View status */
43 struct viewport vp; /* Clipping viewport */ 54 struct viewport vp; /* Clipping viewport */
44 struct bitmap lcd_bitmap; /* The main LCD fb bitmap */ 55 int lcd_bitmap_stride; /* Stride of LCD bitmap */
45 struct bitmap back_bitmap; /* The OSD backbuffer fb bitmap */ 56 void *lcd_bitmap_data; /* Backbuffer framebuffer data */
57 int back_bitmap_stride; /* Stride of backbuffer bitmap */
58 void *back_bitmap_data; /* LCD framebuffer data */
46 int maxwidth; /* How wide may it be at most? */ 59 int maxwidth; /* How wide may it be at most? */
47 int maxheight; /* How high may it be at most? */ 60 int maxheight; /* How high may it be at most? */
48 long timeout; /* Current popup stay duration */ 61 long timeout; /* Current popup stay duration */
49 long hide_tick; /* Tick when it should be hidden */ 62 long hide_tick; /* Tick when it should be hidden */
50 osd_draw_cb_fn_t draw_cb; /* Draw update callback */ 63 osd_draw_cb_fn_t draw_cb; /* Draw update callback */
51} osd; 64 /* Functions to factilitate interface compatibility of OSD types */
65 void * (*init_buffers)(struct osd *osd, unsigned flags, void *buf,
66 size_t *bufsize);
67 void (*set_viewport_pos)(struct viewport *vp, int x, int y, int width,
68 int height);
69 void (*lcd_update)(void);
70 void (*lcd_update_rect)(int x, int y, int width, int height);
71 void (*lcd_set_viewport)(struct viewport *vp);
72 void (*lcd_set_framebuffer)(void *buf);
73 void (*lcd_framebuffer_set_pos)(int x, int y, int width, int height);
74 void (*lcd_bitmap_part)(const void *src, int src_x, int src_y,
75 int stride, int x, int y, int width, int height);
76};
77
78static struct osd native_osd;
79#if LCD_DEPTH < 4
80static struct osd grey_osd;
81#endif
52 82
53/* Framebuffer allocation macros */ 83/* Framebuffer allocation macros */
54#if LCD_DEPTH == 1 84#if LCD_DEPTH == 1
55# if LCD_PIXELFORMAT == HORIZONTAL_PACKING 85# if LCD_PIXELFORMAT == HORIZONTAL_PACKING
56# define LCD_WIDTH2BYTES(w) (((w)+7)/8) 86# define _OSD_WIDTH2BYTES(w) (((w)+7)/8)
57# define LCD_BYTES2WIDTH(b) ((b)*8) 87# define _OSD_BYTES2WIDTH(b) ((b)*8)
58# elif LCD_PIXELFORMAT == VERTICAL_PACKING 88# elif LCD_PIXELFORMAT == VERTICAL_PACKING
59# define LCD_HEIGHT2BYTES(h) (((h)+7)/8) 89# define _OSD_HEIGHT2BYTES(h) (((h)+7)/8)
60# define LCD_BYTES2HEIGHT(b) ((b)*8) 90# define _OSD_BYTES2HEIGHT(b) ((b)*8)
61# else 91# else
62# error Unknown 1-bit format; please define macros 92# error Unknown 1-bit format; please define macros
63# endif /* LCD_PIXELFORMAT */ 93# endif /* LCD_PIXELFORMAT */
64#elif LCD_DEPTH == 2 94#elif LCD_DEPTH == 2
65# if LCD_PIXELFORMAT == HORIZONTAL_PACKING 95# if LCD_PIXELFORMAT == HORIZONTAL_PACKING
66# define LCD_WIDTH2BYTES(w) (((w)+3)/4) 96# define _OSD_WIDTH2BYTES(w) (((w)+3)/4)
67# define LCD_BYTES2WIDTH(b) ((b)*4) 97# define _OSD_BYTES2WIDTH(b) ((b)*4)
68# elif LCD_PIXELFORMAT == VERTICAL_PACKING 98# elif LCD_PIXELFORMAT == VERTICAL_PACKING
69# define LCD_HEIGHT2BYTES(h) (((h)+3)/4) 99# define _OSD_HEIGHT2BYTES(h) (((h)+3)/4)
70# define LCD_BYTES2HEIGHT(b) ((b)*4) 100# define _OSD_BYTES2HEIGHT(b) ((b)*4)
71# elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED 101# elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
72# define LCD_WIDTH2BYTES(w) ((w)*2) 102# define _OSD_HEIGHT2BYTES(h) (((h)+7)/8*2)
73# define LCD_BYTES2WIDTH(b) ((b)/2) 103# define _OSD_BYTES2HEIGHT(b) ((b)/2*8)
74# define LCD_HEIGHT2BYTES(h) (((h)+7)/8*2)
75# define LCD_BYTES2HEIGHT(b) ((b)/2*8)
76# else 104# else
77# error Unknown 2-bit format; please define macros 105# error Unknown 2-bit format; please define macros
78# endif /* LCD_PIXELFORMAT */ 106# endif /* LCD_PIXELFORMAT */
79#elif LCD_DEPTH == 16 107#elif LCD_DEPTH == 16
80# define LCD_WIDTH2BYTES(w) ((w)*2) 108# if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
81# define LCD_BYTES2WIDTH(b) ((b)/2) 109# define _OSD_HEIGHT2BYTES(h) ((h)*2)
82#else 110# define _OSD_BYTES2HEIGHT(b) ((b)/2)
111# else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */
112# define _OSD_WIDTH2BYTES(w) ((w)*2)
113# define _OSD_BYTES2WIDTH(b) ((b)/2)
114# endif /* end stride type selection */
115#else /* other LCD depth */
83# error Unknown LCD depth; please define macros 116# error Unknown LCD depth; please define macros
84#endif /* LCD_DEPTH */ 117#endif /* LCD_DEPTH */
85/* Set defaults if not defined different yet. */ 118/* Set defaults if not defined differently */
86#ifndef LCD_WIDTH2BYTES 119#ifndef _OSD_WIDTH2BYTES
87# define LCD_WIDTH2BYTES(w) (w) 120# define _OSD_WIDTH2BYTES(w) (w)
88#endif 121#endif
89#ifndef LCD_BYTES2WIDTH 122#ifndef _OSD_BYTES2WIDTH
90# define LCD_BYTES2WIDTH(b) (b) 123# define _OSD_BYTES2WIDTH(b) (b)
91#endif 124#endif
92#ifndef LCD_HEIGHT2BYTES 125#ifndef _OSD_HEIGHT2BYTES
93# define LCD_HEIGHT2BYTES(h) (h) 126# define _OSD_HEIGHT2BYTES(h) (h)
94#endif 127#endif
95#ifndef LCD_BYTES2HEIGHT 128#ifndef _OSD_BYTES2HEIGHT
96# define LCD_BYTES2HEIGHT(b) (b) 129# define _OSD_BYTES2HEIGHT(b) (b)
97#endif 130#endif
131#ifndef _OSD_BUFSIZE
132# define _OSD_BUFSIZE(w, h) (_OSD_WIDTH2BYTES(w)*_OSD_HEIGHT2BYTES(h))
133#endif
134
135static void _osd_destroy(struct osd *osd);
136static bool _osd_show(struct osd *osd, unsigned flags);
137
138
139/** Native LCD routines **/
98 140
99/* Create a bitmap framebuffer from a buffer */ 141/* Create a bitmap framebuffer from a buffer */
100static fb_data * buf_to_fb_bitmap(void *buf, size_t bufsize, 142static void * _osd_lcd_init_buffers(struct osd *osd, unsigned flags,
101 int *width, int *height) 143 void *buf, size_t *bufsize)
102{ 144{
103 /* Used as dest, the LCD functions cannot deal with alternate 145 /* Used as dest, the LCD functions cannot deal with alternate
104 strides as of now - the stride guides the calulations. If 146 strides as of now - the stride guides the calulations. If
105 that is no longer the case, then width or height can be 147 that is no longer the case, then width or height can be
106 used instead (and less memory needed for a small surface!). 148 used instead (and less memory needed for a small surface!).
149 IOW: crappiness means one dimension is non-negotiable.
107 */ 150 */
108 DEBUGF("buf: %p bufsize: %lu\n", buf, (unsigned long)bufsize); 151 DEBUGF("OSD: in(buf=%p bufsize=%lu)\n", buf,
152 (unsigned long)*bufsize);
153
154 rb->viewport_set_fullscreen(&osd->vp, SCREEN_MAIN);
109 155
110#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE 156#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
111 int h = LCD_BYTES2HEIGHT(LCD_HEIGHT2BYTES(LCD_HEIGHT)); 157 int colbytes = _OSD_HEIGHT2BYTES(LCD_HEIGHT);
112 int w = bufsize / LCD_HEIGHT2BYTES(h); 158 int bytecols = *bufsize / colbytes;
159 int w = _OSD_BYTES2WIDTH(bytecols);
160 int h = _OSD_BYTES2HEIGHT(colbytes);
113 161
114 if (w == 0) 162 if (flags & OSD_INIT_MAJOR_HEIGHT)
115 { 163 {
116 DEBUGF("OSD: not enough buffer\n"); 164 if (w == 0 || ((flags & OSD_INIT_MINOR_MIN) && w < osd->maxwidth))
117 return NULL; /* not enough buffer */ 165 {
166 DEBUGF("OSD: not enough buffer\n");
167 return NULL; /* not enough buffer */
168 }
169
170 if ((flags & OSD_INIT_MINOR_MAX) && w > osd->maxwidth)
171 w = osd->maxwidth;
172 }
173 else /* OSD_INIT_MAJOR_WIDTH implied */
174 {
175 if (w == 0 || w < osd->maxwidth)
176 {
177 DEBUGF("OSD: not enough buffer\n");
178 return NULL; /* not enough buffer */
179 }
180 else if (w > osd->maxwidth)
181 {
182 w = osd->maxwidth;
183 }
118 } 184 }
119#else
120 int w = LCD_BYTES2WIDTH(LCD_WIDTH2BYTES(LCD_WIDTH));
121 int h = bufsize / LCD_WIDTH2BYTES(w);
122 185
123 if (h == 0) 186 w = _OSD_BYTES2WIDTH(_OSD_WIDTH2BYTES(w));
187 osd->lcd_bitmap_stride = _OSD_BYTES2HEIGHT(_OSD_HEIGHT2BYTES(LCD_HEIGHT));
188 osd->back_bitmap_stride = h;
189#else /* !defined(LCD_STRIDEFORMAT) || LCD_STRIDEFORMAT != VERTICAL_STRIDE */
190 int rowbytes = _OSD_WIDTH2BYTES(LCD_WIDTH);
191 int byterows = *bufsize / rowbytes;
192 int w = _OSD_BYTES2WIDTH(rowbytes);
193 int h = _OSD_BYTES2HEIGHT(byterows);
194
195 if (flags & OSD_INIT_MAJOR_HEIGHT)
124 { 196 {
125 DEBUGF("OSD: not enough buffer\n"); 197 if (h == 0 || h < osd->maxheight)
126 return NULL; /* not enough buffer */ 198 {
199 DEBUGF("OSD: not enough buffer\n");
200 return NULL;
201 }
202 else if (h > osd->maxheight)
203 {
204 h = osd->maxheight;
205 }
127 } 206 }
128#endif 207 else /* OSD_INIT_MAJOR_WIDTH implied */
208 {
209 if (h == 0 || ((flags & OSD_INIT_MINOR_MIN) && h < osd->maxheight))
210 {
211 DEBUGF("OSD: not enough buffer\n");
212 return NULL;
213 }
129 214
130 DEBUGF("fbw:%d fbh:%d\n", w, h); 215 if ((flags & OSD_INIT_MINOR_MAX) && h > osd->maxheight)
216 h = osd->maxheight;
217 }
131 218
132 *width = w; 219 h = _OSD_BYTES2HEIGHT(_OSD_HEIGHT2BYTES(h));
133 *height = h; 220 osd->lcd_bitmap_stride = _OSD_BYTES2WIDTH(_OSD_WIDTH2BYTES(LCD_WIDTH));
134 221 osd->back_bitmap_stride = w;
135 return (fb_data *)buf; 222#endif /* end stride type selection */
136}
137 223
138static inline void osd_set_vp_pos(int x, int y, int width, int height) 224 osd->lcd_bitmap_data = (void *)rb->lcd_framebuffer;
139{ 225 osd->back_bitmap_data = buf;
140 osd.vp.x = x; 226
141 osd.vp.y = y; 227 osd->maxwidth = w;
142 osd.vp.width = width; 228 osd->maxheight = h;
143 osd.vp.height = height; 229 *bufsize = _OSD_BUFSIZE(w, h);
230
231 DEBUGF("OSD: addr(fb=%p bb=%p)\n", osd->lcd_bitmap_data,
232 osd->back_bitmap_data);
233 DEBUGF("OSD: w=%d h=%d bufsz=%lu\n", w, h, (unsigned long)*bufsize);
234
235 return buf;
144} 236}
145 237
146/* Sync the backbuffer to the on-screen image */ 238/* Set viewport coordinates */
147static void osd_lcd_update_back_buffer(void) 239static void _osd_lcd_viewport_set_pos(
240 struct viewport *vp, int x, int y, int width, int height)
148{ 241{
149 rb->lcd_set_framebuffer((fb_data *)osd.back_bitmap.data); 242 vp->x = x;
150 rb->lcd_bmp_part(&osd.lcd_bitmap, osd.vp.x, osd.vp.y, 243 vp->y = y;
151 0, 0, osd.vp.width, osd.vp.height); 244 vp->width = width;
152 /* Assume it was on default framebuffer for now */ 245 vp->height = height;
153 rb->lcd_set_framebuffer(NULL);
154} 246}
155 247
156/* Erase the OSD to restore the framebuffer */ 248
157static void osd_lcd_erase(void) 249#if LCD_DEPTH < 4
250/** Greylib LCD routines **/
251
252/* Create a greylib bitmap framebuffer from a buffer */
253static void * _osd_grey_init_buffers(struct osd *osd, unsigned flags,
254 void *buf, size_t *bufsize)
158{ 255{
159 rb->lcd_bmp_part(&osd.back_bitmap, 0, 0, osd.vp.x, osd.vp.y, 256 int w, h;
160 osd.vp.width, osd.vp.height); 257
258 DEBUGF("OSD (grey): in(buf=%p bufsize=%lu)\n", buf,
259 (unsigned long)*bufsize);
260
261 grey_viewport_set_fullscreen(&osd->vp, SCREEN_MAIN);
262
263 if (flags & OSD_INIT_MAJOR_HEIGHT)
264 {
265 h = osd->maxheight;
266 w = *bufsize / h;
267
268 if (w == 0 || ((flags & OSD_INIT_MINOR_MIN) && w < osd->maxwidth))
269 {
270 DEBUGF("OSD (grey): Not enough buffer\n");
271 return NULL;
272 }
273
274 if ((flags & OSD_INIT_MINOR_MAX) && w > osd->maxwidth)
275 w = osd->maxwidth;
276 }
277 else /* OSD_INIT_MAJOR_WIDTH implied */
278 {
279 w = osd->maxwidth;
280 h = *bufsize / w;
281
282 if (h == 0 || ((flags & OSD_INIT_MINOR_MIN) && h < osd->maxheight))
283 {
284 DEBUGF("OSD (grey): Not enough buffer\n");
285 return NULL;
286 }
287
288 if ((flags & OSD_INIT_MINOR_MAX) && h > osd->maxheight)
289 h = osd->maxheight;
290 }
291
292 /* Have to peek into _grey_info a bit */
293 osd->lcd_bitmap_stride = _grey_info.width;
294 osd->lcd_bitmap_data = _grey_info.buffer;
295 osd->back_bitmap_stride = w;
296 osd->back_bitmap_data = buf;
297
298 osd->maxwidth = w;
299 osd->maxheight = h;
300 *bufsize = w * h;
301
302 DEBUGF("OSD (grey): addr(fb=%p bb=%p)\n", osd->lcd_bitmap_data,
303 osd->back_bitmap_data);
304 DEBUGF("OSD (grey): w=%d h=%d bufsz=%lu\n", w, h, (unsigned long)*bufsize);
305
306 return buf;
161} 307}
308#endif /* LCD_DEPTH < 4*/
309
310
311/** Common LCD routines **/
162 312
163/* Draw the OSD image portion using the callback */ 313/* Draw the OSD image portion using the callback */
164static void osd_lcd_draw_rect(int x, int y, int width, int height) 314static void _osd_draw_osd_rect(struct osd *osd, int x, int y,
315 int width, int height)
165{ 316{
166 rb->lcd_set_viewport(&osd.vp); 317 osd->lcd_set_viewport(&osd->vp);
167 osd.draw_cb(x, y, width, height); 318 osd->draw_cb(x, y, width, height);
168 rb->lcd_set_viewport(NULL); 319 osd->lcd_set_viewport(NULL);
169} 320}
170 321
171/* Draw the OSD image using the callback */ 322/* Draw the OSD image using the callback */
172static void osd_lcd_draw(void) 323static void _osd_draw_osd(struct osd *osd)
173{ 324{
174 osd_lcd_draw_rect(0, 0, osd.vp.width, osd.vp.height); 325 _osd_draw_osd_rect(osd, 0, 0, osd->vp.width, osd->vp.height);
175} 326}
176 327
328static void _osd_update_viewport(struct osd *osd)
329{
330 osd->lcd_update_rect(osd->vp.x, osd->vp.y, osd->vp.width,
331 osd->vp.height);
332}
177 333
178/** Public APIs **/ 334/* Sync the backbuffer to the framebuffer image */
335static void _osd_update_back_buffer(struct osd *osd)
336{
337 /* Assume it's starting with default viewport for now */
338 osd->lcd_set_framebuffer(osd->back_bitmap_data);
339#if LCD_DEPTH < 4
340 if (osd->lcd_framebuffer_set_pos)
341 osd->lcd_framebuffer_set_pos(0, 0, osd->maxwidth, osd->maxheight);
342#endif /* LCD_DEPTH < 4 */
343 osd->lcd_bitmap_part(osd->lcd_bitmap_data, osd->vp.x, osd->vp.y,
344 osd->lcd_bitmap_stride, 0, 0, osd->vp.width,
345 osd->vp.height);
346 /* Assume it was on default framebuffer for now */
347 osd->lcd_set_framebuffer(NULL);
348}
179 349
180/* Initialized the OSD and set its backbuffer */ 350/* Erase the OSD to restore the framebuffer image */
181bool osd_init(void *backbuf, size_t backbuf_size, 351static void _osd_erase_osd(struct osd *osd)
182 osd_draw_cb_fn_t draw_cb)
183{ 352{
184 osd_show(OSD_HIDE); 353 osd->lcd_bitmap_part(osd->back_bitmap_data, 0, 0, osd->back_bitmap_stride,
354 osd->vp.x, osd->vp.y, osd->vp.width, osd->vp.height);
355}
185 356
186 osd.status = OSD_DISABLED; /* Disabled unless all is okay */ 357/* Initialized the OSD and set its backbuffer */
187 osd_set_vp_pos(0, 0, 0, 0); 358static bool _osd_init(struct osd *osd, unsigned flags, void *backbuf,
188 osd.maxwidth = osd.maxheight = 0; 359 size_t backbuf_size, osd_draw_cb_fn_t draw_cb,
189 osd.timeout = 0; 360 int *width, int *height, size_t *bufused)
361{
362 _osd_destroy(osd);
190 363
191 if (!draw_cb) 364 if (!draw_cb)
192 return false; 365 return false;
@@ -194,95 +367,133 @@ bool osd_init(void *backbuf, size_t backbuf_size,
194 if (!backbuf) 367 if (!backbuf)
195 return false; 368 return false;
196 369
197 ALIGN_BUFFER(backbuf, backbuf_size, FB_DATA_SZ); 370 void *backbuf_orig = backbuf; /* Save in case of ptr advance */
371 ALIGN_BUFFER(backbuf, backbuf_size, MAX(FB_DATA_SZ, 4));
198 372
199 if (!backbuf_size) 373 if (!backbuf_size)
200 return false; 374 return false;
201 375
202 rb->viewport_set_fullscreen(&osd.vp, SCREEN_MAIN); 376 if (flags & OSD_INIT_MAJOR_HEIGHT)
377 {
378 if (!height || *height <= 0)
379 return false;
203 380
204 fb_data *backfb = buf_to_fb_bitmap(backbuf, backbuf_size, 381 if ((flags & (OSD_INIT_MINOR_MIN | OSD_INIT_MINOR_MAX)) &&
205 &osd.maxwidth, &osd.maxheight); 382 (!width || *width <= 0))
383 {
384 return false;
385 }
386 }
387 else
388 {
389 if (!width || *width <= 0)
390 return false;
391
392 if ((flags & (OSD_INIT_MINOR_MIN | OSD_INIT_MINOR_MAX)) &&
393 (!height || *height <= 0))
394 {
395 return false;
396 }
397 }
398
399 /* Store requested sizes in max(width|height) */
400 if (width)
401 osd->maxwidth = *width;
402 else
403 osd->maxwidth = LCD_WIDTH;
206 404
207 if (!backfb) 405 if (height)
406 osd->maxheight = *height;
407 else
408 osd->maxheight = LCD_HEIGHT;
409
410 if (!osd->init_buffers(osd, flags, backbuf, &backbuf_size))
411 {
412 osd->maxwidth = osd->maxheight = 0;
208 return false; 413 return false;
414 }
209 415
210 osd.draw_cb = draw_cb; 416 osd->draw_cb = draw_cb;
211 417
212 /* LCD framebuffer bitmap */ 418 if (bufused)
213 osd.lcd_bitmap.width = LCD_BYTES2WIDTH(LCD_WIDTH2BYTES(LCD_WIDTH)); 419 *bufused = backbuf_size + (backbuf_orig - backbuf);
214 osd.lcd_bitmap.height = LCD_BYTES2HEIGHT(LCD_HEIGHT2BYTES(LCD_HEIGHT));
215#if LCD_DEPTH > 1
216 osd.lcd_bitmap.format = FORMAT_NATIVE;
217 osd.lcd_bitmap.maskdata = NULL;
218#endif
219#ifdef HAVE_LCD_COLOR
220 osd.lcd_bitmap.alpha_offset = 0;
221#endif
222 osd.lcd_bitmap.data = (void *)rb->lcd_framebuffer;
223
224 /* Backbuffer bitmap */
225 osd.back_bitmap.width = osd.maxwidth;
226 osd.back_bitmap.height = osd.maxheight;
227#if LCD_DEPTH > 1
228 osd.back_bitmap.format = FORMAT_NATIVE;
229 osd.back_bitmap.maskdata = NULL;
230#endif
231#ifdef HAVE_LCD_COLOR
232 osd.back_bitmap.alpha_offset = 0;
233#endif
234 osd.back_bitmap.data = (void *)backfb;
235 420
236 DEBUGF("FB:%p BB:%p\n", osd.lcd_bitmap.data, osd.back_bitmap.data); 421 if (width)
422 *width = osd->maxwidth;
423
424 if (height)
425 *height = osd->maxheight;
237 426
238 /* Set the default position to the whole thing */ 427 /* Set the default position to the whole thing */
239 osd_set_vp_pos(0, 0, osd.maxwidth, osd.maxheight); 428 osd->set_viewport_pos(&osd->vp, 0, 0, osd->maxwidth, osd->maxheight);
429
430 osd->status = OSD_HIDDEN; /* Ready when you are */
240 431
241 osd.status = OSD_HIDDEN; /* Ready when you are */ 432 return true;
433}
434
435static void _osd_destroy(struct osd *osd)
436{
437 _osd_show(osd, OSD_HIDE);
438
439 /* Set to essential defaults */
440 osd->status = OSD_DISABLED;
441 osd->set_viewport_pos(&osd->vp, 0, 0, 0, 0);
442 osd->maxwidth = osd->maxheight = 0;
443 osd->timeout = 0;
444}
445
446/* Redraw the entire OSD */
447static bool _osd_update(struct osd *osd)
448{
449 if (osd->status != OSD_VISIBLE)
450 return false;
451
452 _osd_draw_osd(osd);
453 _osd_update_viewport(osd);
242 return true; 454 return true;
243} 455}
244 456
245/* Show/Hide the OSD on screen */ 457/* Show/Hide the OSD on screen */
246bool osd_show(unsigned flags) 458static bool _osd_show(struct osd *osd, unsigned flags)
247{ 459{
248 if (flags & OSD_SHOW) 460 if (flags & OSD_SHOW)
249 { 461 {
250 switch (osd.status) 462 switch (osd->status)
251 { 463 {
252 case OSD_DISABLED: 464 case OSD_DISABLED:
253 break; /* No change */ 465 break; /* No change */
254 466
255 case OSD_HIDDEN: 467 case OSD_HIDDEN:
256 osd_lcd_update_back_buffer(); 468 _osd_update_back_buffer(osd);
257 osd.status = OSD_VISIBLE; 469 osd->status = OSD_VISIBLE;
258 osd_update(); 470 _osd_update(osd);
259 osd.hide_tick = *rb->current_tick + osd.timeout; 471 osd->hide_tick = *rb->current_tick + osd->timeout;
260 break; 472 break;
261 473
262 case OSD_VISIBLE: 474 case OSD_VISIBLE:
263 if (flags & OSD_UPDATENOW) 475 if (flags & OSD_UPDATENOW)
264 osd_update(); 476 _osd_update(osd);
265 /* Fall-through */ 477 /* Fall-through */
266 case OSD_ERASED: 478 case OSD_ERASED:
267 osd.hide_tick = *rb->current_tick + osd.timeout; 479 osd->hide_tick = *rb->current_tick + osd->timeout;
268 return true; 480 return true;
269 } 481 }
270 } 482 }
271 else 483 else
272 { 484 {
273 switch (osd.status) 485 switch (osd->status)
274 { 486 {
275 case OSD_DISABLED: 487 case OSD_DISABLED:
276 case OSD_HIDDEN: 488 case OSD_HIDDEN:
277 break; 489 break;
278 490
279 case OSD_VISIBLE: 491 case OSD_VISIBLE:
280 osd_lcd_erase(); 492 _osd_erase_osd(osd);
281 rb->lcd_update_rect(osd.vp.x, osd.vp.y, osd.vp.width, 493 _osd_update_viewport(osd);
282 osd.vp.height);
283 /* Fall-through */ 494 /* Fall-through */
284 case OSD_ERASED: 495 case OSD_ERASED:
285 osd.status = OSD_HIDDEN; 496 osd->status = OSD_HIDDEN;
286 return true; 497 return true;
287 } 498 }
288 } 499 }
@@ -290,30 +501,20 @@ bool osd_show(unsigned flags)
290 return false; 501 return false;
291} 502}
292 503
293/* Redraw the entire OSD */
294bool osd_update(void)
295{
296 if (osd.status != OSD_VISIBLE)
297 return false;
298
299 osd_lcd_draw();
300
301 rb->lcd_update_rect(osd.vp.x, osd.vp.y, osd.vp.width,
302 osd.vp.height);
303
304 return true;
305}
306
307/* Redraw part of the OSD (viewport-relative coordinates) */ 504/* Redraw part of the OSD (viewport-relative coordinates) */
308bool osd_update_rect(int x, int y, int width, int height) 505static bool _osd_update_rect(struct osd *osd, int x, int y, int width,
506 int height)
309{ 507{
310 if (osd.status != OSD_VISIBLE) 508 if (osd->status != OSD_VISIBLE)
311 return false; 509 return false;
312 510
313 osd_lcd_draw_rect(x, y, width, height); 511 _osd_draw_osd_rect(osd, x, y, width, height);
314 512
315 if (x + width > osd.vp.width) 513 int vp_x = osd->vp.x;
316 width = osd.vp.width - x; 514 int vp_w = osd->vp.width;
515
516 if (x + width > vp_w)
517 width = vp_w - x;
317 518
318 if (x < 0) 519 if (x < 0)
319 { 520 {
@@ -324,8 +525,11 @@ bool osd_update_rect(int x, int y, int width, int height)
324 if (width <= 0) 525 if (width <= 0)
325 return false; 526 return false;
326 527
327 if (y + height > osd.vp.height) 528 int vp_y = osd->vp.y;
328 height = osd.vp.height - y; 529 int vp_h = osd->vp.height;
530
531 if (y + height > vp_h)
532 height = vp_h - y;
329 533
330 if (y < 0) 534 if (y < 0)
331 { 535 {
@@ -336,135 +540,313 @@ bool osd_update_rect(int x, int y, int width, int height)
336 if (height <= 0) 540 if (height <= 0)
337 return false; 541 return false;
338 542
339 rb->lcd_update_rect(osd.vp.x + x, osd.vp.y + y, width, height); 543 osd->lcd_update_rect(vp_x + x, vp_y + y, width, height);
340 544
341 return true; 545 return true;
342} 546}
343 547
344/* Set a new screen location and size (screen coordinates) */ 548/* Set a new screen location and size (screen coordinates) */
345bool osd_update_pos(int x, int y, int width, int height) 549static bool _osd_update_pos(struct osd *osd, int x, int y, int width,
550 int height)
346{ 551{
347 if (osd.status == OSD_DISABLED) 552 if (osd->status == OSD_DISABLED)
348 return false; 553 return false;
349 554
350 if (width < 0) 555 if (width < 0)
351 width = 0; 556 width = 0;
352 else if (width > osd.maxwidth) 557 else if (width > osd->maxwidth)
353 width = osd.maxwidth; 558 width = osd->maxwidth;
354 559
355 if (height < 0) 560 if (height < 0)
356 height = 0; 561 height = 0;
357 else if (height > osd.maxheight) 562 else if (height > osd->maxheight)
358 height = osd.maxheight; 563 height = osd->maxheight;
564
565 int vp_x = osd->vp.x;
566 int vp_y = osd->vp.y;
567 int vp_w = osd->vp.width;
568 int vp_h = osd->vp.height;
359 569
360 if (x == osd.vp.x && y == osd.vp.y && 570 if (x == vp_x && y == vp_y && width == vp_w && height == vp_h)
361 width == osd.vp.width && height == osd.vp.height)
362 return false; /* No change */ 571 return false; /* No change */
363 572
364 if (osd.status != OSD_VISIBLE) 573 if (osd->status != OSD_VISIBLE)
365 { 574 {
366 /* Not visible - just update pos */ 575 /* Not visible - just update pos */
367 osd_set_vp_pos(x, y, width, height); 576 osd->set_viewport_pos(&osd->vp, x, y, width, height);
368 return false; 577 return false;
369 } 578 }
370 579
371 /* Visible area has changed */ 580 /* Visible area has changed */
372 osd_lcd_erase(); 581 _osd_erase_osd(osd);
373 582
374 /* Update the smallest rectangle that encloses both the old and new 583 /* Update the smallest rectangle that encloses both the old and new
375 regions to make the change free of flicker (they may overlap) */ 584 regions to make the change free of flicker (they may overlap) */
376 int xu = MIN(osd.vp.x, x); 585 int xu = MIN(vp_x, x);
377 int yu = MIN(osd.vp.y, y); 586 int yu = MIN(vp_y, y);
378 int wu = MAX(osd.vp.x + osd.vp.width, x + width) - xu; 587 int wu = MAX(vp_x + vp_w, x + width) - xu;
379 int hu = MAX(osd.vp.y + osd.vp.height, y + height) - yu; 588 int hu = MAX(vp_y + vp_h, y + height) - yu;
380 589
381 osd_set_vp_pos(x, y, width, height); 590 osd->set_viewport_pos(&osd->vp, x, y, width, height);
382 osd_lcd_update_back_buffer(); 591 _osd_update_back_buffer(osd);
383 osd_lcd_draw(); 592 _osd_draw_osd(osd);
593 osd->lcd_update_rect(xu, yu, wu, hu);
384 594
385 rb->lcd_update_rect(xu, yu, wu, hu);
386 return true; 595 return true;
387} 596}
388 597
389/* Call periodically to have the OSD timeout and hide itself */ 598/* Call periodically to have the OSD timeout and hide itself */
390void osd_monitor_timeout(void) 599static void _osd_monitor_timeout(struct osd *osd)
391{ 600{
392 if (osd.status <= OSD_HIDDEN) 601 if (osd->status <= OSD_HIDDEN)
393 return; /* Already hidden/disabled */ 602 return; /* Already hidden/disabled */
394 603
395 if (osd.timeout > 0 && TIME_AFTER(*rb->current_tick, osd.hide_tick)) 604 if (osd->timeout > 0 && TIME_AFTER(*rb->current_tick, osd->hide_tick))
396 osd_show(OSD_HIDE); 605 _osd_show(osd, OSD_HIDE);
397} 606}
398 607
399/* Set the OSD timeout value. <= 0 = never timeout */ 608/* Set the OSD timeout value. <= 0 = never timeout */
400void osd_set_timeout(long timeout) 609static void _osd_set_timeout(struct osd *osd, long timeout)
401{ 610{
402 if (osd.status == OSD_DISABLED) 611 if (osd->status == OSD_DISABLED)
403 return; 612 return;
404 613
405 osd.timeout = timeout; 614 osd->timeout = timeout;
406 osd_monitor_timeout(); 615 _osd_monitor_timeout(osd);
407} 616}
408 617
409/* Use the OSD viewport context */ 618/* Use the OSD viewport context */
410struct viewport * osd_get_viewport(void) 619static inline struct viewport * _osd_get_viewport(struct osd *osd)
411{ 620{
412 return &osd.vp; 621 return &osd->vp;
413} 622}
414 623
415/* Get the maximum dimensions calculated by osd_init() */ 624/* Get the maximum dimensions calculated by osd_init() */
416void osd_get_max_dims(int *maxwidth, int *maxheight) 625static void _osd_get_max_dims(struct osd *osd,
626 int *maxwidth, int *maxheight)
417{ 627{
418 if (maxwidth) 628 if (maxwidth)
419 *maxwidth = osd.maxwidth; 629 *maxwidth = osd->maxwidth;
420 630
421 if (maxheight) 631 if (maxheight)
422 *maxheight = osd.maxheight; 632 *maxheight = osd->maxheight;
423} 633}
424 634
425/* Is the OSD enabled? */ 635/* Is the OSD enabled? */
426bool osd_enabled(void) 636static inline bool _osd_enabled(struct osd *osd)
427{ 637{
428 return osd.status != OSD_DISABLED; 638 return osd->status != OSD_DISABLED;
429} 639}
430 640
431 641
432/** LCD update substitutes **/ 642/** LCD update substitutes **/
433 643
434/* Prepare LCD framebuffer for regular drawing */ 644/* Prepare LCD framebuffer for regular drawing */
435void osd_lcd_update_prepare(void) 645static inline void _osd_lcd_update_prepare(struct osd *osd)
436{ 646{
437 if (osd.status == OSD_VISIBLE) 647 if (osd->status == OSD_VISIBLE)
438 { 648 {
439 osd.status = OSD_ERASED; 649 osd->status = OSD_ERASED;
440 osd_lcd_erase(); 650 _osd_erase_osd(osd);
441 } 651 }
442} 652}
443 653
444/* Update the whole screen */ 654/* Update the whole screen */
445void osd_lcd_update(void) 655static inline void _osd_lcd_update(struct osd *osd)
446{ 656{
447 if (osd.status == OSD_ERASED) 657 if (osd->status == OSD_ERASED)
448 { 658 {
449 /* Save the screen image underneath and restore the OSD image */ 659 /* Save the screen image underneath and restore the OSD image */
450 osd.status = OSD_VISIBLE; 660 osd->status = OSD_VISIBLE;
451 osd_lcd_update_back_buffer(); 661 _osd_update_back_buffer(osd);
452 osd_lcd_draw(); 662 _osd_draw_osd(osd);
453 } 663 }
454 664
455 rb->lcd_update(); 665 osd->lcd_update();
456} 666}
457 667
458/* Update a part of the screen */ 668/* Update a part of the screen */
459void osd_lcd_update_rect(int x, int y, int width, int height) 669static void _osd_lcd_update_rect(struct osd *osd,
670 int x, int y, int width, int height)
460{ 671{
461 if (osd.status == OSD_ERASED) 672 if (osd->status == OSD_ERASED)
462 { 673 {
463 /* Save the screen image underneath and restore the OSD image */ 674 /* Save the screen image underneath and restore the OSD image */
464 osd.status = OSD_VISIBLE; 675 osd->status = OSD_VISIBLE;
465 osd_lcd_update_back_buffer(); 676 _osd_update_back_buffer(osd);
466 osd_lcd_draw(); 677 _osd_draw_osd(osd);
467 } 678 }
468 679
469 rb->lcd_update_rect(x, y, width, height); 680 osd->lcd_update_rect(x, y, width, height);
681}
682
683/* Native LCD, public */
684bool osd_init(unsigned flags, void *backbuf, size_t backbuf_size,
685 osd_draw_cb_fn_t draw_cb, int *width, int *height,
686 size_t *bufused)
687{
688 native_osd.init_buffers = _osd_lcd_init_buffers;
689 native_osd.set_viewport_pos = _osd_lcd_viewport_set_pos;
690 native_osd.lcd_update = rb->lcd_update;
691 native_osd.lcd_update_rect = rb->lcd_update_rect;
692 native_osd.lcd_set_viewport = rb->lcd_set_viewport;
693 native_osd.lcd_set_framebuffer = (void *)rb->lcd_set_framebuffer;
694#if LCD_DEPTH < 4
695 native_osd.lcd_framebuffer_set_pos = NULL;
696#endif /* LCD_DEPTH < 4 */
697 native_osd.lcd_bitmap_part = (void *)rb->lcd_bitmap_part;
698
699 return _osd_init(&native_osd, flags, backbuf, backbuf_size, draw_cb,
700 width, height, bufused);
701}
702
703void osd_destroy(void)
704{
705 return _osd_destroy(&native_osd);
706}
707
708bool osd_show(unsigned flags)
709{
710 return _osd_show(&native_osd, flags);
711}
712
713bool osd_update(void)
714{
715 return _osd_update(&native_osd);
716}
717
718bool osd_update_rect(int x, int y, int width, int height)
719{
720 return _osd_update_rect(&native_osd, x, y, width, height);
721}
722
723bool osd_update_pos(int x, int y, int width, int height)
724{
725 return _osd_update_pos(&native_osd, x, y, width, height);
726}
727
728void osd_monitor_timeout(void)
729{
730 _osd_monitor_timeout(&native_osd);
731}
732
733void osd_set_timeout(long timeout)
734{
735 _osd_set_timeout(&native_osd, timeout);
736}
737
738struct viewport * osd_get_viewport(void)
739{
740 return _osd_get_viewport(&native_osd);
741}
742
743void osd_get_max_dims(int *maxwidth, int *maxheight)
744{
745 _osd_get_max_dims(&native_osd, maxwidth, maxheight);
746}
747
748bool osd_enabled(void)
749{
750 return _osd_enabled(&native_osd);
751}
752
753void osd_lcd_update_prepare(void)
754{
755 _osd_lcd_update_prepare(&native_osd);
756}
757
758
759void osd_lcd_update(void)
760{
761 _osd_lcd_update(&native_osd);
762}
763
764void osd_lcd_update_rect(int x, int y, int width, int height)
765{
766 _osd_lcd_update_rect(&native_osd, x, y, width, height);
767}
768
769#if LCD_DEPTH < 4
770/* Greylib LCD, public */
771bool osd_grey_init(unsigned flags, void *backbuf, size_t backbuf_size,
772 osd_draw_cb_fn_t draw_cb, int *width, int *height,
773 size_t *bufused)
774{
775 grey_osd.init_buffers = _osd_grey_init_buffers;
776 grey_osd.set_viewport_pos = grey_viewport_set_pos;
777 grey_osd.lcd_update = grey_update;
778 grey_osd.lcd_update_rect = grey_update_rect;
779 grey_osd.lcd_set_viewport = grey_set_viewport;
780 grey_osd.lcd_set_framebuffer = (void *)grey_set_framebuffer;
781 grey_osd.lcd_framebuffer_set_pos = grey_framebuffer_set_pos;
782 grey_osd.lcd_bitmap_part = (void *)grey_gray_bitmap_part;
783
784 return _osd_init(&grey_osd, flags, backbuf, backbuf_size, draw_cb,
785 width, height, bufused);
786}
787
788void osd_grey_destroy(void)
789{
790 return _osd_destroy(&grey_osd);
791}
792
793bool osd_grey_show(unsigned flags)
794{
795 return _osd_show(&grey_osd, flags);
796}
797
798bool osd_grey_update(void)
799{
800 return _osd_update(&grey_osd);
801}
802
803bool osd_grey_update_rect(int x, int y, int width, int height)
804{
805 return _osd_update_rect(&grey_osd, x, y, width, height);
806}
807
808bool osd_grey_update_pos(int x, int y, int width, int height)
809{
810 return _osd_update_pos(&grey_osd, x, y, width, height);
811}
812
813void osd_grey_monitor_timeout(void)
814{
815 _osd_monitor_timeout(&grey_osd);
816}
817
818void osd_grey_set_timeout(long timeout)
819{
820 _osd_set_timeout(&grey_osd, timeout);
821}
822
823struct viewport * osd_grey_get_viewport(void)
824{
825 return _osd_get_viewport(&grey_osd);
826}
827
828void osd_grey_get_max_dims(int *maxwidth, int *maxheight)
829{
830 _osd_get_max_dims(&grey_osd, maxwidth, maxheight);
831}
832
833bool osd_grey_enabled(void)
834{
835 return _osd_enabled(&grey_osd);
836}
837
838void osd_grey_lcd_update_prepare(void)
839{
840 _osd_lcd_update_prepare(&grey_osd);
841}
842
843void osd_grey_lcd_update(void)
844{
845 _osd_lcd_update(&grey_osd);
846}
847
848void osd_grey_lcd_update_rect(int x, int y, int width, int height)
849{
850 _osd_lcd_update_rect(&grey_osd, x, y, width, height);
470} 851}
852#endif /* LCD_DEPTH < 4 */