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 <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-07-31 14:24:45 +02:00
parent 6ab01cbf6b
commit 51b70bef52
5 changed files with 154 additions and 0 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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,
};

View File

@ -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,
};