Commit 2296df0a authored by Peter Hinch's avatar Peter Hinch Committed by Damien George
Browse files

extmod/modframebuf: Enable blit between different formats via a palette.

This achieves a substantial performance improvement when rendering glyphs
to color displays, the benefit increasing proportional to the number of
pixels in the glyph.
parent 996f7031
......@@ -103,16 +103,23 @@ Other methods
Shift the contents of the FrameBuffer by the given vector. This may
leave a footprint of the previous colors in the FrameBuffer.
.. method:: FrameBuffer.blit(fbuf, x, y[, key])
.. method:: FrameBuffer.blit(fbuf, x, y, key=-1, palette=None)
Draw another FrameBuffer on top of the current one at the given coordinates.
If *key* is specified then it should be a color integer and the
corresponding color will be considered transparent: all pixels with that
color value will not be drawn.
This method works between FrameBuffer instances utilising different formats,
but the resulting colors may be unexpected due to the mismatch in color
formats.
The *palette* argument enables blitting between FrameBuffers with differing
formats. Typical usage is to render a monochrome or grayscale glyph/icon to
a color display. The *palette* is a FrameBuffer instance whose format is
that of the current FrameBuffer. The *palette* height is one pixel and its
pixel width is the number of colors in the source FrameBuffer. The *palette*
for an N-bit source needs 2**N pixels; the *palette* for a monochrome source
would have 2 pixels representing background and foreground colors. The
application assigns a color to each pixel in the *palette*. The color of the
current pixel will be that of that *palette* pixel whose x position is the
color of the corresponding source pixel.
Constants
---------
......
......@@ -491,6 +491,10 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
if (n_args > 4) {
key = mp_obj_get_int(args[4]);
}
mp_obj_framebuf_t *palette = NULL;
if (n_args > 5 && args[5] != mp_const_none) {
palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
}
if (
(x >= self->width) ||
......@@ -514,6 +518,9 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
int cx1 = x1;
for (int cx0 = x0; cx0 < x0end; ++cx0) {
uint32_t col = getpixel(source, cx1, y1);
if (palette) {
col = getpixel(palette, col, 0);
}
if (col != (uint32_t)key) {
setpixel(self, cx0, y0, col);
}
......@@ -523,7 +530,7 @@ STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 6, framebuf_blit);
STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
......
# Test blit between different color spaces
try:
import framebuf, usys
except ImportError:
print("SKIP")
raise SystemExit
# Monochrome glyph/icon
w = 8
h = 8
cbuf = bytearray(w * h // 8)
fbc = framebuf.FrameBuffer(cbuf, w, h, framebuf.MONO_HLSB)
fbc.line(0, 0, 7, 7, 1)
# RGB565 destination
wd = 16
hd = 16
dest = bytearray(wd * hd * 2)
fbd = framebuf.FrameBuffer(dest, wd, hd, framebuf.RGB565)
wp = 2
bg = 0x1234
fg = 0xF800
pal = bytearray(wp * 2)
palette = framebuf.FrameBuffer(pal, wp, 1, framebuf.RGB565)
palette.pixel(0, 0, bg)
palette.pixel(1, 0, fg)
fbd.blit(fbc, 0, 0, -1, palette)
print(fbd.pixel(0, 0) == fg)
print(fbd.pixel(7, 7) == fg)
print(fbd.pixel(8, 8) == 0) # Ouside blit
print(fbd.pixel(0, 1) == bg)
print(fbd.pixel(1, 0) == bg)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment