diff options
Diffstat (limited to 'firmware/drivers/lcd-bitmap-common.c')
-rw-r--r-- | firmware/drivers/lcd-bitmap-common.c | 344 |
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); +} |