From 51b70bef525565de62ac11a320d40e25d8c4a64c Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 31 Jul 2012 14:24:45 +0200 Subject: [PATCH] uterm: video: add blend() helper When drawing single glyphs we often have the glyph as alpha-only buffer so we can draw it with any color we want. blit() requires a full image that can be copied, so the new blend() helper is introduced which takes a foreground and background color and blends in an image. Only plain-alpha buffers are currently supported. Signed-off-by: David Herrmann --- src/uterm.h | 5 +++ src/uterm_internal.h | 5 +++ src/uterm_video.c | 13 ++++++++ src/uterm_video_dumb.c | 67 +++++++++++++++++++++++++++++++++++++++++ src/uterm_video_fbdev.c | 64 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+) diff --git a/src/uterm.h b/src/uterm.h index a575d6e..3cdc725 100644 --- a/src/uterm.h +++ b/src/uterm.h @@ -194,6 +194,11 @@ int uterm_screen_swap(struct uterm_screen *screen); int uterm_screen_blit(struct uterm_screen *screen, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y); +int uterm_screen_blend(struct uterm_screen *screen, + const struct uterm_video_buffer *buf, + unsigned int x, unsigned int y, + uint8_t fr, uint8_t fg, uint8_t fb, + uint8_t br, uint8_t bg, uint8_t bb); int uterm_screen_fill(struct uterm_screen *screen, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, diff --git a/src/uterm_internal.h b/src/uterm_internal.h index 2a2a7e6..cac931f 100644 --- a/src/uterm_internal.h +++ b/src/uterm_internal.h @@ -58,6 +58,11 @@ struct display_ops { int (*blit) (struct uterm_display *disp, const struct uterm_video_buffer *buf, unsigned int x, unsigned int y); + int (*blend) (struct uterm_display *disp, + const struct uterm_video_buffer *buf, + unsigned int x, unsigned int y, + uint8_t fr, uint8_t fg, uint8_t fb, + uint8_t br, uint8_t bg, uint8_t bb); int (*fill) (struct uterm_display *disp, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, unsigned int width, unsigned int height); diff --git a/src/uterm_video.c b/src/uterm_video.c index 7b63606..0d585dc 100644 --- a/src/uterm_video.c +++ b/src/uterm_video.c @@ -144,6 +144,19 @@ int uterm_screen_blit(struct uterm_screen *screen, buf, x, y); } +int uterm_screen_blend(struct uterm_screen *screen, + const struct uterm_video_buffer *buf, + unsigned int x, unsigned int y, + uint8_t fr, uint8_t fg, uint8_t fb, + uint8_t br, uint8_t bg, uint8_t bb) +{ + if (!screen) + return -EINVAL; + + return VIDEO_CALL(screen->disp->ops->blend, -EOPNOTSUPP, screen->disp, + buf, x, y, fr, fg, fb, br, bg, bb); +} + int uterm_screen_fill(struct uterm_screen *screen, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, diff --git a/src/uterm_video_dumb.c b/src/uterm_video_dumb.c index a1195a7..5f3bc77 100644 --- a/src/uterm_video_dumb.c +++ b/src/uterm_video_dumb.c @@ -413,6 +413,72 @@ static int display_blit(struct uterm_display *disp, return 0; } +static int display_blend(struct uterm_display *disp, + const struct uterm_video_buffer *buf, + unsigned int x, unsigned int y, + uint8_t fr, uint8_t fg, uint8_t fb, + uint8_t br, uint8_t bg, uint8_t bb) +{ + unsigned int tmp; + uint8_t *dst, *src; + struct dumb_rb *rb; + unsigned int width, height, i; + unsigned int sw, sh; + unsigned int r, g, b; + + if (!disp->video || !display_is_online(disp)) + return -EINVAL; + if (!buf || !video_is_awake(disp->video)) + return -EINVAL; + + rb = &disp->dumb.rb[disp->dumb.current_rb ^ 1]; + sw = disp->current_mode->dumb.info.hdisplay; + sh = disp->current_mode->dumb.info.vdisplay; + + tmp = x + buf->width; + if (tmp < x || x >= sw) + return -EINVAL; + if (tmp > sw) + width = sw - x; + else + width = buf->width; + + tmp = y + buf->height; + if (tmp < y || y >= sh) + return -EINVAL; + if (tmp > sh) + height = sh - y; + else + height = buf->height; + + dst = rb->map; + dst = &dst[y * rb->stride + x * 4]; + src = buf->data; + + if (buf->format == UTERM_FORMAT_GREY) { + while (height--) { + for (i = 0; i < width; ++i) { + r = (fr & 0xff) * src[i] / 255 + + (br & 0xff) * (255 - src[i]) / 255; + g = (fg & 0xff) * src[i] / 255 + + (bg & 0xff) * (255 - src[i]) / 255; + b = (fb & 0xff) * src[i] / 255 + + (bb & 0xff) * (255 - src[i]) / 255; + ((uint32_t*)dst)[i] = + ((r & 0xff) << 16) | + ((g & 0xff) << 8) | + (b & 0xff); + } + dst += rb->stride; + src += buf->stride; + } + } else { + log_warning("using unsupported buffer format for blending"); + } + + return 0; +} + static int display_fill(struct uterm_display *disp, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, @@ -774,6 +840,7 @@ const struct display_ops dumb_display_ops = { .use = NULL, .swap = display_swap, .blit = display_blit, + .blend = display_blend, .fill = display_fill, }; diff --git a/src/uterm_video_fbdev.c b/src/uterm_video_fbdev.c index 9bd0134..d7068ac 100644 --- a/src/uterm_video_fbdev.c +++ b/src/uterm_video_fbdev.c @@ -380,6 +380,69 @@ static int display_blit(struct uterm_display *disp, return 0; } +static int display_blend(struct uterm_display *disp, + const struct uterm_video_buffer *buf, + unsigned int x, unsigned int y, + uint8_t fr, uint8_t fg, uint8_t fb, + uint8_t br, uint8_t bg, uint8_t bb) +{ + unsigned int tmp; + uint8_t *dst, *src; + unsigned int width, height, i; + unsigned int r, g, b; + + if (!disp->video || !(disp->flags & DISPLAY_ONLINE)) + return -EINVAL; + if (!buf || !video_is_awake(disp->video)) + return -EINVAL; + + tmp = x + buf->width; + if (tmp < x || x >= disp->fbdev.xres) + return -EINVAL; + if (tmp > disp->fbdev.xres) + width = disp->fbdev.xres - x; + else + width = buf->width; + + tmp = y + buf->height; + if (tmp < y || y >= disp->fbdev.yres) + return -EINVAL; + if (tmp > disp->fbdev.yres) + height = disp->fbdev.yres - y; + else + height = buf->height; + + if (!(disp->flags & DISPLAY_DBUF) || disp->fbdev.bufid) + dst = disp->fbdev.map; + else + dst = &disp->fbdev.map[disp->fbdev.yres * disp->fbdev.stride]; + dst = &dst[y * disp->fbdev.stride + x * disp->fbdev.bpp]; + src = buf->data; + + if (buf->format == UTERM_FORMAT_GREY) { + while (height--) { + for (i = 0; i < width; ++i) { + r = (fr & 0xff) * src[i] / 255 + + (br & 0xff) * (255 - src[i]) / 255; + g = (fg & 0xff) * src[i] / 255 + + (bg & 0xff) * (255 - src[i]) / 255; + b = (fb & 0xff) * src[i] / 255 + + (bb & 0xff) * (255 - src[i]) / 255; + ((uint32_t*)dst)[i] = + ((r & 0xff) << 16) | + ((g & 0xff) << 8) | + (b & 0xff); + } + dst += disp->fbdev.stride; + src += buf->stride; + } + } else { + log_warning("using unsupported buffer format for blending"); + } + + return 0; +} + static int display_fill(struct uterm_display *disp, uint8_t r, uint8_t g, uint8_t b, unsigned int x, unsigned int y, @@ -516,6 +579,7 @@ const struct display_ops fbdev_display_ops = { .use = NULL, .swap = display_swap, .blit = display_blit, + .blend = display_blend, .fill = display_fill, };