vectorio: palettes don't color dirty rectangles

This is a breaking change with previous palette semantic with respect to python code that uses vectorio.
Displayio has breaking changes in cpy 7 for Group's removal of max_size parameter so this is as good a
time as any to break everything.

Currently:
To color vectorio shapes correctly you have to pass in a palette with length 2. Palette[0] must be set transparent and palette[1] must be the color you want.

New:
To color vectorio shapes correctly you pass in a palette with length >= 1. Palette[0] will be the color of the shape.

Also improves pixels per second when skipping areas that aren't covered by the shape.
This commit is contained in:
Kenny 2021-07-31 16:22:21 -07:00
parent 98cd989c16
commit 0afd863224
2 changed files with 22 additions and 10 deletions

View File

@ -21,7 +21,7 @@
//| class VectorShape:
//| def __init__(self, shape: Union[Polygon, Rectangle, Circle], pixel_shader: Union[displayio.ColorConverter, displayio.Palette], x: int=0, y: int=0) -> None:
//| """Binds a vector shape to a location and pixel color
//| """Binds a vector shape to a location and pixel shader. The shader can be a displayio.Palette(1); it will be asked to color pixel value 0.
//|
//| :param shape: The shape to draw.
//| :param pixel_shader: The pixel shader that produces colors from values

View File

@ -214,18 +214,30 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ
#endif
VECTORIO_SHAPE_PIXEL_DEBUG(" -> %d", input_pixel.pixel);
output_pixel.opaque = true;
if (self->pixel_shader == mp_const_none) {
output_pixel.pixel = input_pixel.pixel;
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
}
if (!output_pixel.opaque) {
// vectorio shapes use 0 to mean "area is not covered."
// We can skip all the rest of the work for this pixel if it's not currently covered by the shape.
if (input_pixel.pixel == 0) {
VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel; input area is not fully covered)\n");
full_coverage = false;
} else {
// Pixel is not transparent. Let's pull the pixel value index down to 0-base for more error-resistant palettes.
input_pixel.pixel -= 1;
output_pixel.opaque = true;
if (self->pixel_shader == mp_const_none) {
output_pixel.pixel = input_pixel.pixel;
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
}
// We double-check this to fast-path the case when a pixel is not covered by the shape & not call the color converter unnecessarily.
if (output_pixel.opaque) {
VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel from colorconverter; input area is not fully covered)\n");
full_coverage = false;
}
*mask_doubleword |= 1u << mask_bit;
if (colorspace->depth == 16) {
VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %04x 16\n", output_pixel.pixel);