summaryrefslogtreecommitdiffstats
path: root/firmware/drivers/lcd-bitmap-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r--firmware/drivers/lcd-bitmap-common.c344
1 files changed, 318 insertions, 26 deletions
diff --git a/firmware/drivers/lcd-bitmap-common.c b/firmware/drivers/lcd-bitmap-common.c
index 9a5f865f2a..975c494b5a 100644
--- a/firmware/drivers/lcd-bitmap-common.c
+++ b/firmware/drivers/lcd-bitmap-common.c
@@ -53,6 +53,158 @@
extern void viewport_set_buffer(struct viewport *vp,
struct frame_buffer_t *buffer,
const enum screen_type screen); /* viewport.c */
+
+/*
+ * In-viewport clipping functions:
+ *
+ * These clip a primitive (pixel, line, rect) given in
+ * viewport-relative coordinates to the specified viewport,
+ * and translate it to screen coordinates. They return
+ * false if the resulting primitive would be off-screen.
+ */
+
+static inline bool clip_viewport_pixel(struct viewport *vp, int *x, int *y)
+{
+ if (*x < 0 || *x >= vp->width ||
+ *y < 0 || *y >= vp->height)
+ return false;
+
+ *x += vp->x;
+ *y += vp->y;
+ return true;
+}
+
+static inline bool clip_viewport_hline(struct viewport *vp,
+ int *x1, int *x2, int *y)
+{
+ if (*y < 0 || *y >= vp->height)
+ return false;
+
+ if (*x2 < *x1) {
+ int tmp = *x2;
+ *x2 = *x1;
+ *x1 = tmp;
+ }
+
+ if (*x1 < 0)
+ *x1 = 0;
+ else if (*x1 >= vp->width)
+ return false;
+
+ if (*x2 < 0)
+ return false;
+ else if (*x2 >= vp->width)
+ *x2 = vp->width - 1;
+
+ *x1 += vp->x;
+ *x2 += vp->x;
+ *y += vp->y;
+ return true;
+}
+
+static inline bool clip_viewport_vline(struct viewport *vp,
+ int *x, int *y1, int *y2)
+{
+ if (*x < 0 || *x >= vp->width)
+ return false;
+
+ if (*y2 < *y1) {
+ int tmp = *y2;
+ *y2 = *y1;
+ *y1 = tmp;
+ }
+
+ if (*y1 < 0)
+ *y1 = 0;
+ else if (*y1 >= vp->height)
+ return false;
+
+ if (*y2 < 0)
+ return false;
+ else if (*y2 >= vp->height)
+ *y2 = vp->height - 1;
+
+ *x += vp->x;
+ *y1 += vp->y;
+ *y2 += vp->y;
+ return true;
+}
+
+static inline bool clip_viewport_rect(struct viewport *vp,
+ int *x, int *y, int *width, int *height,
+ int *src_x, int *src_y)
+{
+ if (*x < 0) {
+ *width += *x;
+ if (src_x)
+ *src_x -= *x;
+ *x = 0;
+ }
+
+ if (*y < 0) {
+ *height += *y;
+ if (src_y)
+ *src_y -= *y;
+ *y = 0;
+ }
+
+ if (*x + *width > vp->width)
+ *width = vp->width - *x;
+
+ if (*y + *height > vp->height)
+ *height = vp->height - *y;
+
+ *x += vp->x;
+ *y += vp->y;
+ return *width > 0 && *height > 0;
+}
+
+/*** parameter handling ***/
+
+void LCDFN(set_drawmode)(int mode)
+{
+ LCDFN(current_viewport)->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
+}
+
+int LCDFN(get_drawmode)(void)
+{
+ return LCDFN(current_viewport)->drawmode;
+}
+
+int LCDFN(getwidth)(void)
+{
+ return LCDFN(current_viewport)->width;
+}
+
+int LCDFN(getheight)(void)
+{
+ return LCDFN(current_viewport)->height;
+}
+
+void LCDFN(setfont)(int newfont)
+{
+ LCDFN(current_viewport)->font = newfont;
+}
+
+int LCDFN(getfont)(void)
+{
+ return LCDFN(current_viewport)->font;
+}
+
+int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
+{
+ return font_getstringsize(str, w, h, LCDFN(current_viewport)->font);
+}
+
+#if LCDM(DEPTH) > 1
+void LCDFN(set_drawinfo)(int mode, unsigned foreground, unsigned background)
+{
+ LCDFN(set_drawmode)(mode);
+ LCDFN(set_foreground)(foreground);
+ LCDFN(set_background)(background);
+}
+#endif
+
/*
* draws the borders of the current viewport
**/
@@ -69,6 +221,34 @@ void LCDFN(fill_viewport)(void)
LCDFN(fillrect)(0, 0, LCDFN(current_viewport)->width, LCDFN(current_viewport)->height);
}
+#if LCDM(DEPTH) < 8
+/*
+ * clear the current viewport - grayscale displays
+ */
+void LCDFN(clear_viewport)(void)
+{
+ struct viewport *vp = LCDFN(current_viewport);
+ int oldmode;
+
+ if (vp == &default_vp && default_vp.buffer == &LCDFN(framebuffer_default))
+ {
+ LCDFN(clear_display)();
+ }
+ else
+ {
+ oldmode = vp->drawmode;
+ vp->drawmode ^= DRMODE_INVERSEVID;
+ vp->drawmode |= DRMODE_SOLID;
+
+ LCDFN(fillrect)(0, 0, vp->width, vp->height);
+
+ vp->drawmode = oldmode;
+ LCDFN(scroll_stop_viewport)(vp);
+ }
+
+ vp->flags &= ~VP_FLAG_VP_SET_CLEAN;
+}
+#endif
/*** Viewports ***/
/* init_viewport Notes: When a viewport is initialized
@@ -84,6 +264,7 @@ struct viewport* LCDFN(init_viewport)(struct viewport* vp)
{
vp = &default_vp;
vp->buffer = fb_default;
+ return vp;
}
/* use defaults if no buffer is provided */
@@ -132,16 +313,13 @@ struct viewport* LCDFN(set_viewport_ex)(struct viewport* vp, int flags)
* expected.
*/
- if((unsigned) vp->x > (unsigned) LCDM(WIDTH)
- || (unsigned) vp->y > (unsigned) LCDM(HEIGHT)
+ if( vp->x < 0 || vp->y < 0
+ || vp->x > LCDM(WIDTH)
+ || vp->y > LCDM(HEIGHT)
|| vp->x + vp->width > LCDM(WIDTH)
|| vp->y + vp->height > LCDM(HEIGHT))
{
-#if !defined(HAVE_VIEWPORT_CLIP)
DEBUGF("ERROR: "
-#else
- DEBUGF("NOTE: "
-#endif
"set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
vp->x, vp->y, vp->width, vp->height);
}
@@ -162,33 +340,22 @@ struct viewport* LCDFN(set_viewport)(struct viewport* vp)
return LCDFN(set_viewport_ex)(vp, VP_FLAG_VP_DIRTY);
}
-struct viewport *LCDFN(get_viewport)(bool *is_default)
-{
-#if 0
- *is_default = memcmp(LCDFN(current_viewport),
- &default_vp, sizeof(struct viewport)) == 0;
-#else
- *is_default = LCDFN(current_viewport) == &default_vp;
-#endif
-
- return LCDFN(current_viewport);
-}
-
void LCDFN(update_viewport)(void)
{
struct viewport* vp = LCDFN(current_viewport);
- if (vp->buffer->stride != LCDFN(framebuffer_default.stride))
- {
- LCDFN(update_viewport_rect)(0,0, vp->width, vp->height);
- return;
- }
- LCDFN(update_rect)(vp->x, vp->y, vp->width, vp->height);
+ LCDFN(update_viewport_rect)(0, 0, vp->width, vp->height);
}
void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
{
struct viewport* vp = LCDFN(current_viewport);
-
+ if ((vp->flags & VP_FLAG_OWNER_UPDATE) == VP_FLAG_OWNER_UPDATE)
+ {
+#ifdef LOGF_ENABLE
+ logf("%s ignored - owner update", __func__);
+#endif
+ return;
+ }
/* handle the case of viewport with differing stride from main screen */
if (vp->buffer->stride != LCDFN(framebuffer_default.stride))
{
@@ -532,7 +699,7 @@ static bool LCDFN(puts_scroll_worker)(int x, int y, const unsigned char *string,
}
/* copy contents to the line buffer */
- strlcpy(s->linebuffer, string, sizeof(s->linebuffer));
+ strmemccpy(s->linebuffer, string, sizeof(s->linebuffer));
/* scroll bidirectional or forward only depending on the string width */
if ( LCDFN(scroll_info).bidir_limit ) {
s->bidir = w < (vp->width) *
@@ -677,3 +844,128 @@ void LCDFN(nine_segment_bmp)(const struct bitmap* bm, int x, int y,
LCDFN(bmp_part)(bm, bm->width - corner_w, bm->width - corner_h,
width - corner_w, height - corner_h, corner_w, corner_h);
}
+
+void LCDFN(drawpixel)(int x, int y)
+{
+ struct viewport *vp = LCDFN(current_viewport);
+ if (clip_viewport_pixel(vp, &x, &y))
+ {
+#if LCDM(DEPTH) >= 8
+ LCDFN(fastpixelfunc_type) *pfunc = LCDFN(fastpixelfuncs)[vp->drawmode];
+ void *(*fbaddr)(int x, int y) = vp->buffer->get_address_fn;
+ pfunc(fbaddr(x, y));
+#else
+ LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[vp->drawmode];
+ pfunc(x, y);
+#endif
+ }
+}
+
+void LCDFN(drawline)(int x1, int y1, int x2, int y2)
+{
+ struct viewport *vp = LCDFN(current_viewport);
+ int numpixels;
+ int i;
+ int deltax, deltay;
+ int d, dinc1, dinc2;
+ int x, xinc1, xinc2;
+ int y, yinc1, yinc2;
+
+ deltay = abs(y2 - y1);
+ if (deltay == 0)
+ {
+ lcd_hline(x1, x2, y1);
+ return;
+ }
+
+ deltax = abs(x2 - x1);
+ if (deltax == 0)
+ {
+ lcd_vline(x1, y1, y2);
+ return;
+ }
+
+ xinc2 = 1;
+ yinc2 = 1;
+
+ if (deltax >= deltay)
+ {
+ numpixels = deltax;
+ d = 2 * deltay - deltax;
+ dinc1 = deltay * 2;
+ dinc2 = (deltay - deltax) * 2;
+ xinc1 = 1;
+ yinc1 = 0;
+ }
+ else
+ {
+ numpixels = deltay;
+ d = 2 * deltax - deltay;
+ dinc1 = deltax * 2;
+ dinc2 = (deltax - deltay) * 2;
+ xinc1 = 0;
+ yinc1 = 1;
+ }
+ numpixels++; /* include endpoints */
+
+ if (x1 > x2)
+ {
+ xinc1 = -xinc1;
+ xinc2 = -xinc2;
+ }
+
+ if (y1 > y2)
+ {
+ yinc1 = -yinc1;
+ yinc2 = -yinc2;
+ }
+
+ x = x1;
+ y = y1;
+
+#if LCDM(DEPTH) >= 8
+ LCDFN(fastpixelfunc_type) *pfunc = LCDFN(fastpixelfuncs)[vp->drawmode];
+ void *(*fbaddr)(int x, int y) = vp->buffer->get_address_fn;
+#else
+ LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[vp->drawmode];
+#endif
+
+ for (i = 0; i < numpixels; i++)
+ {
+ if (x >= 0 && y >= 0 && x < vp->width && y < vp->height)
+ {
+#if LCDM(DEPTH) >= 8
+ pfunc(fbaddr(x + vp->x, y + vp->y));
+#else
+ pfunc(x + vp->x, y + vp->y);
+#endif
+ }
+
+ if (d < 0)
+ {
+ d += dinc1;
+ x += xinc1;
+ y += yinc1;
+ }
+ else
+ {
+ d += dinc2;
+ x += xinc2;
+ y += yinc2;
+ }
+ }
+}
+
+void LCDFN(drawrect)(int x, int y, int width, int height)
+{
+ if ((width <= 0) || (height <= 0))
+ return;
+
+ int x2 = x + width - 1;
+ int y2 = y + height - 1;
+
+ LCDFN(vline)(x, y, y2);
+ LCDFN(vline)(x2, y, y2);
+ LCDFN(hline)(x, x2, y);
+ LCDFN(hline)(x, x2, y2);
+}