diff options
| author | warriorofwire <3454741+WarriorOfWire@users.noreply.github.com> | 2020-05-02 02:21:35 -0700 |
|---|---|---|
| committer | warriorofwire <3454741+WarriorOfWire@users.noreply.github.com> | 2020-05-09 15:38:22 -0700 |
| commit | 206d0e598adb66e2b23a39a7d11e2f5087513205 (patch) | |
| tree | cea5a2e50ec96edd8b4c0bfc09e0d9570694a2ee /shared-bindings/vectorio | |
| parent | 90bd931808fa797938b723e8d30889ec4a0f1654 (diff) | |
Add vectorio: for drawing shapes
vectorio builds on m4 express feather
Concrete shapes are composed into a VectorShape which is put into a displayio Group for display.
VectorShape provides transpose and x/y positioning for shape implementations.
Included Shapes:
* Circle
- A radius; Circle is positioned at its axis in the VectorShape.
- You can freely modify the radius to grow and shrink the circle in-place.
* Polygon
- An ordered list of points.
- Beteween each successive point an edge is inferred. A final edge closing the shape is inferred between the last
point and the first point.
- You can modify the points in a Polygon. The points' coordinate system is relative to (0, 0) so if you'd like a
top-center justified 10x20 rectangle you can do points [(-5, 0), (5, 0), (5, 20), (0, 20)] and your VectorShape
x and y properties will position the rectangle relative to its top center point
* Rectangle
A width and a height.
Diffstat (limited to 'shared-bindings/vectorio')
| -rw-r--r-- | shared-bindings/vectorio/Circle.c | 79 | ||||
| -rw-r--r-- | shared-bindings/vectorio/Circle.h | 22 | ||||
| -rw-r--r-- | shared-bindings/vectorio/Polygon.c | 139 | ||||
| -rw-r--r-- | shared-bindings/vectorio/Polygon.h | 24 | ||||
| -rw-r--r-- | shared-bindings/vectorio/Rectangle.c | 56 | ||||
| -rw-r--r-- | shared-bindings/vectorio/Rectangle.h | 15 | ||||
| -rw-r--r-- | shared-bindings/vectorio/VectorShape.c | 213 | ||||
| -rw-r--r-- | shared-bindings/vectorio/VectorShape.h | 25 | ||||
| -rw-r--r-- | shared-bindings/vectorio/__init__.c | 46 |
9 files changed, 619 insertions, 0 deletions
diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c new file mode 100644 index 000000000..8f409bd65 --- /dev/null +++ b/shared-bindings/vectorio/Circle.c @@ -0,0 +1,79 @@ + +#include "shared-bindings/vectorio/Circle.h" + + +#include <stdint.h> + +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| .. currentmodule:: vectorio +//| +//| :class:`Circle` -- Represents a circle by its radius +//| ========================================================================== +//| +//| .. class:: Circle(radius) +//| +//| :param int radius: The radius of the circle in pixels +//| +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 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + 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_int_t radius = args[ARG_radius].u_int; + if (radius < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_radius); + } + + vectorio_circle_t *self = m_new_obj(vectorio_circle_t); + self->base.type = &vectorio_circle_type; + common_hal_vectorio_circle_construct(self, radius); + + return MP_OBJ_FROM_PTR(self); +} + + +//| .. attribute:: radius +//| +//| Update the radius of the circle +//| +STATIC mp_obj_t vectorio_circle_obj_get_radius(mp_obj_t self_in) { + vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(common_hal_vectorio_circle_get_radius(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(vectorio_circle_get_radius_obj, vectorio_circle_obj_get_radius); + +STATIC mp_obj_t vectorio_circle_obj_set_radius(mp_obj_t self_in, mp_obj_t radius) { + vectorio_circle_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_vectorio_circle_set_radius(self, mp_obj_get_int(radius)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_circle_set_radius_obj, vectorio_circle_obj_set_radius); + +const mp_obj_property_t vectorio_circle_radius_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_circle_get_radius_obj, + (mp_obj_t)&vectorio_circle_set_radius_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +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) }, +}; +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, + .make_new = vectorio_circle_make_new, + .locals_dict = (mp_obj_dict_t*)&vectorio_circle_locals_dict, +}; + diff --git a/shared-bindings/vectorio/Circle.h b/shared-bindings/vectorio/Circle.h new file mode 100644 index 000000000..e8fc048eb --- /dev/null +++ b/shared-bindings/vectorio/Circle.h @@ -0,0 +1,22 @@ +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H + +#include "shared-module/vectorio/__init__.h" +#include "shared-module/vectorio/Circle.h" +#include "shared-module/displayio/area.h" + +extern const mp_obj_type_t vectorio_circle_type; + +void common_hal_vectorio_circle_construct(vectorio_circle_t *self, uint16_t radius); + +void common_hal_vectorio_circle_set_on_dirty(vectorio_circle_t *self, vectorio_event_t notification); + +uint32_t common_hal_vectorio_circle_get_pixel(void *circle, int16_t x, int16_t y); + +void common_hal_vectorio_circle_get_area(void *circle, displayio_area_t *out_area); + + +int16_t common_hal_vectorio_circle_get_radius(void *circle); +void common_hal_vectorio_circle_set_radius(void *circle, int16_t radius); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_CIRCLE_H diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c new file mode 100644 index 000000000..b8bb377ac --- /dev/null +++ b/shared-bindings/vectorio/Polygon.c @@ -0,0 +1,139 @@ + +#include "shared-module/vectorio/__init__.h" +#include "shared-bindings/vectorio/Polygon.h" + +#include <stdint.h> + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +#define VECTORIO_POLYGON_DEBUG(...) (void)0 +// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) + + +// Converts a list of points tuples to a flat list of ints for speedier internal use. +// Also validates the points. +static mp_obj_t _to_points_list(mp_obj_t points_tuple_list) { + size_t len = 0; + mp_obj_t *items; + mp_obj_list_get(points_tuple_list, &len, &items); + VECTORIO_POLYGON_DEBUG("polygon_points_list len: %d\n", len); + + if ( len == 0 ) { + mp_raise_TypeError_varg(translate("empty %q list"), MP_QSTR_point); + } + + mp_obj_t points_list = mp_obj_new_list(0, NULL); + + for ( size_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); + + if (tuple_len != 2) { + mp_raise_ValueError_varg(translate("%q must be a tuple of length 2"), MP_QSTR_point); + } + int value; + if (!mp_obj_get_int_maybe(tuple_items[0], &value)) { + mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point); + } + mp_obj_list_append(points_list, MP_OBJ_NEW_SMALL_INT(value)); + if (!mp_obj_get_int_maybe(tuple_items[1], &value)) { + mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point); + } + mp_obj_list_append(points_list, MP_OBJ_NEW_SMALL_INT(value)); + } + return points_list; +} + + + +//| .. currentmodule:: vectorio +//| +//| :class:`Polygon` -- Represents a closed shape by ordered vertices +//| ========================================================================== +//| +//| .. class:: Polygon( List[ Tuple[ x, y ], ... ] ) +//| +//| :param [Point] points_array: Vertices for the polygon +//| +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 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + 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_TYPE(args[ARG_points_list].u_obj, &mp_type_list)) { + mp_raise_TypeError_varg(translate("%q list must be a list"), MP_QSTR_point); + } + mp_obj_t points_list = _to_points_list(args[ARG_points_list].u_obj); + + vectorio_polygon_t *self = m_new_obj(vectorio_polygon_t); + self->base.type = &vectorio_polygon_type; + + common_hal_vectorio_polygon_construct(self, points_list); + + return MP_OBJ_FROM_PTR(self); +} + + +//| .. attribute:: points +//| +//| Set a new look and shape for this polygon +//| +STATIC mp_obj_t vectorio_polygon_obj_get_points(mp_obj_t self_in) { + vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t list = mp_obj_new_list(0, NULL); + + size_t len = 0; + mp_obj_t *items; + mp_obj_list_get(common_hal_vectorio_polygon_get_points(self), &len, &items); + + for (size_t i = 0; i < len; i += 2) { + mp_obj_t tuple[] = { items[i], items[i+1] }; + mp_obj_list_append( + list, + mp_obj_new_tuple(2, tuple) + ); + } + return list; +} +MP_DEFINE_CONST_FUN_OBJ_1(vectorio_polygon_get_points_obj, vectorio_polygon_obj_get_points); + +STATIC mp_obj_t vectorio_polygon_obj_set_points(mp_obj_t self_in, mp_obj_t points) { + vectorio_polygon_t *self = MP_OBJ_TO_PTR(self_in); + + mp_obj_t points_list = _to_points_list(points); + + common_hal_vectorio_polygon_set_points(self, points_list); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_polygon_set_points_obj, vectorio_polygon_obj_set_points); + +const mp_obj_property_t vectorio_polygon_points_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_polygon_get_points_obj, + (mp_obj_t)&vectorio_polygon_set_points_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + + +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) }, +}; +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, + .make_new = vectorio_polygon_make_new, + .locals_dict = (mp_obj_dict_t*)&vectorio_polygon_locals_dict, +}; + diff --git a/shared-bindings/vectorio/Polygon.h b/shared-bindings/vectorio/Polygon.h new file mode 100644 index 000000000..5594fbec4 --- /dev/null +++ b/shared-bindings/vectorio/Polygon.h @@ -0,0 +1,24 @@ +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H + +#include "shared-module/vectorio/Polygon.h" +#include "shared-module/displayio/area.h" +#include "shared-module/vectorio/__init__.h" + +extern const mp_obj_type_t vectorio_polygon_type; + +void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list); +void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio_event_t notification); + + +uint32_t common_hal_vectorio_polygon_get_pixel(void *polygon, int16_t x, int16_t y); + +void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *out_area); + + + +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); + + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_POLYGON_H diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c new file mode 100644 index 000000000..ea468f788 --- /dev/null +++ b/shared-bindings/vectorio/Rectangle.c @@ -0,0 +1,56 @@ + +#include "shared-bindings/vectorio/Rectangle.h" + +#include <stdint.h> + +#include "py/objtype.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| .. currentmodule:: vectorio +//| +//| :class:`Rectangle` -- Represents a rectangle by defining its bounds +//| ========================================================================== +//| +//| .. class:: Rectangle(width, height) +//| +//| :param int width: The number of pixels wide +//| :param int height: The number of pixels high +//| +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 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + 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_int_t width = args[ARG_width].u_int; + if (width < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_width); + } + mp_int_t height = args[ARG_height].u_int; + if (height < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_height); + } + + vectorio_rectangle_t *self = m_new_obj(vectorio_rectangle_t); + self->base.type = &vectorio_rectangle_type; + common_hal_vectorio_rectangle_construct(self, width, height); + + return MP_OBJ_FROM_PTR(self); +} + + +STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = { +}; +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, + .make_new = vectorio_rectangle_make_new, + .locals_dict = (mp_obj_dict_t*)&vectorio_rectangle_locals_dict, +}; diff --git a/shared-bindings/vectorio/Rectangle.h b/shared-bindings/vectorio/Rectangle.h new file mode 100644 index 000000000..bb461ed9d --- /dev/null +++ b/shared-bindings/vectorio/Rectangle.h @@ -0,0 +1,15 @@ +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H + +#include "shared-module/vectorio/Rectangle.h" +#include "shared-module/displayio/area.h" + +extern const mp_obj_type_t vectorio_rectangle_type; + +void common_hal_vectorio_rectangle_construct(vectorio_rectangle_t *self, uint32_t width, uint32_t height); + +uint32_t common_hal_vectorio_rectangle_get_pixel(void *rectangle, int16_t x, int16_t y); + +void common_hal_vectorio_rectangle_get_area(void *rectangle, displayio_area_t *out_area); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_RECTANGLE_H diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c new file mode 100644 index 000000000..8f99577b4 --- /dev/null +++ b/shared-bindings/vectorio/VectorShape.c @@ -0,0 +1,213 @@ + +#include "shared-module/vectorio/__init__.h" +#include "shared-bindings/vectorio/VectorShape.h" +#include "shared-bindings/vectorio/Circle.h" +#include "shared-bindings/vectorio/Polygon.h" +#include "shared-bindings/vectorio/Rectangle.h" + +#include "shared-bindings/displayio/ColorConverter.h" +#include "shared-bindings/displayio/Palette.h" + +#include <stdint.h> + +#include "lib/utils/context_manager_helpers.h" + +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| .. currentmodule:: vectorio +//| +//| :class:`VectorShape` -- Binds a vector shape to a location and pixel color +//| ========================================================================== +//| +//| .. class:: VectorShape( shape, pixel_shader, x=0, y=0) +//| +//| :param vectorio.Polygon shape: The shape to draw. +//| :param displayio.Palette pixel_shader: The pixel shader that produces colors from values +//| :param int x: Initial x position of the center axis of the shape within the parent. +//| :param int 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, ARG_transpose_xy }; + 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_QSTR_transpose_xy, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + 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; + 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)) { + ishape.shape = shape; + ishape.get_area = &common_hal_vectorio_polygon_get_area; + ishape.get_pixel = &common_hal_vectorio_polygon_get_pixel; + } else if (MP_OBJ_IS_TYPE(shape, &vectorio_rectangle_type)) { + ishape.shape = shape; + ishape.get_area = &common_hal_vectorio_rectangle_get_area; + ishape.get_pixel = &common_hal_vectorio_rectangle_get_pixel; + } else if (MP_OBJ_IS_TYPE(shape, &vectorio_circle_type)) { + ishape.shape = shape; + ishape.get_area = &common_hal_vectorio_circle_get_area; + ishape.get_pixel = &common_hal_vectorio_circle_get_pixel; + } else { + mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_shape); + } + + vectorio_vector_shape_t *self = m_new_obj(vectorio_vector_shape_t); + self->base.type = &vectorio_vector_shape_type; + common_hal_vectorio_vector_shape_construct(self, + ishape, pixel_shader, x, y, args[ARG_transpose_xy].u_bool + ); + + // Wire up event callbacks + vectorio_event_t on_dirty = { + .obj = self, + .event = &common_hal_vectorio_vector_shape_set_dirty + }; + + if (MP_OBJ_IS_TYPE(shape, &vectorio_polygon_type)) { + common_hal_vectorio_polygon_set_on_dirty(self->ishape.shape, on_dirty); + } else if (MP_OBJ_IS_TYPE(shape, &vectorio_rectangle_type)) { + common_hal_vectorio_circle_set_on_dirty(self->ishape.shape, on_dirty); + } else if (MP_OBJ_IS_TYPE(shape, &vectorio_circle_type)) { + } else { + mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_shape); + } + + return MP_OBJ_FROM_PTR(self); +} + + +//| .. attribute:: x +//| +//| 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); + 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); + + mp_int_t x = mp_obj_get_int(x_obj); + common_hal_vectorio_vector_shape_set_x(self, x); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_x_obj, vectorio_vector_shape_obj_set_x); + +const mp_obj_property_t vectorio_vector_shape_x_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_vector_shape_get_x_obj, + (mp_obj_t)&vectorio_vector_shape_set_x_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| .. attribute:: y +//| +//| 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); + 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); + + mp_int_t y = mp_obj_get_int(y_obj); + common_hal_vectorio_vector_shape_set_y(self, y); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_y_obj, vectorio_vector_shape_obj_set_y); + +const mp_obj_property_t vectorio_vector_shape_y_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_vector_shape_get_y_obj, + (mp_obj_t)&vectorio_vector_shape_set_y_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| .. attribute:: transpose_xy +//| +//| true if the object is to be flipped. +//| +STATIC mp_obj_t vectorio_vector_shape_obj_get_transpose_xy(mp_obj_t self_in) { + vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_vectorio_vector_shape_get_transpose_xy(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(vectorio_vector_shape_get_transpose_xy_obj, vectorio_vector_shape_obj_get_transpose_xy); + +const mp_obj_property_t vectorio_vector_shape_transpose_xy_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_vector_shape_get_transpose_xy_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: pixel_shader +//| +//| 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); + 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); + 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")); + } + + common_hal_vectorio_vector_shape_set_pixel_shader(self, pixel_shader); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(vectorio_vector_shape_set_pixel_shader_obj, vectorio_vector_shape_obj_set_pixel_shader); + +const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&vectorio_vector_shape_get_pixel_shader_obj, + (mp_obj_t)&vectorio_vector_shape_set_pixel_shader_obj, + (mp_obj_t)&mp_const_none_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 new file mode 100644 index 000000000..ad745b30f --- /dev/null +++ b/shared-bindings/vectorio/VectorShape.h @@ -0,0 +1,25 @@ +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H + +#include "shared-module/vectorio/VectorShape.h" + +extern const mp_obj_type_t vectorio_vector_shape_type; + +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, bool transpose_xy); + +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_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); + +bool common_hal_vectorio_vector_shape_get_transpose_xy(vectorio_vector_shape_t *self); + +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); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H diff --git a/shared-bindings/vectorio/__init__.c b/shared-bindings/vectorio/__init__.c new file mode 100644 index 000000000..b9e3828bd --- /dev/null +++ b/shared-bindings/vectorio/__init__.c @@ -0,0 +1,46 @@ +#include <stdint.h> + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/vectorio/Circle.h" +#include "shared-bindings/vectorio/Polygon.h" +#include "shared-bindings/vectorio/Rectangle.h" +#include "shared-bindings/vectorio/VectorShape.h" + +//| :mod:`vectorio` --- Lightweight 2d shapes for displays +//| ========================================================================= +//| +//| .. module:: vectorio +//| :synopsis: Adds vector graphics to displayio +//| :platform: SAMD21, SAMD51, nRF52 +//| +//| The `vectorio` module contains classes to construct shapes +//| by describing their points rather than providing them in bitmaps. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Circle +//| Polygon +//| Rectangle +//| VectorShape +//| + + +STATIC const mp_rom_map_elem_t vectorio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_vectorio) }, + { 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); + +const mp_obj_module_t vectorio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&vectorio_module_globals, +}; |
