Skip to content

Commit 0afd863

Browse files
committed
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.
1 parent 98cd989 commit 0afd863

File tree

2 files changed

+22
-10
lines changed

2 files changed

+22
-10
lines changed

shared-bindings/vectorio/VectorShape.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
//| class VectorShape:
2323
//| def __init__(self, shape: Union[Polygon, Rectangle, Circle], pixel_shader: Union[displayio.ColorConverter, displayio.Palette], x: int=0, y: int=0) -> None:
24-
//| """Binds a vector shape to a location and pixel color
24+
//| """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.
2525
//|
2626
//| :param shape: The shape to draw.
2727
//| :param pixel_shader: The pixel shader that produces colors from values

shared-module/vectorio/VectorShape.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,30 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ
214214
#endif
215215
VECTORIO_SHAPE_PIXEL_DEBUG(" -> %d", input_pixel.pixel);
216216

217-
output_pixel.opaque = true;
218-
if (self->pixel_shader == mp_const_none) {
219-
output_pixel.pixel = input_pixel.pixel;
220-
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
221-
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
222-
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
223-
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
224-
}
225-
if (!output_pixel.opaque) {
217+
// vectorio shapes use 0 to mean "area is not covered."
218+
// We can skip all the rest of the work for this pixel if it's not currently covered by the shape.
219+
if (input_pixel.pixel == 0) {
226220
VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel; input area is not fully covered)\n");
227221
full_coverage = false;
228222
} else {
223+
// Pixel is not transparent. Let's pull the pixel value index down to 0-base for more error-resistant palettes.
224+
input_pixel.pixel -= 1;
225+
output_pixel.opaque = true;
226+
227+
if (self->pixel_shader == mp_const_none) {
228+
output_pixel.pixel = input_pixel.pixel;
229+
} else if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) {
230+
output_pixel.opaque = displayio_palette_get_color(self->pixel_shader, colorspace, input_pixel.pixel, &output_pixel.pixel);
231+
} else if (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type)) {
232+
displayio_colorconverter_convert(self->pixel_shader, colorspace, &input_pixel, &output_pixel);
233+
}
234+
235+
// We double-check this to fast-path the case when a pixel is not covered by the shape & not call the color converter unnecessarily.
236+
if (output_pixel.opaque) {
237+
VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel from colorconverter; input area is not fully covered)\n");
238+
full_coverage = false;
239+
}
240+
229241
*mask_doubleword |= 1u << mask_bit;
230242
if (colorspace->depth == 16) {
231243
VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %04x 16\n", output_pixel.pixel);

0 commit comments

Comments
 (0)