From 0afd863224c743914beaee948d4449fa896325dd Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sat, 31 Jul 2021 16:22:21 -0700 Subject: [PATCH 01/25] 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. --- shared-bindings/vectorio/VectorShape.c | 2 +- shared-module/vectorio/VectorShape.c | 30 ++++++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index ae8532eb95..be24a056c9 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -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 diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index f0b6a725c1..87dc78d0c8 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -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); From 1b67b91eddfc4222d2db3882fb889338b161d87b Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sat, 31 Jul 2021 16:59:44 -0700 Subject: [PATCH 02/25] fix inverted logic --- shared-module/vectorio/VectorShape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 87dc78d0c8..fb8ce963f1 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -233,7 +233,7 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ } // 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) { + if (!output_pixel.opaque) { VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel from colorconverter; input area is not fully covered)\n"); full_coverage = false; } From 8607cdd7830220f5ad30fc62e367b0fc01596855 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sun, 1 Aug 2021 13:01:57 -0700 Subject: [PATCH 03/25] vectorio: add draw protocol * Removes VectorShape from user python interactions * Re-integrates vectorio with displayio behind draw protocol implementations * Implements draw protocol with VectorShape * Composes VectorShape behaviors into Rectangle, Circle and Polygon * Fixes terrible pixel garbage being left behind * Improves redraw performance (heuristically) by tracking dirty area separately from current area. Known Issues: It does not work with transposed views. --- shared-bindings/vectorio/Circle.c | 36 ++++- shared-bindings/vectorio/Circle.h | 2 + shared-bindings/vectorio/Polygon.c | 36 ++++- shared-bindings/vectorio/Polygon.h | 2 + shared-bindings/vectorio/Rectangle.c | 36 ++++- shared-bindings/vectorio/Rectangle.h | 2 + shared-bindings/vectorio/VectorShape.c | 84 ++++++------ shared-bindings/vectorio/VectorShape.h | 14 +- shared-bindings/vectorio/__init__.c | 2 +- shared-bindings/vectorio/__init__.h | 41 ++++++ shared-module/displayio/Group.c | 51 ++++--- shared-module/vectorio/Circle.c | 5 + shared-module/vectorio/Circle.h | 1 + shared-module/vectorio/Polygon.c | 22 +-- shared-module/vectorio/Polygon.h | 1 + shared-module/vectorio/Rectangle.c | 11 +- shared-module/vectorio/Rectangle.h | 1 + shared-module/vectorio/VectorShape.c | 180 ++++++++++++++++--------- shared-module/vectorio/VectorShape.h | 3 +- 19 files changed, 374 insertions(+), 156 deletions(-) create mode 100644 shared-bindings/vectorio/__init__.h diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c index 673a976687..d6edba7063 100644 --- a/shared-bindings/vectorio/Circle.c +++ b/shared-bindings/vectorio/Circle.c @@ -1,5 +1,6 @@ - +#include "shared-bindings/vectorio/__init__.h" #include "shared-bindings/vectorio/Circle.h" +#include "shared-bindings/vectorio/VectorShape.h" #include @@ -11,15 +12,21 @@ //| class Circle: //| -//| def __init__(self, radius: int) -> None: +//| def __init__(self, pixel_shader: Union[ColorConverter, Palette] radius: int, x: int, y: int) -> None: //| """Circle is positioned on screen by its center point. //| -//| :param radius: The radius of the circle in pixels""" +//| :param pixel_shader: The pixel shader that produces colors from values +//| :param radius: The radius of the circle in pixels +//| :param x: Initial x position of the axis. +//| :param y: Initial y position of the axis.""" //| static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_radius }; + enum { ARG_pixel_shader, ARG_radius, ARG_x, ARG_y }; static const mp_arg_t allowed_args[] = { + { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -33,9 +40,22 @@ static mp_obj_t vectorio_circle_make_new(const mp_obj_type_t *type, size_t n_arg self->base.type = &vectorio_circle_type; common_hal_vectorio_circle_construct(self, radius); + // VectorShape parts + mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; + int16_t x = args[ARG_x].u_int; + int16_t y = args[ARG_y].u_int; + mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y); + self->draw_protocol_instance = vector_shape; + return MP_OBJ_FROM_PTR(self); } +STATIC const vectorio_draw_protocol_t circle_draw_protocol = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw) + .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_circle_get_draw_protocol, + .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl +}; + //| radius : int //| """The radius of the circle in pixels.""" @@ -62,13 +82,21 @@ const mp_obj_property_t vectorio_circle_radius_obj = { STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = { + // Properties { MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_circle_locals_dict, vectorio_circle_locals_dict_table); const mp_obj_type_t vectorio_circle_type = { { &mp_type_type }, .name = MP_QSTR_Circle, + .flags = MP_TYPE_FLAG_EXTENDED, .make_new = vectorio_circle_make_new, .locals_dict = (mp_obj_dict_t *)&vectorio_circle_locals_dict, + MP_TYPE_EXTENDED_FIELDS( + .protocol = &circle_draw_protocol, + ), }; diff --git a/shared-bindings/vectorio/Circle.h b/shared-bindings/vectorio/Circle.h index e8fc048eb8..37bbe9e65b 100644 --- a/shared-bindings/vectorio/Circle.h +++ b/shared-bindings/vectorio/Circle.h @@ -19,4 +19,6 @@ void common_hal_vectorio_circle_get_area(void *circle, displayio_area_t *out_are int16_t common_hal_vectorio_circle_get_radius(void *circle); void common_hal_vectorio_circle_set_radius(void *circle, int16_t radius); +mp_obj_t common_hal_vectorio_circle_get_draw_protocol(void *circle); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c index 23c7961ec7..261e7ae55e 100644 --- a/shared-bindings/vectorio/Polygon.c +++ b/shared-bindings/vectorio/Polygon.c @@ -1,6 +1,7 @@ - +#include "shared-bindings/vectorio/__init__.h" #include "shared-module/vectorio/__init__.h" #include "shared-bindings/vectorio/Polygon.h" +#include "shared-bindings/vectorio/VectorShape.h" #include @@ -16,15 +17,21 @@ //| class Polygon: -//| def __init__(self, points: List[Tuple[int, int]]) -> None: +//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], points: List[Tuple[int, int]], x: int, y: int) -> None: //| """Represents a closed shape by ordered vertices //| -//| :param points: Vertices for the polygon""" +//| :param pixel_shader: The pixel shader that produces colors from values +//| :param points: Vertices for the polygon +//| :param x: Initial screen x position of the 0,0 origin in the points list. +//| :param y: Initial screen y position of the 0,0 origin in the points list.""" //| static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_points_list }; + enum { ARG_pixel_shader, ARG_points_list, ARG_x, ARG_y }; static const mp_arg_t allowed_args[] = { + { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -38,9 +45,22 @@ static mp_obj_t vectorio_polygon_make_new(const mp_obj_type_t *type, size_t n_ar common_hal_vectorio_polygon_construct(self, args[ARG_points_list].u_obj); + // VectorShape parts + mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; + int16_t x = args[ARG_x].u_int; + int16_t y = args[ARG_y].u_int; + mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y); + self->draw_protocol_instance = vector_shape; + return MP_OBJ_FROM_PTR(self); } +STATIC const vectorio_draw_protocol_t polygon_draw_protocol = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw) + .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_polygon_get_draw_protocol, + .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl +}; + //| points: List[Tuple[int, int]] //| """Set a new look and shape for this polygon""" @@ -67,13 +87,21 @@ const mp_obj_property_t vectorio_polygon_points_obj = { }; STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = { + // Properties { MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_polygon_locals_dict, vectorio_polygon_locals_dict_table); const mp_obj_type_t vectorio_polygon_type = { { &mp_type_type }, .name = MP_QSTR_Polygon, + .flags = MP_TYPE_FLAG_EXTENDED, .make_new = vectorio_polygon_make_new, .locals_dict = (mp_obj_dict_t *)&vectorio_polygon_locals_dict, + MP_TYPE_EXTENDED_FIELDS( + .protocol = &polygon_draw_protocol, + ), }; diff --git a/shared-bindings/vectorio/Polygon.h b/shared-bindings/vectorio/Polygon.h index 5594fbec4a..68136be6bd 100644 --- a/shared-bindings/vectorio/Polygon.h +++ b/shared-bindings/vectorio/Polygon.h @@ -20,5 +20,7 @@ void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *out_a mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self); void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list); +mp_obj_t common_hal_vectorio_polygon_get_draw_protocol(void *polygon); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c index a50a8a14b3..98e38f0c6b 100644 --- a/shared-bindings/vectorio/Rectangle.c +++ b/shared-bindings/vectorio/Rectangle.c @@ -1,5 +1,7 @@ - +#include "shared-bindings/vectorio/__init__.h" #include "shared-bindings/vectorio/Rectangle.h" +#include "shared-module/vectorio/VectorShape.h" +#include "shared-bindings/vectorio/VectorShape.h" #include @@ -8,17 +10,23 @@ #include "supervisor/shared/translate.h" //| class Rectangle: -//| def __init__(self, width: int, height: int) -> None: +//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], width: int, height: int, x: int, y: int) -> None: //| """Represents a rectangle by defining its bounds //| +//| :param pixel_shader: The pixel shader that produces colors from values //| :param width: The number of pixels wide -//| :param height: The number of pixels high""" +//| :param height: The number of pixels high +//| :param x: Initial x position of the top left corner. +//| :param y: Initial y position of the top left corner.""" //| static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_width, ARG_height }; + enum { ARG_pixel_shader, ARG_width, ARG_height, ARG_x, ARG_y }; static const mp_arg_t allowed_args[] = { + { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -36,17 +44,37 @@ static mp_obj_t vectorio_rectangle_make_new(const mp_obj_type_t *type, size_t n_ self->base.type = &vectorio_rectangle_type; common_hal_vectorio_rectangle_construct(self, width, height); + // VectorShape parts + mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; + int16_t x = args[ARG_x].u_int; + int16_t y = args[ARG_y].u_int; + mp_obj_t vector_shape = vectorio_vector_shape_make_new(self, pixel_shader, x, y); + self->draw_protocol_instance = vector_shape; + return MP_OBJ_FROM_PTR(self); } +STATIC const vectorio_draw_protocol_t rectangle_draw_protocol = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_draw) + .draw_get_protocol_self = (draw_get_protocol_self_fun)common_hal_vectorio_rectangle_get_draw_protocol, + .draw_protocol_impl = &vectorio_vector_shape_draw_protocol_impl +}; STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = { + // Properties + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_rectangle_locals_dict, vectorio_rectangle_locals_dict_table); const mp_obj_type_t vectorio_rectangle_type = { { &mp_type_type }, .name = MP_QSTR_Rectangle, + .flags = MP_TYPE_FLAG_EXTENDED, .make_new = vectorio_rectangle_make_new, .locals_dict = (mp_obj_dict_t *)&vectorio_rectangle_locals_dict, + MP_TYPE_EXTENDED_FIELDS( + .protocol = &rectangle_draw_protocol, + ), }; diff --git a/shared-bindings/vectorio/Rectangle.h b/shared-bindings/vectorio/Rectangle.h index bb461ed9d5..24b103c26e 100644 --- a/shared-bindings/vectorio/Rectangle.h +++ b/shared-bindings/vectorio/Rectangle.h @@ -12,4 +12,6 @@ uint32_t common_hal_vectorio_rectangle_get_pixel(void *rectangle, int16_t x, int void common_hal_vectorio_rectangle_get_area(void *rectangle, displayio_area_t *out_area); +mp_obj_t common_hal_vectorio_rectangle_get_draw_protocol(void *rectangle); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index be24a056c9..fc46eceec7 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -19,37 +19,16 @@ #include "supervisor/shared/translate.h" -//| 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 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 -//| :param x: Initial x position of the center axis of the shape within the parent. -//| :param y: Initial y position of the center axis of the shape within the parent.""" -//| ... -//| -STATIC mp_obj_t vectorio_vector_shape_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_shape, ARG_pixel_shader, ARG_x, ARG_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_shape, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; +// shape: The shape implementation to draw. +// pixel_shader: The pixel shader that produces colors from values. The shader can be a displayio.Palette(1); it will be asked to color pixel value 0. +// x: Initial x position of the center axis of the shape within the parent. +// y: Initial y position of the center axis of the shape within the parent.""" +mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pixel_shader, int16_t x, int16_t y) { if (!mp_obj_is_type(pixel_shader, &displayio_colorconverter_type) && !mp_obj_is_type(pixel_shader, &displayio_palette_type)) { mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader); } - int16_t x = args[ARG_x].u_int; - int16_t y = args[ARG_y].u_int; - - mp_obj_t shape = args[ARG_shape].u_obj; vectorio_ishape_t ishape; // Wire up shape functions if (mp_obj_is_type(shape, &vectorio_polygon_type)) { @@ -92,18 +71,31 @@ STATIC mp_obj_t vectorio_vector_shape_make_new(const mp_obj_type_t *type, size_t return MP_OBJ_FROM_PTR(self); } +vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl = { + .draw_fill_area = (draw_fill_area_fun)vectorio_vector_shape_fill_area, + .draw_get_dirty_area = (draw_get_dirty_area_fun)vectorio_vector_shape_get_dirty_area, + .draw_update_transform = (draw_update_transform_fun)vectorio_vector_shape_update_transform, + .draw_finish_refresh = (draw_finish_refresh_fun)vectorio_vector_shape_finish_refresh, + .draw_get_refresh_areas = (draw_get_refresh_areas_fun)vectorio_vector_shape_get_refresh_areas, +}; + //| x: int //| """X position of the center point of the shape in the parent.""" //| -STATIC mp_obj_t vectorio_vector_shape_obj_get_x(mp_obj_t self_in) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_get_x(mp_obj_t wrapper_shape) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + return MP_OBJ_NEW_SMALL_INT(common_hal_vectorio_vector_shape_get_x(self)); } MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_x_obj, vectorio_vector_shape_obj_get_x); -STATIC mp_obj_t vectorio_vector_shape_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_set_x(mp_obj_t wrapper_shape, mp_obj_t x_obj) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); mp_int_t x = mp_obj_get_int(x_obj); common_hal_vectorio_vector_shape_set_x(self, x); @@ -122,14 +114,19 @@ const mp_obj_property_t vectorio_vector_shape_x_obj = { //| y: int //| """Y position of the center point of the shape in the parent.""" //| -STATIC mp_obj_t vectorio_vector_shape_obj_get_y(mp_obj_t self_in) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_get_y(mp_obj_t wrapper_shape) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + return MP_OBJ_NEW_SMALL_INT(common_hal_vectorio_vector_shape_get_y(self)); } MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_y_obj, vectorio_vector_shape_obj_get_y); -STATIC mp_obj_t vectorio_vector_shape_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_set_y(mp_obj_t wrapper_shape, mp_obj_t y_obj) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); mp_int_t y = mp_obj_get_int(y_obj); common_hal_vectorio_vector_shape_set_y(self, y); @@ -148,14 +145,20 @@ const mp_obj_property_t vectorio_vector_shape_y_obj = { //| pixel_shader: Union[displayio.ColorConverter, displayio.Palette] //| """The pixel shader of the shape.""" //| -STATIC mp_obj_t vectorio_vector_shape_obj_get_pixel_shader(mp_obj_t self_in) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_get_pixel_shader(mp_obj_t wrapper_shape) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + return common_hal_vectorio_vector_shape_get_pixel_shader(self); } MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_pixel_shader_obj, vectorio_vector_shape_obj_get_pixel_shader); -STATIC mp_obj_t vectorio_vector_shape_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) { - vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t vectorio_vector_shape_obj_set_pixel_shader(mp_obj_t wrapper_shape, mp_obj_t pixel_shader) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + if (!mp_obj_is_type(pixel_shader, &displayio_palette_type) && !mp_obj_is_type(pixel_shader, &displayio_colorconverter_type)) { mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter")); } @@ -175,16 +178,11 @@ const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj = { STATIC const mp_rom_map_elem_t vectorio_vector_shape_locals_dict_table[] = { - // Properties - { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, - { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, - { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_vector_shape_locals_dict, vectorio_vector_shape_locals_dict_table); const mp_obj_type_t vectorio_vector_shape_type = { { &mp_type_type }, .name = MP_QSTR_VectorShape, - .make_new = vectorio_vector_shape_make_new, .locals_dict = (mp_obj_dict_t *)&vectorio_vector_shape_locals_dict, }; diff --git a/shared-bindings/vectorio/VectorShape.h b/shared-bindings/vectorio/VectorShape.h index fa11f73ffd..4cf2ae373b 100644 --- a/shared-bindings/vectorio/VectorShape.h +++ b/shared-bindings/vectorio/VectorShape.h @@ -1,11 +1,18 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H +#include "py/objproperty.h" + +#include "shared-bindings/vectorio/__init__.h" #include "shared-module/vectorio/VectorShape.h" #include "shared-module/displayio/area.h" extern const mp_obj_type_t vectorio_vector_shape_type; +// Python shared bindings constructor +mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pixel_shader, int16_t x, int16_t y); + +// C data constructor void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self, vectorio_ishape_t ishape, mp_obj_t pixel_shader, uint16_t x, uint16_t y); @@ -21,7 +28,12 @@ void common_hal_vectorio_vector_shape_set_y(vectorio_vector_shape_t *self, mp_in mp_obj_t common_hal_vectorio_vector_shape_get_pixel_shader(vectorio_vector_shape_t *self); void common_hal_vectorio_vector_shape_set_pixel_shader(vectorio_vector_shape_t *self, mp_obj_t pixel_shader); - void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displayio_buffer_transform_t *group_transform); +// Composable property definition for shapes that use VectorShape +extern vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl; +extern const mp_obj_property_t vectorio_vector_shape_x_obj; +extern const mp_obj_property_t vectorio_vector_shape_y_obj; +extern const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj; + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H diff --git a/shared-bindings/vectorio/__init__.c b/shared-bindings/vectorio/__init__.c index 12fb4d72b1..556bfe59ec 100644 --- a/shared-bindings/vectorio/__init__.c +++ b/shared-bindings/vectorio/__init__.c @@ -16,7 +16,7 @@ STATIC const mp_rom_map_elem_t vectorio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Circle), MP_ROM_PTR(&vectorio_circle_type) }, { MP_ROM_QSTR(MP_QSTR_Polygon), MP_ROM_PTR(&vectorio_polygon_type) }, { MP_ROM_QSTR(MP_QSTR_Rectangle), MP_ROM_PTR(&vectorio_rectangle_type) }, - { MP_ROM_QSTR(MP_QSTR_VectorShape), MP_ROM_PTR(&vectorio_vector_shape_type) }, +// { MP_ROM_QSTR(MP_QSTR_VectorShape), MP_ROM_PTR(&vectorio_vector_shape_type) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_module_globals, vectorio_module_globals_table); diff --git a/shared-bindings/vectorio/__init__.h b/shared-bindings/vectorio/__init__.h new file mode 100644 index 0000000000..a221224058 --- /dev/null +++ b/shared-bindings/vectorio/__init__.h @@ -0,0 +1,41 @@ +#ifndef SHARED_MODULE_VECTORIO__INIT__H +#define SHARED_MODULE_VECTORIO__INIT__H + +#include +#include + +#include "py/obj.h" +#include "py/proto.h" + +#include "shared-module/displayio/area.h" +#include "shared-module/displayio/Palette.h" + +// Returns the object on which the rest of the draw protocol methods are invoked. +typedef mp_obj_t (*draw_get_protocol_self_fun)(mp_obj_t protocol_container); + +typedef bool (*draw_fill_area_fun)(mp_obj_t draw_protocol_self, const _displayio_colorspace_t *colorspace, const displayio_area_t *area, uint32_t *mask, uint32_t *buffer); +typedef bool (*draw_get_dirty_area_fun)(mp_obj_t draw_protocol_self, displayio_area_t *current_dirty_area); +typedef void (*draw_update_transform_fun)(mp_obj_t draw_protocol_self, displayio_buffer_transform_t *group_transform); +typedef void (*draw_finish_refresh_fun)(mp_obj_t draw_protocol_self); +typedef displayio_area_t *(*draw_get_refresh_areas_fun)(mp_obj_t draw_protocol_self, displayio_area_t *tail); + +typedef struct _vectorio_draw_protocol_impl_t { + draw_fill_area_fun draw_fill_area; + draw_get_dirty_area_fun draw_get_dirty_area; + draw_update_transform_fun draw_update_transform; + draw_finish_refresh_fun draw_finish_refresh; + draw_get_refresh_areas_fun draw_get_refresh_areas; +} vectorio_draw_protocol_impl_t; + +// Draw protocol +typedef struct _vectorio_draw_protocol_t { + MP_PROTOCOL_HEAD // MP_QSTR_protocol_draw + + // Instance of the draw protocol + draw_get_protocol_self_fun draw_get_protocol_self; + + // Implementation functions for the draw protocol + vectorio_draw_protocol_impl_t *draw_protocol_impl; +} vectorio_draw_protocol_t; + +#endif diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index ec8ad7ba5a..b9179f0a00 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -144,10 +144,10 @@ static void _update_child_transforms(displayio_group_t *self) { for (size_t i = 0; i < self->members->len; i++) { mp_obj_t layer; #if CIRCUITPY_VECTORIO - layer = mp_obj_cast_to_native_base( - self->members->items[i], &vectorio_vector_shape_type); - if (layer != MP_OBJ_NULL) { - vectorio_vector_shape_update_transform(layer, &self->absolute_transform); + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, self->members->items[i]); + if (draw_protocol != NULL) { + layer = draw_protocol->draw_get_protocol_self(self->members->items[i]); + draw_protocol->draw_protocol_impl->draw_update_transform(layer, &self->absolute_transform); continue; } #endif @@ -241,15 +241,14 @@ void common_hal_displayio_group_set_y(displayio_group_t *self, mp_int_t y) { } static void _add_layer(displayio_group_t *self, mp_obj_t layer) { - mp_obj_t native_layer; #if CIRCUITPY_VECTORIO - native_layer = mp_obj_cast_to_native_base(layer, &vectorio_vector_shape_type); - if (native_layer != MP_OBJ_NULL) { - vectorio_vector_shape_update_transform(native_layer, &self->absolute_transform); + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, layer); + if (draw_protocol != NULL) { + draw_protocol->draw_protocol_impl->draw_update_transform(draw_protocol->draw_get_protocol_self(layer), &self->absolute_transform); return; } #endif - native_layer = mp_obj_cast_to_native_base(layer, &displayio_tilegrid_type); + mp_obj_t native_layer = mp_obj_cast_to_native_base(layer, &displayio_tilegrid_type); if (native_layer != MP_OBJ_NULL) { displayio_tilegrid_t *tilegrid = native_layer; if (tilegrid->in_group) { @@ -283,12 +282,12 @@ static void _remove_layer(displayio_group_t *self, size_t index) { displayio_area_t layer_area; bool rendered_last_frame = false; #if CIRCUITPY_VECTORIO - layer = mp_obj_cast_to_native_base( - self->members->items[index], &vectorio_vector_shape_type); - if (layer != MP_OBJ_NULL) { - bool has_dirty_area = vectorio_vector_shape_get_dirty_area(layer, &layer_area); + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, self->members->items[index]); + if (draw_protocol != NULL) { + layer = draw_protocol->draw_get_protocol_self(self->members->items[index]); + bool has_dirty_area = draw_protocol->draw_protocol_impl->draw_get_dirty_area(layer, &layer_area); rendered_last_frame = has_dirty_area; - vectorio_vector_shape_update_transform(layer, NULL); + draw_protocol->draw_protocol_impl->draw_update_transform(layer, NULL); } #endif layer = mp_obj_cast_to_native_base( @@ -362,10 +361,10 @@ bool displayio_group_fill_area(displayio_group_t *self, const _displayio_colorsp for (int32_t i = self->members->len - 1; i >= 0; i--) { mp_obj_t layer; #if CIRCUITPY_VECTORIO - layer = mp_obj_cast_to_native_base( - self->members->items[i], &vectorio_vector_shape_type); - if (layer != MP_OBJ_NULL) { - if (vectorio_vector_shape_fill_area(layer, colorspace, area, mask, buffer)) { + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, self->members->items[i]); + if (draw_protocol != NULL) { + layer = draw_protocol->draw_get_protocol_self(self->members->items[i]); + if (draw_protocol->draw_protocol_impl->draw_fill_area(layer, colorspace, area, mask, buffer)) { return true; } continue; @@ -396,10 +395,10 @@ void displayio_group_finish_refresh(displayio_group_t *self) { for (int32_t i = self->members->len - 1; i >= 0; i--) { mp_obj_t layer; #if CIRCUITPY_VECTORIO - layer = mp_obj_cast_to_native_base( - self->members->items[i], &vectorio_vector_shape_type); - if (layer != MP_OBJ_NULL) { - vectorio_vector_shape_finish_refresh(layer); + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, self->members->items[i]); + if (draw_protocol != NULL) { + layer = draw_protocol->draw_get_protocol_self(self->members->items[i]); + draw_protocol->draw_protocol_impl->draw_finish_refresh(layer); continue; } #endif @@ -427,10 +426,10 @@ displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, dis for (int32_t i = self->members->len - 1; i >= 0; i--) { mp_obj_t layer; #if CIRCUITPY_VECTORIO - layer = mp_obj_cast_to_native_base( - self->members->items[i], &vectorio_vector_shape_type); - if (layer != MP_OBJ_NULL) { - tail = vectorio_vector_shape_get_refresh_areas(layer, tail); + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, self->members->items[i]); + if (draw_protocol != NULL) { + layer = draw_protocol->draw_get_protocol_self(self->members->items[i]); + tail = draw_protocol->draw_protocol_impl->draw_get_refresh_areas(layer, tail); continue; } #endif diff --git a/shared-module/vectorio/Circle.c b/shared-module/vectorio/Circle.c index 9c74580650..6b4c441620 100644 --- a/shared-module/vectorio/Circle.c +++ b/shared-module/vectorio/Circle.c @@ -59,3 +59,8 @@ void common_hal_vectorio_circle_set_radius(void *obj, int16_t radius) { self->on_dirty.event(self->on_dirty.obj); } } + +mp_obj_t common_hal_vectorio_circle_get_draw_protocol(void *circle) { + vectorio_circle_t *self = circle; + return self->draw_protocol_instance; +} diff --git a/shared-module/vectorio/Circle.h b/shared-module/vectorio/Circle.h index d6a77b1667..106bca6a71 100644 --- a/shared-module/vectorio/Circle.h +++ b/shared-module/vectorio/Circle.h @@ -11,6 +11,7 @@ typedef struct { mp_obj_base_t base; uint16_t radius; vectorio_event_t on_dirty; + mp_obj_t draw_protocol_instance; } vectorio_circle_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_VECTORIO_CIRCLE_H diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c index 00af1e0d7e..db3deced2a 100644 --- a/shared-module/vectorio/Polygon.c +++ b/shared-module/vectorio/Polygon.c @@ -1,4 +1,3 @@ - #include "shared-module/vectorio/__init__.h" #include "shared-bindings/vectorio/Polygon.h" #include "shared-module/displayio/area.h" @@ -108,17 +107,17 @@ void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *area) int x = self->points_list[i]; ++i; int y = self->points_list[i]; - if (x <= area->x1) { - area->x1 = x - 1; + if (x < area->x1) { + area->x1 = x; } - if (y <= area->y1) { - area->y1 = y - 1; + if (y < area->y1) { + area->y1 = y; } - if (x >= area->x2) { - area->x2 = x + 1; + if (x > area->x2) { + area->x2 = x; } - if (y >= area->y2) { - area->y2 = y + 1; + if (y > area->y2) { + area->y2 = y; } } } @@ -167,3 +166,8 @@ uint32_t common_hal_vectorio_polygon_get_pixel(void *obj, int16_t x, int16_t y) } return winding_number == 0 ? 0 : 1; } + +mp_obj_t common_hal_vectorio_polygon_get_draw_protocol(void *polygon) { + vectorio_polygon_t *self = polygon; + return self->draw_protocol_instance; +} diff --git a/shared-module/vectorio/Polygon.h b/shared-module/vectorio/Polygon.h index 70de9036d7..21d32d3581 100644 --- a/shared-module/vectorio/Polygon.h +++ b/shared-module/vectorio/Polygon.h @@ -12,6 +12,7 @@ typedef struct { int *points_list; size_t len; vectorio_event_t on_dirty; + mp_obj_t draw_protocol_instance; } vectorio_polygon_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_VECTORIO_POLYGON_H diff --git a/shared-module/vectorio/Rectangle.c b/shared-module/vectorio/Rectangle.c index 56be5ebb5e..17185ec7ab 100644 --- a/shared-module/vectorio/Rectangle.c +++ b/shared-module/vectorio/Rectangle.c @@ -12,10 +12,10 @@ void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_ uint32_t common_hal_vectorio_rectangle_get_pixel(void *obj, int16_t x, int16_t y) { vectorio_rectangle_t *self = obj; - if (x < 0 || x >= self->width || y >= self->height || y < 0) { - return 0; + if (x >= 0 && y >= 0 && x < self->width && y < self->height ) { + return 1; } - return 1; + return 0; } @@ -32,3 +32,8 @@ uint32_t common_hal_vectorio_rectangle_get_height(void *rectangle) { vectorio_rectangle_t *self = rectangle; return self->height; } + +mp_obj_t common_hal_vectorio_rectangle_get_draw_protocol(void *rectangle) { + vectorio_rectangle_t *self = rectangle; + return self->draw_protocol_instance; +} diff --git a/shared-module/vectorio/Rectangle.h b/shared-module/vectorio/Rectangle.h index 56342a6d76..e3cfbb2676 100644 --- a/shared-module/vectorio/Rectangle.h +++ b/shared-module/vectorio/Rectangle.h @@ -9,6 +9,7 @@ typedef struct { mp_obj_base_t base; uint16_t width; uint16_t height; + mp_obj_t draw_protocol_instance; } vectorio_rectangle_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_VECTORIO_RECTANGLE_H diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index fb8ce963f1..929be46c0f 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -15,16 +15,16 @@ // Lifecycle actions. #define VECTORIO_SHAPE_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Used in both logging and ifdefs, for extra variables -// #define VECTORIO_PERF(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define VECTORIO_PERF(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Really verbose. #define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) inline __attribute__((always_inline)) @@ -32,6 +32,11 @@ static int32_t max(int32_t a, int32_t b) { return a > b ? a : b; } +inline __attribute__((always_inline)) +static int32_t min(int32_t a, int32_t b) { + return a < b ? a : b; +} + inline __attribute__((always_inline)) static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *out_area) { @@ -39,48 +44,67 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou self->absolute_transform->x, self->absolute_transform->y, self->absolute_transform->dx, self->absolute_transform->dy, self->absolute_transform->scale, self->absolute_transform->width, self->absolute_transform->height, self->absolute_transform->mirror_x, self->absolute_transform->mirror_y, self->absolute_transform->transpose_xy ); - self->ishape.get_area(self->ishape.shape, out_area); - VECTORIO_SHAPE_DEBUG(" in:{(%5d,%5d), (%5d,%5d)}", out_area->x1, out_area->y1, out_area->x2, out_area->y2); - if (self->absolute_transform->transpose_xy) { - int16_t swap = out_area->x1; - out_area->x1 = (out_area->y1 + self->y) * self->absolute_transform->dx + self->absolute_transform->x; - out_area->y1 = (swap + self->x) * self->absolute_transform->dy + self->absolute_transform->y; - swap = out_area->x2; - out_area->x2 = (out_area->y2 + self->y) * self->absolute_transform->dx + self->absolute_transform->x; - out_area->y2 = (swap + self->x) * self->absolute_transform->dy + self->absolute_transform->y; - } else { - out_area->x1 = (out_area->x1 + self->x) * self->absolute_transform->dx + self->absolute_transform->x; - out_area->y1 = (out_area->y1 + self->y) * self->absolute_transform->dy + self->absolute_transform->y; - out_area->x2 = (out_area->x2 + self->x) * self->absolute_transform->dx + self->absolute_transform->x; - out_area->y2 = (out_area->y2 + self->y) * self->absolute_transform->dy + self->absolute_transform->y; - } - // We might have mirrored due to dx - displayio_area_canon(out_area); + displayio_area_t shape_area; + self->ishape.get_area(self->ishape.shape, &shape_area); + VECTORIO_SHAPE_DEBUG(" in:{(%5d,%5d), (%5d,%5d)}", shape_area.x1, shape_area.y1, shape_area.x2, shape_area.y2); + + displayio_area_shift( + &shape_area, + self->x * self->absolute_transform->dx + min(0, self->absolute_transform->dx * displayio_area_width(&shape_area)), + self->y * self->absolute_transform->dy + min(0, self->absolute_transform->dy * displayio_area_height(&shape_area)) + ); + + displayio_area_transform_within( + false, + false, + self->absolute_transform->transpose_xy, + &shape_area, &shape_area, out_area + ); + + displayio_area_shift( + out_area, + self->absolute_transform->x, + self->absolute_transform->y + ); + VECTORIO_SHAPE_DEBUG(" out:{(%5d,%5d), (%5d,%5d)}\n", out_area->x1, out_area->y1, out_area->x2, out_area->y2); } // For use by Group to know where it needs to redraw on layer removal. bool vectorio_vector_shape_get_dirty_area(vectorio_vector_shape_t *self, displayio_area_t *out_area) { - displayio_area_copy(&self->ephemeral_dirty_area, out_area); + out_area->x1 = out_area->x2; + displayio_area_union( + &self->ephemeral_dirty_area, + &self->current_area, + out_area + ); return true; // For now just always redraw. } -// This must be invoked each time a shape changes its position or its shape in any way. +// This must be invoked after each time a shape changes its position, shape or appearance in any way. void common_hal_vectorio_vector_shape_set_dirty(void *vector_shape) { vectorio_vector_shape_t *self = vector_shape; // In screen space. Need to offset the shape space. displayio_area_t current_area; _get_screen_area(self, ¤t_area); - VECTORIO_SHAPE_DEBUG("%p shape_dirty current:{(%3d,%3d), (%3d,%3d)} dirty:{(%3d,%3d), (%3d,%3d)}", + VECTORIO_SHAPE_DEBUG("%p shape_dirty new:{(%3d,%3d), (%3d,%3d)} dirty:{(%3d,%3d), (%3d,%3d)}", self, current_area.x1, current_area.y1, current_area.x2, current_area.y2, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - self->dirty = true; - // Dirty area tracks the shape's footprint between draws. It's reset on refresh finish, - displayio_area_union(&self->ephemeral_dirty_area, ¤t_area, &self->ephemeral_dirty_area); - VECTORIO_SHAPE_DEBUG(" -> expanded:{(%3d,%3d), (%3d,%3d)}\n", self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); + + bool moved = !displayio_area_equal(¤t_area, &self->current_area); + if (moved) { + displayio_area_union(&self->current_area, &self->ephemeral_dirty_area, &self->ephemeral_dirty_area); + VECTORIO_SHAPE_DEBUG(" stale:{(%3d,%3d), (%3d,%3d)} -> expanded:{(%3d,%3d), (%3d,%3d)}\n", + self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2, + self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); + + // Dirty area tracks the shape's footprint between draws. It's reset on refresh finish. + displayio_area_copy(¤t_area, &self->current_area); + } + self->current_area_dirty = true; } @@ -92,10 +116,11 @@ void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self, self->y = y; self->pixel_shader = pixel_shader; self->ishape = ishape; - self->dirty = true; self->absolute_transform = &null_transform; // Critical to have a valid transform before getting screen area. - _get_screen_area(self, &self->ephemeral_dirty_area); + self->ephemeral_dirty_area.x1 = self->ephemeral_dirty_area.x2; // Cheat to set area to 0 self->ephemeral_dirty_area.next = NULL; + self->current_area_dirty = true; + _get_screen_area(self, &self->current_area); } @@ -153,13 +178,12 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ uint64_t start = common_hal_time_monotonic_ns(); uint64_t pixel_time = 0; #endif - displayio_area_t overlap; - VECTORIO_SHAPE_DEBUG("%p fill_area dirty:%d fill: {(%5d,%5d), (%5d,%5d)} dirty: {(%5d,%5d), (%5d,%5d)}", - self, self->dirty, - area->x1, area->y1, area->x2, area->y2, - self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2 + VECTORIO_SHAPE_DEBUG("%p fill_area: fill: {(%5d,%5d), (%5d,%5d)}", + self, + area->x1, area->y1, area->x2, area->y2 ); - if (!displayio_area_compute_overlap(area, &self->ephemeral_dirty_area, &overlap)) { + displayio_area_t overlap; + if (!displayio_area_compute_overlap(area, &self->current_area, &overlap)) { VECTORIO_SHAPE_DEBUG(" no overlap\n"); return false; } @@ -168,6 +192,11 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ bool full_coverage = displayio_area_equal(area, &overlap); uint8_t pixels_per_byte = 8 / colorspace->depth; + VECTORIO_SHAPE_DEBUG(" xy:(%3d %3d) tform:{x:%d y:%d dx:%d dy:%d scl:%d w:%d h:%d mx:%d my:%d tr:%d}", + self->x, self->y, + self->absolute_transform->x, self->absolute_transform->y, self->absolute_transform->dx, self->absolute_transform->dy, self->absolute_transform->scale, + self->absolute_transform->width, self->absolute_transform->height, self->absolute_transform->mirror_x, self->absolute_transform->mirror_y, self->absolute_transform->transpose_xy + ); uint32_t linestride_px = displayio_area_width(area); uint32_t line_dirty_offset_px = (overlap.y1 - area->y1) * linestride_px; @@ -178,6 +207,25 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ displayio_input_pixel_t input_pixel; displayio_output_pixel_t output_pixel; + int16_t math_transform_offset_x; + int16_t math_transform_offset_y; + int16_t math_shape_offset_x; + int16_t math_shape_offset_y; + if (self->absolute_transform->transpose_xy) { + math_transform_offset_x = self->absolute_transform->dy * self->y; + math_transform_offset_y = self->absolute_transform->dx * self->x; + math_shape_offset_x = min(0, self->absolute_transform->dy * displayio_area_width(&self->current_area)); + math_shape_offset_y = min(0, self->absolute_transform->dx * displayio_area_height(&self->current_area)); + } else { + math_transform_offset_x = self->absolute_transform->dx * self->x; + math_transform_offset_y = self->absolute_transform->dy * self->y; + math_shape_offset_x = min(0, self->absolute_transform->dx * displayio_area_width(&self->current_area)); + math_shape_offset_y = min(0, self->absolute_transform->dy * displayio_area_height(&self->current_area)); + } + + VECTORIO_SHAPE_DEBUG(", transform_offset: (%3d,%3d), shape_offset: (%3d,%3d)", math_transform_offset_x, math_transform_offset_y, math_shape_offset_x, math_shape_offset_y); + + uint32_t mask_start_px = line_dirty_offset_px; for (input_pixel.y = overlap.y1; input_pixel.y < overlap.y2; ++input_pixel.y) { mask_start_px += column_dirty_offset_px; @@ -186,9 +234,9 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ uint32_t pixel_index = mask_start_px + (input_pixel.x - overlap.x1); uint32_t *mask_doubleword = &(mask[pixel_index / 32]); uint8_t mask_bit = pixel_index % 32; - VECTORIO_SHAPE_PIXEL_DEBUG("%p pixel_index: %5u mask_bit: %2u", self, pixel_index, mask_bit); + VECTORIO_SHAPE_PIXEL_DEBUG("\n%p pixel_index: %5u mask_bit: %2u", self, pixel_index, mask_bit); if ((*mask_doubleword & (1u << mask_bit)) != 0) { - VECTORIO_SHAPE_PIXEL_DEBUG(" masked\n"); + VECTORIO_SHAPE_PIXEL_DEBUG(" masked"); continue; } output_pixel.pixel = 0; @@ -197,11 +245,11 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ int16_t pixel_to_get_x; int16_t pixel_to_get_y; if (self->absolute_transform->transpose_xy) { - pixel_to_get_x = (input_pixel.y - self->absolute_transform->dy * self->x - self->absolute_transform->y) / self->absolute_transform->dy; - pixel_to_get_y = (input_pixel.x - self->absolute_transform->dx * self->y - self->absolute_transform->x) / self->absolute_transform->dx; + pixel_to_get_x = (input_pixel.y - math_transform_offset_y - self->absolute_transform->y) - math_shape_offset_y; + pixel_to_get_y = (input_pixel.x - math_transform_offset_x - self->absolute_transform->x) - math_shape_offset_x; } else { - pixel_to_get_x = (input_pixel.x - self->absolute_transform->dx * self->x - self->absolute_transform->x) / self->absolute_transform->dx; - pixel_to_get_y = (input_pixel.y - self->absolute_transform->dy * self->y - self->absolute_transform->y) / self->absolute_transform->dy; + pixel_to_get_x = (input_pixel.x - math_transform_offset_x - self->absolute_transform->x) - math_shape_offset_x; + pixel_to_get_y = (input_pixel.y - math_transform_offset_y - self->absolute_transform->y) - math_shape_offset_y; } VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y); #ifdef VECTORIO_PERF @@ -217,7 +265,7 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ // 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"); + VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel; input area is not fully covered)"); full_coverage = false; } else { // Pixel is not transparent. Let's pull the pixel value index down to 0-base for more error-resistant palettes. @@ -234,16 +282,16 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ // 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"); + VECTORIO_SHAPE_PIXEL_DEBUG(" (encountered transparent pixel from colorconverter; input area is not fully covered)"); full_coverage = false; } *mask_doubleword |= 1u << mask_bit; if (colorspace->depth == 16) { - VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %04x 16\n", output_pixel.pixel); + VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %04x 16", output_pixel.pixel); *(((uint16_t *)buffer) + pixel_index) = output_pixel.pixel; } else if (colorspace->depth == 8) { - VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %02x 8\n", output_pixel.pixel); + VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %02x 8", output_pixel.pixel); *(((uint8_t *)buffer) + pixel_index) = output_pixel.pixel; } else if (colorspace->depth < 8) { // Reorder the offsets to pack multiple rows into a byte (meaning they share a column). @@ -258,7 +306,7 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ // Reverse the shift by subtracting it from the leftmost shift. shift = (pixels_per_byte - 1) * colorspace->depth - shift; } - VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %2d %d\n", output_pixel.pixel, colorspace->depth); + VECTORIO_SHAPE_PIXEL_DEBUG(" buffer = %2d %d", output_pixel.pixel, colorspace->depth); ((uint8_t *)buffer)[pixel_index / pixels_per_byte] |= output_pixel.pixel << shift; } } @@ -277,20 +325,23 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ (double)(pixel_time / 1000.0 / pixels) ); #endif - VECTORIO_SHAPE_DEBUG(" -> pixels:%4d\n"); + VECTORIO_SHAPE_DEBUG(" -> pixels:%4d\n", (overlap.x2 - overlap.x1) * (overlap.y2 - overlap.y1)); return full_coverage; } void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { - if (!self->dirty) { + if (displayio_area_empty(&self->ephemeral_dirty_area)) { return; } VECTORIO_SHAPE_DEBUG("%p finish_refresh was:{(%3d,%3d), (%3d,%3d)}\n", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - self->dirty = false; - // Reset dirty area tracking to current footprint - _get_screen_area(self, &self->ephemeral_dirty_area); + // Reset dirty area to nothing + self->ephemeral_dirty_area.x1 = self->ephemeral_dirty_area.x2; // Cheat to set area to empty self->ephemeral_dirty_area.next = NULL; + + self->current_area_dirty = false; // We don't clear current area so we can remember what to clean up if we move + self->current_area.next = NULL; + VECTORIO_SHAPE_DEBUG("%p finish_refresh now:{(%3d,%3d), (%3d,%3d)}\n", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); if (mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { @@ -303,21 +354,30 @@ void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { // Assembles a singly linked list of dirty areas from all components on the display. displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_t *self, displayio_area_t *tail) { - if (self->dirty + displayio_area_t *new_tail = tail; + if (!displayio_area_empty(&self->ephemeral_dirty_area)) { + // vector.add_to_head + self->ephemeral_dirty_area.next = tail; + new_tail = &self->ephemeral_dirty_area; + VECTORIO_SHAPE_DEBUG("%p get_refresh_area dirty: {(%3d,%3d), (%3d,%3d)}", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); + } + if (self->current_area_dirty || (mp_obj_is_type(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)) ) { - VECTORIO_SHAPE_DEBUG("%p get_refresh_area dirty:%d {(%3d,%3d), (%3d,%3d)}", self, self->dirty, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - common_hal_vectorio_vector_shape_set_dirty(self); - // vector.add_to_head - self->ephemeral_dirty_area.next = tail; - VECTORIO_SHAPE_DEBUG(" this_area: %p next: %p after: %p\n", &self->ephemeral_dirty_area, tail, tail == NULL ? NULL : tail->next); - return &self->ephemeral_dirty_area; + self->current_area.next = new_tail; + new_tail = &self->current_area; + VECTORIO_SHAPE_DEBUG(" redrawing current: {(%3d,%3d), (%3d,%3d)}", self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2); } - return tail; +#ifdef VECTORIO_SHAPE_DEBUG + if (new_tail != tail) { + VECTORIO_SHAPE_DEBUG("\n"); + } +#endif + return new_tail; } void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displayio_buffer_transform_t *group_transform) { - self->absolute_transform = group_transform == NULL ? &null_transform : group_transform; common_hal_vectorio_vector_shape_set_dirty(self); + self->absolute_transform = group_transform == NULL ? &null_transform : group_transform; } diff --git a/shared-module/vectorio/VectorShape.h b/shared-module/vectorio/VectorShape.h index 1896c72d6e..fdbae964a8 100644 --- a/shared-module/vectorio/VectorShape.h +++ b/shared-module/vectorio/VectorShape.h @@ -31,11 +31,12 @@ typedef struct { int16_t x; int16_t y; displayio_buffer_transform_t *absolute_transform; - bool dirty; // True if we need to draw // Tracks current shape footprint and expands outward as the shape dirties and changes. // This is suboptimal if you move your shape far. Could add more state to only redraw // exactly what we left behind. displayio_area_t ephemeral_dirty_area; + displayio_area_t current_area; + bool current_area_dirty; } vectorio_vector_shape_t; displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_t *self, displayio_area_t *tail); From 8c22993e284d234afe60376d752cfe5f239377fd Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Mon, 2 Aug 2021 20:38:37 -0700 Subject: [PATCH 04/25] fix linter --- shared-module/vectorio/Rectangle.c | 2 +- shared-module/vectorio/VectorShape.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-module/vectorio/Rectangle.c b/shared-module/vectorio/Rectangle.c index 17185ec7ab..2471daa608 100644 --- a/shared-module/vectorio/Rectangle.c +++ b/shared-module/vectorio/Rectangle.c @@ -12,7 +12,7 @@ void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_ uint32_t common_hal_vectorio_rectangle_get_pixel(void *obj, int16_t x, int16_t y) { vectorio_rectangle_t *self = obj; - if (x >= 0 && y >= 0 && x < self->width && y < self->height ) { + if (x >= 0 && y >= 0 && x < self->width && y < self->height) { return 1; } return 0; diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 929be46c0f..4406f20120 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -60,7 +60,7 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou self->absolute_transform->transpose_xy, &shape_area, &shape_area, out_area ); - + displayio_area_shift( out_area, self->absolute_transform->x, @@ -100,7 +100,7 @@ void common_hal_vectorio_vector_shape_set_dirty(void *vector_shape) { VECTORIO_SHAPE_DEBUG(" stale:{(%3d,%3d), (%3d,%3d)} -> expanded:{(%3d,%3d), (%3d,%3d)}\n", self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - + // Dirty area tracks the shape's footprint between draws. It's reset on refresh finish. displayio_area_copy(¤t_area, &self->current_area); } @@ -369,11 +369,11 @@ displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_ new_tail = &self->current_area; VECTORIO_SHAPE_DEBUG(" redrawing current: {(%3d,%3d), (%3d,%3d)}", self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2); } -#ifdef VECTORIO_SHAPE_DEBUG + #ifdef VECTORIO_SHAPE_DEBUG if (new_tail != tail) { VECTORIO_SHAPE_DEBUG("\n"); } -#endif + #endif return new_tail; } From 464281b881d6a1ff09919be23c16f1a5ae2f66de Mon Sep 17 00:00:00 2001 From: Kenny Date: Tue, 3 Aug 2021 08:08:11 -0700 Subject: [PATCH 05/25] Stub comma --- shared-bindings/vectorio/Circle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c index d6edba7063..cf4e643662 100644 --- a/shared-bindings/vectorio/Circle.c +++ b/shared-bindings/vectorio/Circle.c @@ -12,7 +12,7 @@ //| class Circle: //| -//| def __init__(self, pixel_shader: Union[ColorConverter, Palette] radius: int, x: int, y: int) -> None: +//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], radius: int, x: int, y: int) -> None: //| """Circle is positioned on screen by its center point. //| //| :param pixel_shader: The pixel shader that produces colors from values From 739ef92fc95f48d98b77a4746b83022b8382685e Mon Sep 17 00:00:00 2001 From: Kenny Date: Tue, 3 Aug 2021 09:20:02 -0700 Subject: [PATCH 06/25] Update __init__.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More random spaces. Why isn’t this in a pre-commit check --- shared-bindings/vectorio/__init__.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/vectorio/__init__.h b/shared-bindings/vectorio/__init__.h index a221224058..a34195de26 100644 --- a/shared-bindings/vectorio/__init__.h +++ b/shared-bindings/vectorio/__init__.h @@ -30,7 +30,7 @@ typedef struct _vectorio_draw_protocol_impl_t { // Draw protocol typedef struct _vectorio_draw_protocol_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_draw - + // Instance of the draw protocol draw_get_protocol_self_fun draw_get_protocol_self; From 48ea81e2f1660e6bdf05252ee059a79c84097881 Mon Sep 17 00:00:00 2001 From: Kenny Date: Tue, 3 Aug 2021 11:25:31 -0700 Subject: [PATCH 08/25] Vexing pedantry Spaces deleted from phone Eternal chore, lint --- shared-bindings/vectorio/VectorShape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index fc46eceec7..979651bd4a 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -87,7 +87,7 @@ STATIC mp_obj_t vectorio_vector_shape_obj_get_x(mp_obj_t wrapper_shape) { // Relies on the fact that only vector_shape impl gets matched with a VectorShape. const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); - + return MP_OBJ_NEW_SMALL_INT(common_hal_vectorio_vector_shape_get_x(self)); } MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_x_obj, vectorio_vector_shape_obj_get_x); From 85bf3d074f4355d70c2477e0d3987c653f401c81 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:55:03 -0700 Subject: [PATCH 09/25] stub checker does not approve of shared vectorshape properties --- shared-bindings/vectorio/VectorShape.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index 979651bd4a..8d6c2b71db 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -80,9 +80,10 @@ vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl = { }; -//| x: int -//| """X position of the center point of the shape in the parent.""" -//| +// Stub checker does not approve of these shared properties. +// x: int +// """X position of the center point of the shape in the parent.""" +// STATIC mp_obj_t vectorio_vector_shape_obj_get_x(mp_obj_t wrapper_shape) { // Relies on the fact that only vector_shape impl gets matched with a VectorShape. const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); @@ -111,9 +112,9 @@ const mp_obj_property_t vectorio_vector_shape_x_obj = { }; -//| y: int -//| """Y position of the center point of the shape in the parent.""" -//| +// y: int +// """Y position of the center point of the shape in the parent.""" +// STATIC mp_obj_t vectorio_vector_shape_obj_get_y(mp_obj_t wrapper_shape) { // Relies on the fact that only vector_shape impl gets matched with a VectorShape. const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); @@ -142,9 +143,9 @@ const mp_obj_property_t vectorio_vector_shape_y_obj = { }; -//| pixel_shader: Union[displayio.ColorConverter, displayio.Palette] -//| """The pixel shader of the shape.""" -//| +// pixel_shader: Union[displayio.ColorConverter, displayio.Palette] +// """The pixel shader of the shape.""" +// STATIC mp_obj_t vectorio_vector_shape_obj_get_pixel_shader(mp_obj_t wrapper_shape) { // Relies on the fact that only vector_shape impl gets matched with a VectorShape. const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); From 6be952d3bae45b1ff81203f464616bc986dd280a Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Thu, 5 Aug 2021 00:13:10 -0700 Subject: [PATCH 10/25] found more documentation dependencies that needed updating --- docs/redirects.txt | 1 - shared-bindings/displayio/Group.c | 14 +++++++------- shared-bindings/vectorio/Circle.c | 2 +- shared-bindings/vectorio/Polygon.c | 2 +- shared-bindings/vectorio/Rectangle.c | 2 +- shared-bindings/vectorio/VectorShape.c | 2 +- shared-bindings/vectorio/__init__.c | 2 -- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/redirects.txt b/docs/redirects.txt index 6eb7ddc4d8..d8fc46b358 100644 --- a/docs/redirects.txt +++ b/docs/redirects.txt @@ -152,7 +152,6 @@ shared-bindings/ustack/__init__.rst shared-bindings/ustack/ shared-bindings/vectorio/Circle.rst shared-bindings/vectorio/#vectorio.Circle shared-bindings/vectorio/Polygon.rst shared-bindings/vectorio/#vectorio.Polygon shared-bindings/vectorio/Rectangle.rst shared-bindings/vectorio/#vectorio.Rectangle -shared-bindings/vectorio/VectorShape.rst shared-bindings/vectorio/#vectorio.VectorShape shared-bindings/vectorio/__init__.rst shared-bindings/vectorio/ shared-bindings/watchdog/WatchDogMode.rst shared-bindings/watchdog/#watchdog.WatchDogMode shared-bindings/watchdog/WatchDogTimer.rst shared-bindings/watchdog/#watchdog.WatchDogTimer diff --git a/shared-bindings/displayio/Group.c b/shared-bindings/displayio/Group.c index d636ee335b..4783c97453 100644 --- a/shared-bindings/displayio/Group.c +++ b/shared-bindings/displayio/Group.c @@ -183,7 +183,7 @@ const mp_obj_property_t displayio_group_y_obj = { MP_ROM_NONE}, }; -//| def append(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> None: +//| def append(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None: //| """Append a layer to the group. It will be drawn above other layers.""" //| ... //| @@ -194,7 +194,7 @@ STATIC mp_obj_t displayio_group_obj_append(mp_obj_t self_in, mp_obj_t layer) { } MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_append_obj, displayio_group_obj_append); -//| def insert(self, index: int, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> None: +//| def insert(self, index: int, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None: //| """Insert a layer into the group.""" //| ... //| @@ -210,7 +210,7 @@ STATIC mp_obj_t displayio_group_obj_insert(mp_obj_t self_in, mp_obj_t index_obj, MP_DEFINE_CONST_FUN_OBJ_3(displayio_group_insert_obj, displayio_group_obj_insert); -//| def index(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> int: +//| def index(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> int: //| """Returns the index of the first copy of layer. Raises ValueError if not found.""" //| ... //| @@ -224,7 +224,7 @@ STATIC mp_obj_t displayio_group_obj_index(mp_obj_t self_in, mp_obj_t layer) { } MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_index_obj, displayio_group_obj_index); -//| def pop(self, i: int = -1) -> Union[vectorio.VectorShape, Group, TileGrid]: +//| def pop(self, i: int = -1) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]: //| """Remove the ith item and return it.""" //| ... //| @@ -247,7 +247,7 @@ STATIC mp_obj_t displayio_group_obj_pop(size_t n_args, const mp_obj_t *pos_args, MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_pop_obj, 1, displayio_group_obj_pop); -//| def remove(self, layer: Union[vectorio.VectorShape, Group, TileGrid]) -> None: +//| def remove(self, layer: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None: //| """Remove the first copy of layer. Raises ValueError if it is not present.""" //| ... //| @@ -280,7 +280,7 @@ STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } -//| def __getitem__(self, index: int) -> Union[vectorio.VectorShape, Group, TileGrid]: +//| def __getitem__(self, index: int) -> Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]: //| """Returns the value at the given index. //| //| This allows you to:: @@ -288,7 +288,7 @@ STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { //| print(group[0])""" //| ... //| -//| def __setitem__(self, index: int, value: Union[vectorio.VectorShape, Group, TileGrid]) -> None: +//| def __setitem__(self, index: int, value: Union[vectorio.Circle, vectorio.Rectangle, vectorio.Polygon, Group, TileGrid]) -> None: //| """Sets the value at the given index. //| //| This allows you to:: diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c index cf4e643662..37780b5562 100644 --- a/shared-bindings/vectorio/Circle.c +++ b/shared-bindings/vectorio/Circle.c @@ -12,7 +12,7 @@ //| class Circle: //| -//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], radius: int, x: int, y: int) -> None: +//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], radius: int, x: int, y: int) -> None: //| """Circle is positioned on screen by its center point. //| //| :param pixel_shader: The pixel shader that produces colors from values diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c index 261e7ae55e..551954f98d 100644 --- a/shared-bindings/vectorio/Polygon.c +++ b/shared-bindings/vectorio/Polygon.c @@ -17,7 +17,7 @@ //| class Polygon: -//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], points: List[Tuple[int, int]], x: int, y: int) -> None: +//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], points: List[Tuple[int, int]], x: int, y: int) -> None: //| """Represents a closed shape by ordered vertices //| //| :param pixel_shader: The pixel shader that produces colors from values diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c index 98e38f0c6b..1e885064ff 100644 --- a/shared-bindings/vectorio/Rectangle.c +++ b/shared-bindings/vectorio/Rectangle.c @@ -10,7 +10,7 @@ #include "supervisor/shared/translate.h" //| class Rectangle: -//| def __init__(self, pixel_shader: Union[ColorConverter, Palette], width: int, height: int, x: int, y: int) -> None: +//| def __init__(self, pixel_shader: Union[displayio.ColorConverter, displayio.Palette], width: int, height: int, x: int, y: int) -> None: //| """Represents a rectangle by defining its bounds //| //| :param pixel_shader: The pixel shader that produces colors from values diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index 8d6c2b71db..f59ff26213 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -143,7 +143,7 @@ const mp_obj_property_t vectorio_vector_shape_y_obj = { }; -// pixel_shader: Union[displayio.ColorConverter, displayio.Palette] +// pixel_shader: Union[ColorConverter, Palette] // """The pixel shader of the shape.""" // STATIC mp_obj_t vectorio_vector_shape_obj_get_pixel_shader(mp_obj_t wrapper_shape) { diff --git a/shared-bindings/vectorio/__init__.c b/shared-bindings/vectorio/__init__.c index 556bfe59ec..5a3729573e 100644 --- a/shared-bindings/vectorio/__init__.c +++ b/shared-bindings/vectorio/__init__.c @@ -6,7 +6,6 @@ #include "shared-bindings/vectorio/Circle.h" #include "shared-bindings/vectorio/Polygon.h" #include "shared-bindings/vectorio/Rectangle.h" -#include "shared-bindings/vectorio/VectorShape.h" //| """Lightweight 2d shapes for displays""" //| @@ -16,7 +15,6 @@ STATIC const mp_rom_map_elem_t vectorio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Circle), MP_ROM_PTR(&vectorio_circle_type) }, { MP_ROM_QSTR(MP_QSTR_Polygon), MP_ROM_PTR(&vectorio_polygon_type) }, { MP_ROM_QSTR(MP_QSTR_Rectangle), MP_ROM_PTR(&vectorio_rectangle_type) }, -// { MP_ROM_QSTR(MP_QSTR_VectorShape), MP_ROM_PTR(&vectorio_vector_shape_type) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_module_globals, vectorio_module_globals_table); From b5837b157df0329d3c18e5e9f23a33a093cf8d2f Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sat, 7 Aug 2021 17:47:57 -0700 Subject: [PATCH 11/25] improve transpose and mirror * add heuristic to avoid drawing area unnecessarily * fix Polygon.points * fix transpose * fix mirror x and y Known broken: Polygon with negative Y coordinates does not work right. --- shared-module/vectorio/Polygon.c | 61 +++++--- shared-module/vectorio/Polygon.h | 4 +- shared-module/vectorio/VectorShape.c | 216 ++++++++++++++++++--------- 3 files changed, 185 insertions(+), 96 deletions(-) diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c index db3deced2a..6cc99a6096 100644 --- a/shared-module/vectorio/Polygon.c +++ b/shared-module/vectorio/Polygon.c @@ -10,7 +10,7 @@ #define VECTORIO_POLYGON_DEBUG(...) (void)0 -// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Converts a list of points tuples to a flat list of ints for speedier internal use. @@ -30,12 +30,12 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple VECTORIO_POLYGON_DEBUG("free(%d), ", sizeof(self->points_list)); gc_free(self->points_list); } - self->points_list = gc_alloc(2 * len * sizeof(int), false, false); - VECTORIO_POLYGON_DEBUG("alloc(%p, %d)", self->points_list, 2 * len * sizeof(int)); + self->points_list = gc_alloc(2 * len * sizeof(uint16_t), false, false); + VECTORIO_POLYGON_DEBUG("alloc(%p, %d)", self->points_list, 2 * len * sizeof(uint16_t)); } self->len = 2 * len; - for (size_t i = 0; i < len; ++i) { + for (uint16_t i = 0; i < len; ++i) { size_t tuple_len = 0; mp_obj_t *tuple_items; mp_obj_tuple_get(items[i], &tuple_len, &tuple_items); @@ -43,14 +43,19 @@ static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple if (tuple_len != 2) { mp_raise_ValueError_varg(translate("%q must be a tuple of length 2"), MP_QSTR_point); } - if (!mp_obj_get_int_maybe(tuple_items[ 0 ], &self->points_list[2 * i ]) - || !mp_obj_get_int_maybe(tuple_items[ 1 ], &self->points_list[2 * i + 1]) + mp_int_t x; + mp_int_t y; + if (!mp_obj_get_int_maybe(tuple_items[ 0 ], &x) + || !mp_obj_get_int_maybe(tuple_items[ 1 ], &y) + || x < SHRT_MIN || x > SHRT_MAX || y < SHRT_MIN || y > SHRT_MAX ) { - self->len = 0; gc_free(self->points_list); self->points_list = NULL; mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point); + self->len = 0; } + self->points_list[2 * i ] = (int16_t)x; + self->points_list[2 * i + 1] = (int16_t)y; } } @@ -68,16 +73,23 @@ void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t po mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) { VECTORIO_POLYGON_DEBUG("%p common_hal_vectorio_polygon_get_points {len: %d, points_list: %p}\n", self, self->len, self->points_list); - mp_obj_t list = mp_obj_new_list(self->len / 2, NULL); + mp_obj_list_t *list = MP_OBJ_TO_PTR(mp_obj_new_list(0, NULL)); + + VECTORIO_POLYGON_DEBUG(" >points\n"); + for (uint16_t i = 0; i < self->len; i += 2) { + VECTORIO_POLYGON_DEBUG(" (%4d, %4d)\n", self->points_list[i], self->points_list[i + 1]); + + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + pair->items[0] = mp_obj_new_int((mp_int_t) self->points_list[i ]); + pair->items[1] = mp_obj_new_int((mp_int_t) self->points_list[i + 1]); - for (size_t i = 0; i < self->len; i += 2) { - mp_obj_t tuple[] = { mp_obj_new_int(self->points_list[i]), mp_obj_new_int(self->points_list[i + 1]) }; mp_obj_list_append( list, - mp_obj_new_tuple(2, tuple) + pair ); } - return list; + VECTORIO_POLYGON_DEBUG(" x1 = SHRT_MAX; area->y1 = SHRT_MAX; area->x2 = SHRT_MIN; area->y2 = SHRT_MIN; - for (size_t i = 0; i < self->len; ++i) { - int x = self->points_list[i]; + for (uint16_t i = 0; i < self->len; ++i) { + int16_t x = self->points_list[i]; ++i; - int y = self->points_list[i]; + int16_t y = self->points_list[i]; if (x < area->x1) { + VECTORIO_POLYGON_DEBUG(" x1: %d\n", x); area->x1 = x; } if (y < area->y1) { + VECTORIO_POLYGON_DEBUG(" y1: %d\n", y); area->y1 = y; } if (x > area->x2) { + VECTORIO_POLYGON_DEBUG(" x2: %d\n", x); area->x2 = x; } if (y > area->y2) { + VECTORIO_POLYGON_DEBUG(" y2: %d\n", y); area->y2 = y; } } @@ -126,7 +143,7 @@ void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *area) // <0 if the point is to the left of the line vector // 0 if the point is on the line // >0 if the point is to the right of the line vector -__attribute__((always_inline)) static inline int line_side(mp_int_t x1, mp_int_t y1, mp_int_t x2, mp_int_t y2, int16_t px, int16_t py) { +__attribute__((always_inline)) static inline int line_side(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t px, int16_t py) { return (px - x1) * (y2 - y1) - (py - y1) * (x2 - x1); } @@ -140,14 +157,14 @@ uint32_t common_hal_vectorio_polygon_get_pixel(void *obj, int16_t x, int16_t y) return 0; } - int winding_number = 0; - int x1 = self->points_list[0]; - int y1 = self->points_list[1]; - for (size_t i = 2; i <= self->len + 1; ++i) { + int16_t winding_number = 0; + int16_t x1 = self->points_list[0]; + int16_t y1 = self->points_list[1]; + for (uint16_t i = 2; i <= self->len + 1; ++i) { VECTORIO_POLYGON_DEBUG(" {(%3d, %3d),", x1, y1); - int x2 = self->points_list[i % self->len]; + int16_t x2 = self->points_list[i % self->len]; ++i; - int y2 = self->points_list[i % self->len]; + int16_t y2 = self->points_list[i % self->len]; VECTORIO_POLYGON_DEBUG(" (%3d, %3d)}\n", x2, y2); if (y1 <= y) { if (y2 > y && line_side(x1, y1, x2, y2, x, y) < 0) { diff --git a/shared-module/vectorio/Polygon.h b/shared-module/vectorio/Polygon.h index 21d32d3581..e1d94f9f97 100644 --- a/shared-module/vectorio/Polygon.h +++ b/shared-module/vectorio/Polygon.h @@ -9,8 +9,8 @@ typedef struct { mp_obj_base_t base; // An int array[ x, y, ... ] - int *points_list; - size_t len; + int16_t *points_list; + uint16_t len; vectorio_event_t on_dirty; mp_obj_t draw_protocol_instance; } vectorio_polygon_t; diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 4406f20120..64c1b94c0d 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -14,8 +14,8 @@ #include "shared-bindings/vectorio/Rectangle.h" // Lifecycle actions. -#define VECTORIO_SHAPE_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +// #define VECTORIO_SHAPE_DEBUG(...) (void)0 +#define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Used in both logging and ifdefs, for extra variables @@ -23,8 +23,43 @@ // Really verbose. -#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 +#define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) + +#define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" +#define U32_TO_BINARY(u32) \ + (u32 & 0x80000000 ? '1' : '0'), \ + (u32 & 0x40000000 ? '1' : '0'), \ + (u32 & 0x20000000 ? '1' : '0'), \ + (u32 & 0x10000000 ? '1' : '0'), \ + (u32 & 0x8000000 ? '1' : '0'), \ + (u32 & 0x4000000 ? '1' : '0'), \ + (u32 & 0x2000000 ? '1' : '0'), \ + (u32 & 0x1000000 ? '1' : '0'), \ + (u32 & 0x800000 ? '1' : '0'), \ + (u32 & 0x400000 ? '1' : '0'), \ + (u32 & 0x200000 ? '1' : '0'), \ + (u32 & 0x100000 ? '1' : '0'), \ + (u32 & 0x80000 ? '1' : '0'), \ + (u32 & 0x40000 ? '1' : '0'), \ + (u32 & 0x20000 ? '1' : '0'), \ + (u32 & 0x10000 ? '1' : '0'), \ + (u32 & 0x8000 ? '1' : '0'), \ + (u32 & 0x4000 ? '1' : '0'), \ + (u32 & 0x2000 ? '1' : '0'), \ + (u32 & 0x1000 ? '1' : '0'), \ + (u32 & 0x800 ? '1' : '0'), \ + (u32 & 0x400 ? '1' : '0'), \ + (u32 & 0x200 ? '1' : '0'), \ + (u32 & 0x100 ? '1' : '0'), \ + (u32 & 0x80 ? '1' : '0'), \ + (u32 & 0x40 ? '1' : '0'), \ + (u32 & 0x20 ? '1' : '0'), \ + (u32 & 0x10 ? '1' : '0'), \ + (u32 & 0x8 ? '1' : '0'), \ + (u32 & 0x4 ? '1' : '0'), \ + (u32 & 0x2 ? '1' : '0'), \ + (u32 & 0x1 ? '1' : '0') inline __attribute__((always_inline)) @@ -33,39 +68,41 @@ static int32_t max(int32_t a, int32_t b) { } inline __attribute__((always_inline)) -static int32_t min(int32_t a, int32_t b) { +static uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; } +inline __attribute__((always_inline)) +static void area_transpose(displayio_area_t *to_transpose) { + int16_t swap = to_transpose->y1; + to_transpose->y1 = to_transpose->x1; + to_transpose->x1 = swap; + swap = to_transpose->y2; + to_transpose->y2 = to_transpose->x2; + to_transpose->x2 = swap; +} inline __attribute__((always_inline)) static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *out_area) { - VECTORIO_SHAPE_DEBUG("%p get_screen_area tform:{x:%d y:%d dx:%d dy:%d scl:%d w:%d h:%d mx:%d my:%d tr:%d}", self, + VECTORIO_SHAPE_DEBUG("%p get_screen_area (%3d,%3d) tform:{x:%d y:%d dx:%d dy:%d scl:%d w:%d h:%d mx:%d my:%d tr:%d}", self, self->x, self->y, self->absolute_transform->x, self->absolute_transform->y, self->absolute_transform->dx, self->absolute_transform->dy, self->absolute_transform->scale, self->absolute_transform->width, self->absolute_transform->height, self->absolute_transform->mirror_x, self->absolute_transform->mirror_y, self->absolute_transform->transpose_xy ); - displayio_area_t shape_area; - self->ishape.get_area(self->ishape.shape, &shape_area); - VECTORIO_SHAPE_DEBUG(" in:{(%5d,%5d), (%5d,%5d)}", shape_area.x1, shape_area.y1, shape_area.x2, shape_area.y2); + self->ishape.get_area(self->ishape.shape, out_area); + VECTORIO_SHAPE_DEBUG(" in:{(%5d,%5d), (%5d,%5d)}", out_area->x1, out_area->y1, out_area->x2, out_area->y2); - displayio_area_shift( - &shape_area, - self->x * self->absolute_transform->dx + min(0, self->absolute_transform->dx * displayio_area_width(&shape_area)), - self->y * self->absolute_transform->dy + min(0, self->absolute_transform->dy * displayio_area_height(&shape_area)) - ); - - displayio_area_transform_within( - false, - false, - self->absolute_transform->transpose_xy, - &shape_area, &shape_area, out_area - ); - - displayio_area_shift( - out_area, - self->absolute_transform->x, - self->absolute_transform->y - ); + int16_t x; + int16_t y; + if (self->absolute_transform->transpose_xy) { + x = self->absolute_transform->x + self->absolute_transform->dx * self->y; + y = self->absolute_transform->y + self->absolute_transform->dy * self->x; + area_transpose(out_area); + displayio_area_canon(out_area); + } else { + x = self->absolute_transform->x + self->absolute_transform->dx * self->x; + y = self->absolute_transform->y + self->absolute_transform->dy * self->y; + } + displayio_area_shift(out_area, x, y); VECTORIO_SHAPE_DEBUG(" out:{(%5d,%5d), (%5d,%5d)}\n", out_area->x1, out_area->y1, out_area->x2, out_area->y2); } @@ -198,43 +235,34 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ self->absolute_transform->width, self->absolute_transform->height, self->absolute_transform->mirror_x, self->absolute_transform->mirror_y, self->absolute_transform->transpose_xy ); - uint32_t linestride_px = displayio_area_width(area); - uint32_t line_dirty_offset_px = (overlap.y1 - area->y1) * linestride_px; - uint32_t column_dirty_offset_px = overlap.x1 - area->x1; + uint16_t linestride_px = displayio_area_width(area); + uint16_t line_dirty_offset_px = (overlap.y1 - area->y1) * linestride_px; + uint16_t column_dirty_offset_px = overlap.x1 - area->x1; VECTORIO_SHAPE_DEBUG(", linestride:%3d line_offset:%3d col_offset:%3d depth:%2d ppb:%2d shape:%s", linestride_px, line_dirty_offset_px, column_dirty_offset_px, colorspace->depth, pixels_per_byte, mp_obj_get_type_str(self->ishape.shape)); displayio_input_pixel_t input_pixel; displayio_output_pixel_t output_pixel; - int16_t math_transform_offset_x; - int16_t math_transform_offset_y; - int16_t math_shape_offset_x; - int16_t math_shape_offset_y; + uint16_t width_px_indices; + uint16_t height_px_indices; if (self->absolute_transform->transpose_xy) { - math_transform_offset_x = self->absolute_transform->dy * self->y; - math_transform_offset_y = self->absolute_transform->dx * self->x; - math_shape_offset_x = min(0, self->absolute_transform->dy * displayio_area_width(&self->current_area)); - math_shape_offset_y = min(0, self->absolute_transform->dx * displayio_area_height(&self->current_area)); + width_px_indices = displayio_area_height(&self->current_area) - 1; + height_px_indices = displayio_area_width(&self->current_area) - 1; } else { - math_transform_offset_x = self->absolute_transform->dx * self->x; - math_transform_offset_y = self->absolute_transform->dy * self->y; - math_shape_offset_x = min(0, self->absolute_transform->dx * displayio_area_width(&self->current_area)); - math_shape_offset_y = min(0, self->absolute_transform->dy * displayio_area_height(&self->current_area)); + width_px_indices = displayio_area_width(&self->current_area) - 1; + height_px_indices = displayio_area_height(&self->current_area) - 1; } - VECTORIO_SHAPE_DEBUG(", transform_offset: (%3d,%3d), shape_offset: (%3d,%3d)", math_transform_offset_x, math_transform_offset_y, math_shape_offset_x, math_shape_offset_y); - - - uint32_t mask_start_px = line_dirty_offset_px; + uint16_t mask_start_px = line_dirty_offset_px; for (input_pixel.y = overlap.y1; input_pixel.y < overlap.y2; ++input_pixel.y) { mask_start_px += column_dirty_offset_px; for (input_pixel.x = overlap.x1; input_pixel.x < overlap.x2; ++input_pixel.x) { // Check the mask first to see if the pixel has already been set. - uint32_t pixel_index = mask_start_px + (input_pixel.x - overlap.x1); + uint16_t pixel_index = mask_start_px + (input_pixel.x - overlap.x1); uint32_t *mask_doubleword = &(mask[pixel_index / 32]); uint8_t mask_bit = pixel_index % 32; - VECTORIO_SHAPE_PIXEL_DEBUG("\n%p pixel_index: %5u mask_bit: %2u", self, pixel_index, mask_bit); + VECTORIO_SHAPE_PIXEL_DEBUG("\n%p pixel_index: %5u mask_bit: %2u mask: "U32_TO_BINARY_FMT, self, pixel_index, mask_bit, U32_TO_BINARY(*mask_doubleword)); if ((*mask_doubleword & (1u << mask_bit)) != 0) { VECTORIO_SHAPE_PIXEL_DEBUG(" masked"); continue; @@ -245,12 +273,27 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ int16_t pixel_to_get_x; int16_t pixel_to_get_y; if (self->absolute_transform->transpose_xy) { - pixel_to_get_x = (input_pixel.y - math_transform_offset_y - self->absolute_transform->y) - math_shape_offset_y; - pixel_to_get_y = (input_pixel.x - math_transform_offset_x - self->absolute_transform->x) - math_shape_offset_x; + pixel_to_get_x = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->x; + pixel_to_get_y = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->y; + + if (self->absolute_transform->mirror_x) { + pixel_to_get_y = height_px_indices - pixel_to_get_y; + } + if (self->absolute_transform->mirror_y) { + pixel_to_get_x = width_px_indices - pixel_to_get_x; + } } else { - pixel_to_get_x = (input_pixel.x - math_transform_offset_x - self->absolute_transform->x) - math_shape_offset_x; - pixel_to_get_y = (input_pixel.y - math_transform_offset_y - self->absolute_transform->y) - math_shape_offset_y; + pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x; + pixel_to_get_y = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->y; + + if (self->absolute_transform->mirror_x) { + pixel_to_get_x = width_px_indices - pixel_to_get_x; + } + if (self->absolute_transform->mirror_y) { + pixel_to_get_y = height_px_indices - pixel_to_get_y; + } } + VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y); #ifdef VECTORIO_PERF uint64_t pre_pixel = common_hal_time_monotonic_ns(); @@ -296,10 +339,9 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ } else if (colorspace->depth < 8) { // Reorder the offsets to pack multiple rows into a byte (meaning they share a column). if (!colorspace->pixels_in_byte_share_row) { - uint16_t width = linestride_px; - uint16_t row = pixel_index / width; - uint16_t col = pixel_index % width; - pixel_index = col * pixels_per_byte + (row / pixels_per_byte) * pixels_per_byte * width + row % pixels_per_byte; + uint16_t row = pixel_index / linestride_px; + uint16_t col = pixel_index % linestride_px; + pixel_index = col * pixels_per_byte + (row / pixels_per_byte) * pixels_per_byte * linestride_px + row % pixels_per_byte; } uint8_t shift = (pixel_index % pixels_per_byte) * colorspace->depth; if (colorspace->reverse_pixels_in_byte) { @@ -354,27 +396,57 @@ void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { // Assembles a singly linked list of dirty areas from all components on the display. displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_t *self, displayio_area_t *tail) { - displayio_area_t *new_tail = tail; - if (!displayio_area_empty(&self->ephemeral_dirty_area)) { - // vector.add_to_head - self->ephemeral_dirty_area.next = tail; - new_tail = &self->ephemeral_dirty_area; - VECTORIO_SHAPE_DEBUG("%p get_refresh_area dirty: {(%3d,%3d), (%3d,%3d)}", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); - } if (self->current_area_dirty || (mp_obj_is_type(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || (mp_obj_is_type(self->pixel_shader, &displayio_colorconverter_type) && displayio_colorconverter_needs_refresh(self->pixel_shader)) ) { - self->current_area.next = new_tail; - new_tail = &self->current_area; - VECTORIO_SHAPE_DEBUG(" redrawing current: {(%3d,%3d), (%3d,%3d)}", self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2); + if (!displayio_area_empty(&self->ephemeral_dirty_area)) { + // Both are dirty, check if we should combine the areas or draw separately + // Draws as few pixels as possible both when animations move short distances and large distances. + // The display core implementation currently doesn't combine areas to reduce redrawing of masked areas. If it does, + // this could be simplified to just return the 2 possibly overlapping areas. + displayio_area_t area_swap; + displayio_area_compute_overlap(&self->ephemeral_dirty_area, &self->current_area, &area_swap); + uint32_t overlap_size = displayio_area_size(&area_swap); + displayio_area_union(&self->ephemeral_dirty_area, &self->current_area, &area_swap); // Leave area_swap as the union area for later. + uint32_t union_size = displayio_area_size(&area_swap); + uint32_t current_size = displayio_area_size(&self->current_area); + uint32_t dirty_size = displayio_area_size(&self->ephemeral_dirty_area); + + VECTORIO_SHAPE_DEBUG("%p get_refresh_area: dirty{(%3d,%3d), (%3d,%3d)} + current{(%3d,%3d), (%3d,%3d)} = union{(%3d,%3d), (%3d,%3d)}: union%d - dirty%d - curr%d + overlap%d = excluded%d : ", self, + self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2, + self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2, + area_swap.x1, area_swap.y1, area_swap.x2, area_swap.y2, + union_size, dirty_size, current_size, overlap_size, (int32_t)union_size - dirty_size - current_size + overlap_size + ); + + if ((int32_t)union_size - dirty_size - current_size + overlap_size <= min(dirty_size, current_size)) { + // The excluded / non-overlapping area from the disjoint dirty and current areas is smaller + // than the smallest area we need to draw. Redrawing the overlapping area would cost more + // than just drawing the union disjoint area once. + VECTORIO_SHAPE_DEBUG("combining to take disjoint area\n"); + displayio_area_copy(&area_swap, &self->ephemeral_dirty_area); + } else { + // The excluded area between the 2 dirty areas is larger than the smallest dirty area. It would be + // more costly to combine these areas than possibly redraw some overlap. + VECTORIO_SHAPE_DEBUG("excluded area too large, drawing separate area\n"); + self->current_area.next = tail; + tail = &self->current_area; + } + + self->ephemeral_dirty_area.next = tail; + tail = &self->ephemeral_dirty_area; + } else { + self->current_area.next = tail; + tail = &self->current_area; + VECTORIO_SHAPE_DEBUG("%p get_refresh_area: redrawing current: {(%3d,%3d), (%3d,%3d)}\n", self, self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2); + } + } else if (!displayio_area_empty(&self->ephemeral_dirty_area)) { + self->ephemeral_dirty_area.next = tail; + tail = &self->ephemeral_dirty_area; + VECTORIO_SHAPE_DEBUG("%p get_refresh_area redrawing dirty: {(%3d,%3d), (%3d,%3d)}\n", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); } - #ifdef VECTORIO_SHAPE_DEBUG - if (new_tail != tail) { - VECTORIO_SHAPE_DEBUG("\n"); - } - #endif - return new_tail; + return tail; } void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displayio_buffer_transform_t *group_transform) { From 051d7a970ef23b349f5b63e39f1c56f460c484e5 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sat, 7 Aug 2021 19:32:02 -0700 Subject: [PATCH 12/25] fix rotation and mirroring now works with all vector shapes, even those with internal reference locations that are negative. All shape locations are anchored to their 0,0 but they can display pixels from negative coordinates if the shape's location on the screen would have room for it. --- shared-module/vectorio/VectorShape.c | 29 ++++++++++++---------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 64c1b94c0d..b18460868d 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -14,8 +14,8 @@ #include "shared-bindings/vectorio/Rectangle.h" // Lifecycle actions. -// #define VECTORIO_SHAPE_DEBUG(...) (void)0 -#define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#define VECTORIO_SHAPE_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Used in both logging and ifdefs, for extra variables @@ -23,8 +23,8 @@ // Really verbose. -// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 -#define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" #define U32_TO_BINARY(u32) \ @@ -244,15 +244,8 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ displayio_input_pixel_t input_pixel; displayio_output_pixel_t output_pixel; - uint16_t width_px_indices; - uint16_t height_px_indices; - if (self->absolute_transform->transpose_xy) { - width_px_indices = displayio_area_height(&self->current_area) - 1; - height_px_indices = displayio_area_width(&self->current_area) - 1; - } else { - width_px_indices = displayio_area_width(&self->current_area) - 1; - height_px_indices = displayio_area_height(&self->current_area) - 1; - } + displayio_area_t shape_area; + self->ishape.get_area(self->ishape.shape, &shape_area); uint16_t mask_start_px = line_dirty_offset_px; for (input_pixel.y = overlap.y1; input_pixel.y < overlap.y2; ++input_pixel.y) { @@ -275,22 +268,24 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ if (self->absolute_transform->transpose_xy) { pixel_to_get_x = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->x; pixel_to_get_y = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->y; + VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); if (self->absolute_transform->mirror_x) { - pixel_to_get_y = height_px_indices - pixel_to_get_y; + pixel_to_get_y = shape_area.y2 - 1 - (pixel_to_get_y - shape_area.y1); } if (self->absolute_transform->mirror_y) { - pixel_to_get_x = width_px_indices - pixel_to_get_x; + pixel_to_get_x = shape_area.x2 - 1 - (pixel_to_get_x - shape_area.x1); } } else { pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x; pixel_to_get_y = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->y; + VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); if (self->absolute_transform->mirror_x) { - pixel_to_get_x = width_px_indices - pixel_to_get_x; + pixel_to_get_x = shape_area.x2 - 1 - (pixel_to_get_x - shape_area.x1); } if (self->absolute_transform->mirror_y) { - pixel_to_get_y = height_px_indices - pixel_to_get_y; + pixel_to_get_y = shape_area.y2 - 1 - (pixel_to_get_y - shape_area.y1); } } From bb25aeee510e41bb0e3ea7df5442af4782c30077 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sat, 7 Aug 2021 19:40:07 -0700 Subject: [PATCH 13/25] fix code formatting that pre-commit --all-files did not locally report --- shared-module/vectorio/Polygon.c | 4 +- shared-module/vectorio/VectorShape.c | 66 ++++++++++++++-------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c index 6cc99a6096..f7199c7f83 100644 --- a/shared-module/vectorio/Polygon.c +++ b/shared-module/vectorio/Polygon.c @@ -80,8 +80,8 @@ mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) { VECTORIO_POLYGON_DEBUG(" (%4d, %4d)\n", self->points_list[i], self->points_list[i + 1]); mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - pair->items[0] = mp_obj_new_int((mp_int_t) self->points_list[i ]); - pair->items[1] = mp_obj_new_int((mp_int_t) self->points_list[i + 1]); + pair->items[0] = mp_obj_new_int((mp_int_t)self->points_list[i ]); + pair->items[1] = mp_obj_new_int((mp_int_t)self->points_list[i + 1]); mp_obj_list_append( list, diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index b18460868d..bf7cd7dc42 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -28,38 +28,38 @@ #define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" #define U32_TO_BINARY(u32) \ - (u32 & 0x80000000 ? '1' : '0'), \ - (u32 & 0x40000000 ? '1' : '0'), \ - (u32 & 0x20000000 ? '1' : '0'), \ - (u32 & 0x10000000 ? '1' : '0'), \ - (u32 & 0x8000000 ? '1' : '0'), \ - (u32 & 0x4000000 ? '1' : '0'), \ - (u32 & 0x2000000 ? '1' : '0'), \ - (u32 & 0x1000000 ? '1' : '0'), \ - (u32 & 0x800000 ? '1' : '0'), \ - (u32 & 0x400000 ? '1' : '0'), \ - (u32 & 0x200000 ? '1' : '0'), \ - (u32 & 0x100000 ? '1' : '0'), \ - (u32 & 0x80000 ? '1' : '0'), \ - (u32 & 0x40000 ? '1' : '0'), \ - (u32 & 0x20000 ? '1' : '0'), \ - (u32 & 0x10000 ? '1' : '0'), \ - (u32 & 0x8000 ? '1' : '0'), \ - (u32 & 0x4000 ? '1' : '0'), \ - (u32 & 0x2000 ? '1' : '0'), \ - (u32 & 0x1000 ? '1' : '0'), \ - (u32 & 0x800 ? '1' : '0'), \ - (u32 & 0x400 ? '1' : '0'), \ - (u32 & 0x200 ? '1' : '0'), \ - (u32 & 0x100 ? '1' : '0'), \ - (u32 & 0x80 ? '1' : '0'), \ - (u32 & 0x40 ? '1' : '0'), \ - (u32 & 0x20 ? '1' : '0'), \ - (u32 & 0x10 ? '1' : '0'), \ - (u32 & 0x8 ? '1' : '0'), \ - (u32 & 0x4 ? '1' : '0'), \ - (u32 & 0x2 ? '1' : '0'), \ - (u32 & 0x1 ? '1' : '0') + (u32 & 0x80000000 ? '1' : '0'), \ + (u32 & 0x40000000 ? '1' : '0'), \ + (u32 & 0x20000000 ? '1' : '0'), \ + (u32 & 0x10000000 ? '1' : '0'), \ + (u32 & 0x8000000 ? '1' : '0'), \ + (u32 & 0x4000000 ? '1' : '0'), \ + (u32 & 0x2000000 ? '1' : '0'), \ + (u32 & 0x1000000 ? '1' : '0'), \ + (u32 & 0x800000 ? '1' : '0'), \ + (u32 & 0x400000 ? '1' : '0'), \ + (u32 & 0x200000 ? '1' : '0'), \ + (u32 & 0x100000 ? '1' : '0'), \ + (u32 & 0x80000 ? '1' : '0'), \ + (u32 & 0x40000 ? '1' : '0'), \ + (u32 & 0x20000 ? '1' : '0'), \ + (u32 & 0x10000 ? '1' : '0'), \ + (u32 & 0x8000 ? '1' : '0'), \ + (u32 & 0x4000 ? '1' : '0'), \ + (u32 & 0x2000 ? '1' : '0'), \ + (u32 & 0x1000 ? '1' : '0'), \ + (u32 & 0x800 ? '1' : '0'), \ + (u32 & 0x400 ? '1' : '0'), \ + (u32 & 0x200 ? '1' : '0'), \ + (u32 & 0x100 ? '1' : '0'), \ + (u32 & 0x80 ? '1' : '0'), \ + (u32 & 0x40 ? '1' : '0'), \ + (u32 & 0x20 ? '1' : '0'), \ + (u32 & 0x10 ? '1' : '0'), \ + (u32 & 0x8 ? '1' : '0'), \ + (u32 & 0x4 ? '1' : '0'), \ + (u32 & 0x2 ? '1' : '0'), \ + (u32 & 0x1 ? '1' : '0') inline __attribute__((always_inline)) @@ -413,7 +413,7 @@ displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_ self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2, area_swap.x1, area_swap.y1, area_swap.x2, area_swap.y2, union_size, dirty_size, current_size, overlap_size, (int32_t)union_size - dirty_size - current_size + overlap_size - ); + ); if ((int32_t)union_size - dirty_size - current_size + overlap_size <= min(dirty_size, current_size)) { // The excluded / non-overlapping area from the disjoint dirty and current areas is smaller From 5ed585d3f463f6a5a7f4205a9e19314068877175 Mon Sep 17 00:00:00 2001 From: Wellington Terumi Uemura Date: Sat, 7 Aug 2021 05:13:55 +0000 Subject: [PATCH 14/25] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (1013 of 1013 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/pt_BR/ --- locale/pt_BR.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/locale/pt_BR.po b/locale/pt_BR.po index cad52558af..c120f92ec0 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2021-07-24 15:35+0000\n" +"PO-Revision-Date: 2021-08-08 05:33+0000\n" "Last-Translator: Wellington Terumi Uemura \n" "Language-Team: \n" "Language: pt_BR\n" @@ -14,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.7.2-dev\n" +"X-Generator: Weblate 4.8-dev\n" #: main.c msgid "" @@ -3164,7 +3164,7 @@ msgstr "o arquivo deve ser um arquivo aberto no modo byte" #: shared-bindings/traceback/__init__.c msgid "file write is not available" -msgstr "" +msgstr "a gravação de arquivos não está disponível" #: shared-bindings/storage/__init__.c msgid "filesystem must provide mount method" @@ -3456,7 +3456,7 @@ msgstr "element_size %d é inválido, deve ser, 1, 2, ou 4" #: shared-bindings/traceback/__init__.c msgid "invalid exception" -msgstr "" +msgstr "exceção inválida" #: extmod/modframebuf.c msgid "invalid format" @@ -3497,7 +3497,7 @@ msgstr "sintaxe inválida para o número" #: py/objexcept.c shared-bindings/traceback/__init__.c msgid "invalid traceback" -msgstr "" +msgstr "rastreamento inválido" #: py/objtype.c msgid "issubclass() arg 1 must be a class" @@ -3548,7 +3548,7 @@ msgstr "o lhs e rhs devem ser compatíveis" #: shared-bindings/traceback/__init__.c msgid "limit should be an int" -msgstr "" +msgstr "o limite deve ser um inteiro" #: py/emitnative.c msgid "local '%q' has type '%q' but source is '%q'" From a1fff320fb4b827dc59c6295d09bd749f6fcf7dd Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sun, 8 Aug 2021 00:14:53 -0700 Subject: [PATCH 15/25] add location property to vectorshape and all composed shapes --- locale/circuitpython.pot | 23 +++++++------- shared-bindings/vectorio/Circle.c | 1 + shared-bindings/vectorio/Polygon.c | 1 + shared-bindings/vectorio/Rectangle.c | 1 + shared-bindings/vectorio/VectorShape.c | 30 ++++++++++++++++++ shared-bindings/vectorio/VectorShape.h | 5 +++ shared-module/vectorio/VectorShape.c | 43 ++++++++++++++++++++++---- 7 files changed, 86 insertions(+), 18 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 81531c0cbd..885f596776 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -318,6 +318,10 @@ msgstr "" msgid "'yield' outside function" msgstr "" +#: shared-module/vectorio/VectorShape.c +msgid "(x,y) integers required" +msgstr "" + #: py/compile.c msgid "*x must be assignment target" msgstr "" @@ -1185,11 +1189,6 @@ msgstr "" msgid "Input/output error" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, c-format -msgid "Missing jmp_pin. Instruction %d jumps on pin" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #, c-format msgid "Instruction %d shifts in more bits than pin count" @@ -1506,6 +1505,11 @@ msgstr "" msgid "Missing first_set_pin. Instruction %d sets pin(s)" msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, c-format +msgid "Missing jmp_pin. Instruction %d jumps on pin" +msgstr "" + #: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2063,7 +2067,6 @@ msgid "Size not supported" msgstr "" #: ports/raspberrypi/common-hal/alarm/SleepMemory.c -#: ports/stm/common-hal/alarm/SleepMemory.c msgid "Sleep Memory not available" msgstr "" @@ -2510,7 +2513,7 @@ msgid "argument name reused" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c +#: shared-bindings/digitalio/DigitalInOut.c msgid "argument num/types mismatch" msgstr "" @@ -3594,10 +3597,6 @@ msgstr "" msgid "no active exception to reraise" msgstr "" -#: shared-bindings/socket/__init__.c shared-module/network/__init__.c -msgid "no available NIC" -msgstr "" - #: py/compile.c msgid "no binding for nonlocal found" msgstr "" @@ -4299,7 +4298,7 @@ msgid "unreadable attribute" msgstr "" #: shared-bindings/displayio/TileGrid.c shared-bindings/vectorio/VectorShape.c -#: shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Polygon.c shared-module/vectorio/VectorShape.c msgid "unsupported %q type" msgstr "" diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c index 37780b5562..c0cc0bbcc2 100644 --- a/shared-bindings/vectorio/Circle.c +++ b/shared-bindings/vectorio/Circle.c @@ -86,6 +86,7 @@ STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) }, { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_circle_locals_dict, vectorio_circle_locals_dict_table); diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c index 551954f98d..5d493a30b6 100644 --- a/shared-bindings/vectorio/Polygon.c +++ b/shared-bindings/vectorio/Polygon.c @@ -91,6 +91,7 @@ STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) }, { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_polygon_locals_dict, vectorio_polygon_locals_dict_table); diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c index 1e885064ff..aa2c166a6d 100644 --- a/shared-bindings/vectorio/Rectangle.c +++ b/shared-bindings/vectorio/Rectangle.c @@ -64,6 +64,7 @@ STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) }, { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&vectorio_vector_shape_location_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&vectorio_vector_shape_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(vectorio_rectangle_locals_dict, vectorio_rectangle_locals_dict_table); diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index f59ff26213..6e4299a6d3 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -143,6 +143,36 @@ const mp_obj_property_t vectorio_vector_shape_y_obj = { }; +// location: Tuple[int, int] +// """location of the center point of the shape in the parent.""" +// +STATIC mp_obj_t vectorio_vector_shape_obj_get_location(mp_obj_t wrapper_shape) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + + return MP_OBJ_TO_PTR(common_hal_vectorio_vector_shape_get_location(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_location_obj, vectorio_vector_shape_obj_get_location); + +STATIC mp_obj_t vectorio_vector_shape_obj_set_location(mp_obj_t wrapper_shape, mp_obj_t location_obj) { + // Relies on the fact that only vector_shape impl gets matched with a VectorShape. + const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape); + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape)); + + common_hal_vectorio_vector_shape_set_location(self, location_obj); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_location_obj, vectorio_vector_shape_obj_set_location); + +const mp_obj_property_t vectorio_vector_shape_location_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_vector_shape_get_location_obj, + (mp_obj_t)&vectorio_vector_shape_set_location_obj, + MP_ROM_NONE}, +}; + + // pixel_shader: Union[ColorConverter, Palette] // """The pixel shader of the shape.""" // diff --git a/shared-bindings/vectorio/VectorShape.h b/shared-bindings/vectorio/VectorShape.h index 4cf2ae373b..9ac6906000 100644 --- a/shared-bindings/vectorio/VectorShape.h +++ b/shared-bindings/vectorio/VectorShape.h @@ -2,6 +2,7 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H #include "py/objproperty.h" +#include "py/objtuple.h" #include "shared-bindings/vectorio/__init__.h" #include "shared-module/vectorio/VectorShape.h" @@ -22,6 +23,9 @@ void common_hal_vectorio_vector_shape_set_dirty(void *self); mp_int_t common_hal_vectorio_vector_shape_get_x(vectorio_vector_shape_t *self); void common_hal_vectorio_vector_shape_set_x(vectorio_vector_shape_t *self, mp_int_t x); +mp_obj_tuple_t *common_hal_vectorio_vector_shape_get_location(vectorio_vector_shape_t *self); +void common_hal_vectorio_vector_shape_set_location(vectorio_vector_shape_t *self, mp_obj_t xy); + mp_int_t common_hal_vectorio_vector_shape_get_y(vectorio_vector_shape_t *self); void common_hal_vectorio_vector_shape_set_y(vectorio_vector_shape_t *self, mp_int_t y); @@ -34,6 +38,7 @@ void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displ extern vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl; extern const mp_obj_property_t vectorio_vector_shape_x_obj; extern const mp_obj_property_t vectorio_vector_shape_y_obj; +extern const mp_obj_property_t vectorio_vector_shape_location_obj; extern const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj; #endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index bf7cd7dc42..a6a63a498a 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -14,8 +14,8 @@ #include "shared-bindings/vectorio/Rectangle.h" // Lifecycle actions. -#define VECTORIO_SHAPE_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +//#define VECTORIO_SHAPE_DEBUG(...) (void)0 +#define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Used in both logging and ifdefs, for extra variables @@ -23,8 +23,8 @@ // Really verbose. -#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 -// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +//#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 +#define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" #define U32_TO_BINARY(u32) \ @@ -192,6 +192,37 @@ void common_hal_vectorio_vector_shape_set_y(vectorio_vector_shape_t *self, mp_in common_hal_vectorio_vector_shape_set_dirty(self); } +mp_obj_tuple_t *common_hal_vectorio_vector_shape_get_location(vectorio_vector_shape_t *self) { + VECTORIO_SHAPE_DEBUG("%p get_location\n", self); + mp_obj_tuple_t *pair = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + pair->items[0] = mp_obj_new_int((mp_int_t)self->x); + pair->items[1] = mp_obj_new_int((mp_int_t)self->y); + return pair; +} + + +void common_hal_vectorio_vector_shape_set_location(vectorio_vector_shape_t *self, mp_obj_t xy) { + VECTORIO_SHAPE_DEBUG("%p set_location\n", self); + size_t tuple_len = 0; + mp_obj_t *tuple_items; + mp_obj_tuple_get(xy, &tuple_len, &tuple_items); + if (tuple_len != 2) { + mp_raise_TypeError_varg(translate("(x,y) integers required")); + } + + mp_int_t x; + mp_int_t y; + if (!mp_obj_get_int_maybe(tuple_items[ 0 ], &x) + || !mp_obj_get_int_maybe(tuple_items[ 1 ], &y) + || x < SHRT_MIN || x > SHRT_MAX || y < SHRT_MIN || y > SHRT_MAX + ) { + mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point); + } + self->x = (int16_t)x; + self->y = (int16_t)y; + common_hal_vectorio_vector_shape_set_dirty(self); +} + mp_obj_t common_hal_vectorio_vector_shape_get_pixel_shader(vectorio_vector_shape_t *self) { VECTORIO_SHAPE_DEBUG("%p get_pixel_shader\n", self); @@ -271,10 +302,10 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); if (self->absolute_transform->mirror_x) { - pixel_to_get_y = shape_area.y2 - 1 - (pixel_to_get_y - shape_area.y1); + pixel_to_get_y = shape_area.y2 - 1 - pixel_to_get_y; } if (self->absolute_transform->mirror_y) { - pixel_to_get_x = shape_area.x2 - 1 - (pixel_to_get_x - shape_area.x1); + pixel_to_get_x = shape_area.x2 - 1 - pixel_to_get_x; } } else { pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x; From 9897ac6b5cf8d48219cbb05c37f3334e86cc08c7 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sun, 8 Aug 2021 00:25:17 -0700 Subject: [PATCH 16/25] yet more failures of local pre-commit to find that which github pre-commit does --- shared-module/vectorio/VectorShape.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index a6a63a498a..259ab87251 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -14,7 +14,7 @@ #include "shared-bindings/vectorio/Rectangle.h" // Lifecycle actions. -//#define VECTORIO_SHAPE_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_DEBUG(...) (void)0 #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) @@ -23,7 +23,7 @@ // Really verbose. -//#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" From a15ac65fa02cf5bb1c4dec9aae5c627750efedfb Mon Sep 17 00:00:00 2001 From: Nathan Young <77929198+NathanY3G@users.noreply.github.com> Date: Sun, 8 Aug 2021 21:43:12 +0200 Subject: [PATCH 17/25] Add board.LED for Grand Central M4 Express Fixes #5111 --- ports/atmel-samd/boards/grandcentral_m4_express/pins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/grandcentral_m4_express/pins.c b/ports/atmel-samd/boards/grandcentral_m4_express/pins.c index b125aca086..cb683db0bd 100644 --- a/ports/atmel-samd/boards/grandcentral_m4_express/pins.c +++ b/ports/atmel-samd/boards/grandcentral_m4_express/pins.c @@ -137,6 +137,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PC24) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB01) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LED_RX), MP_ROM_PTR(&pin_PC31) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LED_TX), MP_ROM_PTR(&pin_PC30) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, From 7eece7d959b44247335b2c9fa192cc9a2f8bbd8f Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sun, 8 Aug 2021 15:35:36 -0700 Subject: [PATCH 18/25] dirty area computed for non-transposed but at least d-1 --- shared-module/vectorio/VectorShape.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 259ab87251..bd0684670a 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -97,11 +97,19 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou x = self->absolute_transform->x + self->absolute_transform->dx * self->y; y = self->absolute_transform->y + self->absolute_transform->dy * self->x; area_transpose(out_area); - displayio_area_canon(out_area); } else { + if (self->absolute_transform->dx < 1) { + out_area->x1 = out_area->x1 * -1 + 1; + out_area->x2 = out_area->x2 * -1 + 1; + } + if (self->absolute_transform->dy < 1) { + out_area->y1 = out_area->y1 * -1 + 1; + out_area->y2 = out_area->y2 * -1 + 1; + } x = self->absolute_transform->x + self->absolute_transform->dx * self->x; y = self->absolute_transform->y + self->absolute_transform->dy * self->y; } + displayio_area_canon(out_area); displayio_area_shift(out_area, x, y); VECTORIO_SHAPE_DEBUG(" out:{(%5d,%5d), (%5d,%5d)}\n", out_area->x1, out_area->y1, out_area->x2, out_area->y2); @@ -313,10 +321,10 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); if (self->absolute_transform->mirror_x) { - pixel_to_get_x = shape_area.x2 - 1 - (pixel_to_get_x - shape_area.x1); + pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x + shape_area.x1) + shape_area.x1 - 1; } if (self->absolute_transform->mirror_y) { - pixel_to_get_y = shape_area.y2 - 1 - (pixel_to_get_y - shape_area.y1); + pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y + shape_area.y1) + +shape_area.y1 - 1; } } From cf2712d23f5c12694305c6ecbc3673c3aba37ef1 Mon Sep 17 00:00:00 2001 From: Kenny <3454741+WarriorOfWire@users.noreply.github.com> Date: Sun, 8 Aug 2021 17:01:36 -0700 Subject: [PATCH 19/25] transposing and mirroring work * fix absolute_transform dirtying early instead of after the change, missing the draw * fix transpose and mirror. (0,0) -> location in all vector shapes now in all rotations. --- shared-module/vectorio/VectorShape.c | 55 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index bd0684670a..9d0279cf14 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -14,8 +14,8 @@ #include "shared-bindings/vectorio/Rectangle.h" // Lifecycle actions. -// #define VECTORIO_SHAPE_DEBUG(...) (void)0 -#define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#define VECTORIO_SHAPE_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) // Used in both logging and ifdefs, for extra variables @@ -23,8 +23,8 @@ // Really verbose. -// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 -#define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) +#define VECTORIO_SHAPE_PIXEL_DEBUG(...) (void)0 +// #define VECTORIO_SHAPE_PIXEL_DEBUG(...) mp_printf(&mp_plat_print, __VA_ARGS__) #define U32_TO_BINARY_FMT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c" #define U32_TO_BINARY(u32) \ @@ -96,8 +96,19 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou if (self->absolute_transform->transpose_xy) { x = self->absolute_transform->x + self->absolute_transform->dx * self->y; y = self->absolute_transform->y + self->absolute_transform->dy * self->x; + if (self->absolute_transform->dx < 1) { + out_area->y1 = out_area->y1 * -1 + 1; + out_area->y2 = out_area->y2 * -1 + 1; + } + if (self->absolute_transform->dy < 1) { + out_area->x1 = out_area->x1 * -1 + 1; + out_area->x2 = out_area->x2 * -1 + 1; + } area_transpose(out_area); } else { + x = self->absolute_transform->x + self->absolute_transform->dx * self->x; + y = self->absolute_transform->y + self->absolute_transform->dy * self->y; + if (self->absolute_transform->dx < 1) { out_area->x1 = out_area->x1 * -1 + 1; out_area->x2 = out_area->x2 * -1 + 1; @@ -106,8 +117,6 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou out_area->y1 = out_area->y1 * -1 + 1; out_area->y2 = out_area->y2 * -1 + 1; } - x = self->absolute_transform->x + self->absolute_transform->dx * self->x; - y = self->absolute_transform->y + self->absolute_transform->dy * self->y; } displayio_area_canon(out_area); displayio_area_shift(out_area, x, y); @@ -307,25 +316,35 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ if (self->absolute_transform->transpose_xy) { pixel_to_get_x = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->x; pixel_to_get_y = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->y; - VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); - if (self->absolute_transform->mirror_x) { - pixel_to_get_y = shape_area.y2 - 1 - pixel_to_get_y; + VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); + if (self->absolute_transform->dx < 1) { + pixel_to_get_y *= -1; } - if (self->absolute_transform->mirror_y) { - pixel_to_get_x = shape_area.x2 - 1 - pixel_to_get_x; + if (self->absolute_transform->dy < 1) { + pixel_to_get_x *= -1; } + VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); } else { pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x; pixel_to_get_y = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->y; - VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); - if (self->absolute_transform->mirror_x) { - pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x + shape_area.x1) + shape_area.x1 - 1; + VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); + if (self->absolute_transform->dx < 1) { + pixel_to_get_x *= -1; } - if (self->absolute_transform->mirror_y) { - pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y + shape_area.y1) + +shape_area.y1 - 1; + if (self->absolute_transform->dy < 1) { + pixel_to_get_y *= -1; } + VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y); + + // It's mirrored via dx. Maybe we need to add support for also separately mirroring? + // if (self->absolute_transform->mirror_x) { + // pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x - shape_area.x1) + shape_area.x1 - 1; + // } + // if (self->absolute_transform->mirror_y) { + // pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y - shape_area.y1) + +shape_area.y1 - 1; + // } } VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y); @@ -407,7 +426,7 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ void vectorio_vector_shape_finish_refresh(vectorio_vector_shape_t *self) { - if (displayio_area_empty(&self->ephemeral_dirty_area)) { + if (displayio_area_empty(&self->ephemeral_dirty_area) && !self->current_area_dirty) { return; } VECTORIO_SHAPE_DEBUG("%p finish_refresh was:{(%3d,%3d), (%3d,%3d)}\n", self, self->ephemeral_dirty_area.x1, self->ephemeral_dirty_area.y1, self->ephemeral_dirty_area.x2, self->ephemeral_dirty_area.y2); @@ -484,6 +503,6 @@ displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_ } void vectorio_vector_shape_update_transform(vectorio_vector_shape_t *self, displayio_buffer_transform_t *group_transform) { - common_hal_vectorio_vector_shape_set_dirty(self); self->absolute_transform = group_transform == NULL ? &null_transform : group_transform; + common_hal_vectorio_vector_shape_set_dirty(self); } From 579194a543ca407f20a6d88a641cf2f487feee3a Mon Sep 17 00:00:00 2001 From: Nathan Young <77929198+NathanY3G@users.noreply.github.com> Date: Mon, 9 Aug 2021 05:35:38 +0200 Subject: [PATCH 20/25] Colocated board.LED and D13 together (GCM4) --- ports/atmel-samd/boards/grandcentral_m4_express/pins.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/grandcentral_m4_express/pins.c b/ports/atmel-samd/boards/grandcentral_m4_express/pins.c index cb683db0bd..7db9491dd3 100644 --- a/ports/atmel-samd/boards/grandcentral_m4_express/pins.c +++ b/ports/atmel-samd/boards/grandcentral_m4_express/pins.c @@ -52,6 +52,8 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PB22) }, { MP_OBJ_NEW_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PB23) }, { MP_OBJ_NEW_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_PB00) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB01) }, { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB01) }, { MP_OBJ_NEW_QSTR(MP_QSTR_TX3), MP_ROM_PTR(&pin_PB16) }, @@ -137,7 +139,6 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PC24) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB01) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LED_RX), MP_ROM_PTR(&pin_PC31) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LED_TX), MP_ROM_PTR(&pin_PC30) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, From bfea6947e510e5a20bd46db4946f9ae524077b47 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 8 Aug 2021 10:27:50 -0500 Subject: [PATCH 21/25] Improve mp_printf with support for compressed strings * The new nonstandard '%S' format takes a pointer to compressed_string_t and prints it * The new mp_cprintf and mp_vcprintf take a format string that is a compressed_string_t --- locale/circuitpython.pot | 12 ++++++--- py/builtinhelp.c | 25 +++++------------- py/mpprint.c | 42 +++++++++++++++++++++++++----- py/mpprint.h | 6 +++++ py/obj.c | 16 +++--------- py/objexcept.c | 5 +--- shared-module/traceback/__init__.c | 14 +++------- supervisor/shared/translate.c | 5 ++-- supervisor/shared/translate.h | 2 +- 9 files changed, 67 insertions(+), 60 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index f10f7fd019..720f52d40b 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -35,11 +35,11 @@ msgid "" "https://github.com/adafruit/circuitpython/issues\n" msgstr "" -#: py/obj.c shared-bindings/traceback/__init__.c +#: py/obj.c msgid " File \"%q\"" msgstr "" -#: py/obj.c shared-bindings/traceback/__init__.c +#: py/obj.c msgid " File \"%q\", line %d" msgstr "" @@ -322,7 +322,7 @@ msgstr "" msgid "*x must be assignment target" msgstr "" -#: py/obj.c shared-bindings/traceback/__init__.c +#: py/obj.c msgid ", in %q\n" msgstr "" @@ -2211,7 +2211,7 @@ msgstr "" msgid "Touch alarms not available" msgstr "" -#: py/obj.c shared-bindings/traceback/__init__.c +#: py/obj.c msgid "Traceback (most recent call last):\n" msgstr "" @@ -3903,6 +3903,10 @@ msgstr "" #: ports/esp32s2/boards/espressif_saola_1_wrover/mpconfigboard.h #: ports/esp32s2/boards/franzininho_wifi_wroom/mpconfigboard.h #: ports/esp32s2/boards/franzininho_wifi_wrover/mpconfigboard.h +#: ports/esp32s2/boards/gravitech_cucumber_m/mpconfigboard.h +#: ports/esp32s2/boards/gravitech_cucumber_ms/mpconfigboard.h +#: ports/esp32s2/boards/gravitech_cucumber_r/mpconfigboard.h +#: ports/esp32s2/boards/gravitech_cucumber_rs/mpconfigboard.h #: ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h #: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h #: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h diff --git a/py/builtinhelp.c b/py/builtinhelp.c index 344ded80b0..8590c4beea 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -131,10 +131,7 @@ STATIC void mp_help_print_modules(void) { #if MICROPY_ENABLE_EXTERNAL_IMPORT // let the user know there may be other modules available from the filesystem - const compressed_string_t *compressed = translate("Plus any modules on the filesystem\n"); - char decompressed[decompress_length(compressed)]; - decompress(compressed, decompressed); - mp_print_str(MP_PYTHON_PRINTER, decompressed); + mp_printf(MP_PYTHON_PRINTER, "%S", translate("Plus any modules on the filesystem\n")); #endif } #endif @@ -150,18 +147,10 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) { const mp_obj_type_t *type = mp_obj_get_type(obj); // try to print something sensible about the given object - const compressed_string_t *compressed = translate("object "); - char decompressed_object[decompress_length(compressed)]; - decompress(compressed, decompressed_object); - - mp_print_str(MP_PYTHON_PRINTER, decompressed_object); + mp_cprintf(MP_PYTHON_PRINTER, translate("object ")); mp_obj_print(obj, PRINT_STR); - compressed = translate(" is of type %q\n"); - char decompressed_typestring[decompress_length(compressed)]; - decompress(compressed, decompressed_typestring); - - mp_printf(MP_PYTHON_PRINTER, decompressed_typestring, type->name); + mp_cprintf(MP_PYTHON_PRINTER, translate(" is of type %q\n"), type->name); mp_map_t *map = NULL; if (type == &mp_type_module) { @@ -186,11 +175,9 @@ STATIC void mp_help_print_obj(const mp_obj_t obj) { STATIC mp_obj_t mp_builtin_help(size_t n_args, const mp_obj_t *args) { if (n_args == 0) { // print a general help message. Translate only works on single strings on one line. - const compressed_string_t *compressed = - translate("Welcome to Adafruit CircuitPython %s!\n\nPlease visit learn.adafruit.com/category/circuitpython for project guides.\n\nTo list built-in modules please do `help(\"modules\")`.\n"); - char decompressed[decompress_length(compressed)]; - decompress(compressed, decompressed); - mp_printf(MP_PYTHON_PRINTER, decompressed, MICROPY_GIT_TAG); + mp_cprintf(MP_PYTHON_PRINTER, + translate("Welcome to Adafruit CircuitPython %s!\n\nPlease visit learn.adafruit.com/category/circuitpython for project guides.\n\nTo list built-in modules please do `help(\"modules\")`.\n"), + MICROPY_GIT_TAG); } else { // try to print something sensible about the given object mp_help_print_obj(args[0]); diff --git a/py/mpprint.c b/py/mpprint.c index b99b5d658d..af485a50f2 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -376,6 +376,13 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c } #endif +static int print_str_common(const mp_print_t *print, const char *str, int prec, size_t len, int flags, int fill, int width) { + if (prec >= 0 && (size_t)prec < len) { + len = prec; + } + return mp_print_strn(print, str, len, flags, fill, width); +} + int mp_printf(const mp_print_t *print, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -484,19 +491,24 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { qstr qst = va_arg(args, qstr); size_t len; const char *str = (const char *)qstr_data(qst, &len); - if (prec >= 0 && (size_t)prec < len) { - len = prec; - } - chrs += mp_print_strn(print, str, len, flags, fill, width); + chrs += print_str_common(print, str, prec, len, flags, fill, width); + break; + } + case 'S': { + compressed_string_t *arg = va_arg(args, compressed_string_t *); + size_t len_with_nul = decompress_length(arg); + size_t len = len_with_nul - 1; + char str[len_with_nul]; + decompress(arg, str); + chrs += print_str_common(print, str, prec, len, flags, fill, width); break; } case 's': { const char *str = va_arg(args, const char *); #ifndef NDEBUG // With debugging enabled, catch printing of null string pointers - if (prec != 0 && str == NULL) { - chrs += mp_print_strn(print, "(null)", 6, flags, fill, width); - break; + if (str == NULL) { + str = "(null)"; } #endif size_t len = strlen(str); @@ -574,3 +586,19 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } return chrs; } + +int mp_cprintf(const mp_print_t *print, const compressed_string_t *compressed_fmt, ...) { + va_list ap; + va_start(ap, compressed_fmt); + int ret = mp_vcprintf(print, compressed_fmt, ap); + va_end(ap); + return ret; +} + +int mp_vcprintf(const mp_print_t *print, const compressed_string_t *compressed_fmt, va_list args) { + char fmt[decompress_length(compressed_fmt)]; + // TODO: Optimise this to format-while-decompressing (and not require the temp stack space). + decompress(compressed_fmt, fmt); + + return mp_vprintf(print, fmt, args); +} diff --git a/py/mpprint.h b/py/mpprint.h index 4458ea883b..9284935f96 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -71,4 +71,10 @@ int mp_printf(const mp_print_t *print, const char *fmt, ...); int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args); #endif +struct compressed_string; +int mp_cprintf(const mp_print_t *print, const struct compressed_string *compressed_fmt, ...); +#ifdef va_start +int mp_vcprintf(const mp_print_t *print, const struct compressed_string *compressed_fmt, va_list args); +#endif + #endif // MICROPY_INCLUDED_PY_MPPRINT_H diff --git a/py/obj.c b/py/obj.c index c8a1106a3d..dcf48b81ae 100644 --- a/py/obj.c +++ b/py/obj.c @@ -149,35 +149,27 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { mp_obj_exception_get_traceback(exc, &n, &values); if (n > 0) { assert(n % 3 == 0); - // Decompress the format strings - const compressed_string_t *traceback = MP_ERROR_TEXT("Traceback (most recent call last):\n"); - char decompressed[decompress_length(traceback)]; - decompress(traceback, decompressed); #if MICROPY_ENABLE_SOURCE_LINE const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\", line %d"); #else const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\""); #endif - char decompressed_frame[decompress_length(frame)]; - decompress(frame, decompressed_frame); const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n"); - char decompressed_block[decompress_length(block_fmt)]; - decompress(block_fmt, decompressed_block); // Print the traceback - mp_print_str(print, decompressed); + mp_cprintf(print, MP_ERROR_TEXT("Traceback (most recent call last):\n")); for (int i = n - 3; i >= 0; i -= 3) { #if MICROPY_ENABLE_SOURCE_LINE - mp_printf(print, decompressed_frame, values[i], (int)values[i + 1]); + mp_cprintf(print, frame, values[i], (int)values[i + 1]); #else - mp_printf(print, decompressed_frame, values[i]); + mp_printf(print, frame, values[i]); #endif // the block name can be NULL if it's unknown qstr block = values[i + 2]; if (block == MP_QSTRnull) { mp_print_str(print, "\n"); } else { - mp_printf(print, decompressed_block, block); + mp_cprintf(print, block_fmt, block); } } } diff --git a/py/objexcept.c b/py/objexcept.c index 6488413115..e572225bbc 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -465,12 +465,9 @@ mp_obj_t mp_obj_new_exception_msg_vlist(const mp_obj_type_t *exc_type, const com o_str->data = NULL; } else { // We have some memory to format the string. - // TODO: Optimise this to format-while-decompressing (and not require the temp stack space). struct _exc_printer_t exc_pr = {!used_emg_buf, o_str_alloc, 0, o_str_buf}; mp_print_t print = {&exc_pr, exc_add_strn}; - char fmt_decompressed[decompress_length(fmt)]; - decompress(fmt, fmt_decompressed); - mp_vprintf(&print, fmt_decompressed, ap); + mp_vcprintf(&print, fmt, ap); exc_pr.buf[exc_pr.len] = '\0'; o_str->len = exc_pr.len; o_str->data = exc_pr.buf; diff --git a/shared-module/traceback/__init__.c b/shared-module/traceback/__init__.c index 388b1c18de..11237edb5c 100644 --- a/shared-module/traceback/__init__.c +++ b/shared-module/traceback/__init__.c @@ -35,18 +35,12 @@ void shared_module_traceback_print_exception(mp_obj_exception_t *exc, mp_print_t assert(n % 3 == 0); // Decompress the format strings const compressed_string_t *traceback = MP_ERROR_TEXT("Traceback (most recent call last):\n"); - char decompressed[decompress_length(traceback)]; - decompress(traceback, decompressed); #if MICROPY_ENABLE_SOURCE_LINE const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\", line %d"); #else const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\""); #endif - char decompressed_frame[decompress_length(frame)]; - decompress(frame, decompressed_frame); const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n"); - char decompressed_block[decompress_length(block_fmt)]; - decompress(block_fmt, decompressed_block); // Set traceback formatting // Default: Print full traceback @@ -69,20 +63,20 @@ void shared_module_traceback_print_exception(mp_obj_exception_t *exc, mp_print_t } // Print the traceback - mp_print_str(print, decompressed); + mp_cprintf(print, traceback); for (; i >= limit; i -= 3) { j = (i < 0) ? -i : i; #if MICROPY_ENABLE_SOURCE_LINE - mp_printf(print, decompressed_frame, values[j], (int)values[j + 1]); + mp_cprintf(print, frame, values[j], (int)values[j + 1]); #else - mp_printf(print, decompressed_frame, values[j]); + mp_printf(print, frame, values[j]); #endif // The block name can be NULL if it's unknown qstr block = values[j + 2]; if (block == MP_QSTRnull) { mp_print_str(print, "\n"); } else { - mp_printf(print, decompressed_block, block); + mp_printf(print, block_fmt, block); } } } diff --git a/supervisor/shared/translate.c b/supervisor/shared/translate.c index 4d899ad6d0..a14fa5c728 100644 --- a/supervisor/shared/translate.c +++ b/supervisor/shared/translate.c @@ -35,12 +35,11 @@ #endif #include "py/misc.h" +#include "py/mpprint.h" #include "supervisor/serial.h" void serial_write_compressed(const compressed_string_t *compressed) { - char decompressed[decompress_length(compressed)]; - decompress(compressed, decompressed); - serial_write(decompressed); + mp_printf(MP_PYTHON_PRINTER, "%S", compressed); } STATIC void get_word(int n, const mchar_t **pos, const mchar_t **end) { diff --git a/supervisor/shared/translate.h b/supervisor/shared/translate.h index 26a961a3ed..da58e1eb78 100644 --- a/supervisor/shared/translate.h +++ b/supervisor/shared/translate.h @@ -69,7 +69,7 @@ // flexible array}, but is also future-proofed against strings with // UTF-8 length above 256, with a savings of about 1.375 bytes per // string. -typedef struct { +typedef struct compressed_string { uint8_t data; const uint8_t tail[]; } compressed_string_t; From c1ffab7476d9bdb042eae89abecf46344ee34301 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 8 Aug 2021 10:36:25 -0500 Subject: [PATCH 22/25] Reduce code duplication in traceback module --- py/obj.c | 38 ++++++++++++++++---- py/obj.h | 1 + shared-module/traceback/__init__.c | 58 +----------------------------- 3 files changed, 34 insertions(+), 63 deletions(-) diff --git a/py/obj.c b/py/obj.c index dcf48b81ae..fa3cd0c51c 100644 --- a/py/obj.c +++ b/py/obj.c @@ -143,7 +143,7 @@ void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { } // helper function to print an exception with traceback -void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { +void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit) { if (mp_obj_is_exception_instance(exc) && stack_ok()) { size_t n, *values; mp_obj_exception_get_traceback(exc, &n, &values); @@ -156,16 +156,38 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { #endif const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n"); + // Set traceback formatting + // Default: Print full traceback + limit = limit * 3; + mp_int_t i = n - 3, j; + if (limit > 0) { + // Print upto limit traceback + // entries from caller's frame + if ((unsigned)limit > n) { + limit = n; + } + limit = n - limit; + } else if (limit < 0) { + // Print upto limit traceback + // entries from last + if ((unsigned)-limit > n) { + limit = -n; + } + i = 0, limit = limit + 3; + } + // Print the traceback mp_cprintf(print, MP_ERROR_TEXT("Traceback (most recent call last):\n")); - for (int i = n - 3; i >= 0; i -= 3) { + + for (; i >= limit; i -= 3) { + j = (i < 0) ? -i : i; #if MICROPY_ENABLE_SOURCE_LINE - mp_cprintf(print, frame, values[i], (int)values[i + 1]); + mp_cprintf(print, frame, values[j], (int)values[j + 1]); #else - mp_printf(print, frame, values[i]); + mp_cprintf(print, frame, values[j]); #endif - // the block name can be NULL if it's unknown - qstr block = values[i + 2]; + // The block name can be NULL if it's unknown + qstr block = values[j + 2]; if (block == MP_QSTRnull) { mp_print_str(print, "\n"); } else { @@ -178,6 +200,10 @@ void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { mp_print_str(print, "\n"); } +void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) { + mp_obj_print_exception_with_limit(print, exc, 0); +} + bool PLACE_IN_ITCM(mp_obj_is_true)(mp_obj_t arg) { if (arg == mp_const_false) { return 0; diff --git a/py/obj.h b/py/obj.h index b91932b11e..a043154ada 100644 --- a/py/obj.h +++ b/py/obj.h @@ -888,6 +888,7 @@ mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); +void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit); bool mp_obj_is_true(mp_obj_t arg); bool mp_obj_is_callable(mp_obj_t o_in); diff --git a/shared-module/traceback/__init__.c b/shared-module/traceback/__init__.c index 11237edb5c..a29bd5743f 100644 --- a/shared-module/traceback/__init__.c +++ b/shared-module/traceback/__init__.c @@ -27,61 +27,5 @@ #include "shared-module/traceback/__init__.h" void shared_module_traceback_print_exception(mp_obj_exception_t *exc, mp_print_t *print, mp_int_t limit) { - // Print traceback - if (exc->traceback != NULL) { - size_t n = exc->traceback->len; - size_t *values = exc->traceback->data; - if (n > 0) { - assert(n % 3 == 0); - // Decompress the format strings - const compressed_string_t *traceback = MP_ERROR_TEXT("Traceback (most recent call last):\n"); - #if MICROPY_ENABLE_SOURCE_LINE - const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\", line %d"); - #else - const compressed_string_t *frame = MP_ERROR_TEXT(" File \"%q\""); - #endif - const compressed_string_t *block_fmt = MP_ERROR_TEXT(", in %q\n"); - - // Set traceback formatting - // Default: Print full traceback - limit = limit * 3; - mp_int_t i = n - 3, j; - if (limit > 0) { - // Print upto limit traceback - // entries from caller's frame - if ((unsigned)limit > n) { - limit = n; - } - limit = n - limit; - } else if (limit < 0) { - // Print upto limit traceback - // entries from last - if ((unsigned)-limit > n) { - limit = -n; - } - i = 0, limit = limit + 3; - } - - // Print the traceback - mp_cprintf(print, traceback); - for (; i >= limit; i -= 3) { - j = (i < 0) ? -i : i; - #if MICROPY_ENABLE_SOURCE_LINE - mp_cprintf(print, frame, values[j], (int)values[j + 1]); - #else - mp_printf(print, frame, values[j]); - #endif - // The block name can be NULL if it's unknown - qstr block = values[j + 2]; - if (block == MP_QSTRnull) { - mp_print_str(print, "\n"); - } else { - mp_printf(print, block_fmt, block); - } - } - } - } - // Print exception - mp_obj_print_helper(print, exc, PRINT_EXC); - mp_print_str(print, "\n"); + mp_obj_print_exception_with_limit(print, exc, limit); } From 9a932a5a48487e511461940b3082c7125351c539 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 8 Aug 2021 11:03:03 -0500 Subject: [PATCH 23/25] traceback: Implement format_exception --- locale/circuitpython.pot | 4 -- shared-bindings/traceback/__init__.c | 96 +++++++++++++++++++++------- 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 720f52d40b..c7c4dfd098 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3453,10 +3453,6 @@ msgstr "" msgid "lhs and rhs should be compatible" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "limit should be an int" -msgstr "" - #: py/emitnative.c msgid "local '%q' has type '%q' but source is '%q'" msgstr "" diff --git a/shared-bindings/traceback/__init__.c b/shared-bindings/traceback/__init__.c index d5290559ca..828d6bc28e 100644 --- a/shared-bindings/traceback/__init__.c +++ b/shared-bindings/traceback/__init__.c @@ -38,6 +38,75 @@ //| ... //| +STATIC void traceback_exception_common(mp_print_t *print, mp_obj_t value, mp_obj_t tb_obj, mp_obj_t limit_obj) { + if (!mp_obj_is_exception_instance(value)) { + mp_raise_TypeError(translate("invalid exception")); + } + mp_obj_exception_t exc = *(mp_obj_exception_t *)MP_OBJ_TO_PTR(value); + + mp_int_t limit = 0; + bool print_tb = true; + if (limit_obj != mp_const_none) { + limit = mp_obj_get_int(limit_obj); + print_tb = (limit != 0); + } + + if (tb_obj != mp_const_none && print_tb) { + if (!mp_obj_is_type(tb_obj, &mp_type_traceback)) { + mp_raise_TypeError(translate("invalid traceback")); + } + exc.traceback = MP_OBJ_TO_PTR(tb_obj); + } else { + exc.traceback = NULL; + } + + shared_module_traceback_print_exception(&exc, print, limit); +} + +//| def format_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType, +//| limit: Optional[int] = None, chain: Optional[bool] = True) -> None: +//| """Format a stack trace and the exception information. +//| +//| The arguments have the same meaning as the corresponding arguments +//| to print_exception(). The return value is a list of strings, each +//| ending in a newline and some containing internal newlines. When +//| these lines are concatenated and printed, exactly the same text is +//| printed as does print_exception(). +//| +//| .. note: Setting `chain` will have no effect as chained exceptions are not yet implemented. +//| +//| :param Type[BaseException] etype: This is ignored and inferred from the type of ``value``. +//| :param BaseException value: The exception. Must be an instance of `BaseException`. +//| :param TracebackType tb: The traceback object. If `None`, the traceback will not be printed. +//| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive. +//| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed. +//| :param bool chain: If `True` then chained exceptions will be printed (note: not yet implemented). +//| +//| """ +//| ... +//| +STATIC mp_obj_t traceback_format_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_chain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_etype, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_value, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_tb, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_limit, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_chain, MP_ARG_BOOL, {.u_bool = true} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_print_t print; + vstr_t vstr; + vstr_init_print(&vstr, 0, &print); + traceback_exception_common(&print, args[ARG_value].u_obj, args[ARG_tb].u_obj, args[ARG_limit].u_obj); + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 3, traceback_format_exception); + //| def print_exception(etype: Type[BaseException], value: BaseException, tb: TracebackType, //| limit: Optional[int] = None, file: Optional[io.FileIO] = None, chain: Optional[bool] = True) -> None: //| @@ -57,6 +126,7 @@ //| """ //| ... //| + STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_etype, ARG_value, ARG_tb, ARG_limit, ARG_file, ARG_chain }; static const mp_arg_t allowed_args[] = { @@ -71,11 +141,6 @@ STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_arg mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - if (!mp_obj_is_exception_instance(args[ARG_value].u_obj)) { - mp_raise_TypeError(translate("invalid exception")); - } - mp_obj_exception_t exc = *(mp_obj_exception_t *)MP_OBJ_TO_PTR(args[ARG_value].u_obj); - mp_print_t print = mp_plat_print; if (args[ARG_file].u_obj != mp_const_none) { #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES @@ -87,25 +152,7 @@ STATIC mp_obj_t traceback_print_exception(size_t n_args, const mp_obj_t *pos_arg #endif } - mp_int_t limit = 0; - bool print_tb = true; - if (args[ARG_limit].u_obj != mp_const_none) { - if (!mp_obj_get_int_maybe(args[ARG_limit].u_obj, &limit)) { - mp_raise_TypeError(translate("limit should be an int")); - } - print_tb = (limit != 0); - } - - if (args[ARG_tb].u_obj != mp_const_none && print_tb) { - if (!mp_obj_is_type(args[ARG_tb].u_obj, &mp_type_traceback)) { - mp_raise_TypeError(translate("invalid traceback")); - } - exc.traceback = MP_OBJ_TO_PTR(args[ARG_tb].u_obj); - } else { - exc.traceback = NULL; - } - - shared_module_traceback_print_exception(&exc, &print, limit); + traceback_exception_common(&print, args[ARG_value].u_obj, args[ARG_tb].u_obj, args[ARG_limit].u_obj); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(traceback_print_exception_obj, 3, traceback_print_exception); @@ -114,6 +161,7 @@ STATIC const mp_rom_map_elem_t traceback_module_globals_table[] = { // module name { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_traceback) }, // module functions + { MP_ROM_QSTR(MP_QSTR_format_exception), MP_ROM_PTR(&traceback_format_exception_obj) }, { MP_ROM_QSTR(MP_QSTR_print_exception), MP_ROM_PTR(&traceback_print_exception_obj) }, }; STATIC MP_DEFINE_CONST_DICT(traceback_module_globals, traceback_module_globals_table); From 6764af182a95cce1f106a2cbcbecc3c7d9595f3e Mon Sep 17 00:00:00 2001 From: Eddie Espinal Date: Mon, 9 Aug 2021 11:31:20 -0400 Subject: [PATCH 24/25] Fixes the MOSI and MISO pins. By mistake I added them backward in this mapping --- ports/esp32s2/boards/atmegazero_esp32s2/pins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/esp32s2/boards/atmegazero_esp32s2/pins.c b/ports/esp32s2/boards/atmegazero_esp32s2/pins.c index cfc4ef6223..96dd940985 100644 --- a/ports/esp32s2/boards/atmegazero_esp32s2/pins.c +++ b/ports/esp32s2/boards/atmegazero_esp32s2/pins.c @@ -64,9 +64,9 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_DAC1), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_DAC2), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO35) }, { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO40) }, From 32ee06b293b2ff2d619835bf4b9c25f0ec09d36e Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Mon, 9 Aug 2021 22:53:23 +0530 Subject: [PATCH 25/25] fix crash when traceback object is supplied --- shared-bindings/traceback/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/traceback/__init__.c b/shared-bindings/traceback/__init__.c index 828d6bc28e..dc5be20a88 100644 --- a/shared-bindings/traceback/__init__.c +++ b/shared-bindings/traceback/__init__.c @@ -57,7 +57,7 @@ STATIC void traceback_exception_common(mp_print_t *print, mp_obj_t value, mp_obj } exc.traceback = MP_OBJ_TO_PTR(tb_obj); } else { - exc.traceback = NULL; + exc.traceback = (mp_obj_traceback_t *)&mp_const_empty_traceback_obj; } shared_module_traceback_print_exception(&exc, print, limit);