diff options
| -rw-r--r-- | locale/circuitpython.pot | 2 | ||||
| -rw-r--r-- | shared-bindings/bitmaptools/__init__.c | 116 | ||||
| -rw-r--r-- | shared-bindings/bitmaptools/__init__.h | 10 | ||||
| -rw-r--r-- | shared-module/bitmaptools/__init__.c | 164 | ||||
| -rw-r--r-- | shared-module/displayio/Bitmap.h | 2 |
5 files changed, 292 insertions, 2 deletions
diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index afff80687..2f15d70b1 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3643,7 +3643,7 @@ msgstr "" msgid "out of range of source" msgstr "" -#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c msgid "out of range of target" msgstr "" diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index cf48d12dc..118564ff8 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -243,13 +243,127 @@ STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom); // requires at least 2 arguments (destination bitmap and source bitmap) +//| +//| def fill_region( +//| dest_bitmap: displayio.Bitmap, +//| x1: int, y1: int, +//| x2: int, y2: int, +//| value: int) -> None: +//| """Draws the color value into the destination bitmap within the +//| rectangular region bounded by (x1,y1) and (x2,y2), exclusive. +//| +//| :param bitmap dest_bitmap: Destination bitmap that will be written into +//| :param int x1: x-pixel position of the first corner of the rectangular fill region +//| :param int y1: y-pixel position of the first corner of the rectangular fill region +//| :param int x2: x-pixel position of the second corner of the rectangular fill region (exclusive) +//| :param int y2: y-pixel position of the second corner of the rectangular fill region (exclusive) +//| :param int value: Bitmap palette index that will be written into the rectangular +//| fill region in the destination bitmap""" +//| ... +//| +STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ + enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value}; + + static const mp_arg_t allowed_args[] = { + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_value, 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); + + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + + uint32_t value, color_depth; + value = args[ARG_value].u_int; + color_depth = (1 << destination->bits_per_value); + if (color_depth <= value) { + mp_raise_ValueError(translate("out of range of target")); + } + + int16_t x1 = args[ARG_x1].u_int; + int16_t y1 = args[ARG_y1].u_int; + int16_t x2 = args[ARG_x2].u_int; + int16_t y2 = args[ARG_y2].u_int; + + common_hal_bitmaptools_fill_region(destination, x1, y1, x2, y2, value); + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_fill_region_obj, 0, bitmaptools_obj_fill_region); +// requires all 6 arguments + +//| +//| def draw_line( +//| dest_bitmap: displayio.Bitmap, +//| x1: int, y1: int, +//| x2: int, y2: int, +//| value: int) -> None: +//| """Draws a line into a bitmap specified two endpoints (x1,y1) and (x2,y2). +//| +//| :param bitmap dest_bitmap: Destination bitmap that will be written into +//| :param int x1: x-pixel position of the line's first endpoint +//| :param int y1: y-pixel position of the line's first endpoint +//| :param int x2: x-pixel position of the line's second endpoint +//| :param int y2: y-pixel position of the line's second endpoint +//| :param int value: Bitmap palette index that will be written into the +//| line in the destination bitmap""" +//| ... +//| +STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ + enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value}; + + static const mp_arg_t allowed_args[] = { + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_value, 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); + + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + + uint32_t value, color_depth; + value = args[ARG_value].u_int; + color_depth = (1 << destination->bits_per_value); + if (color_depth <= value) { + mp_raise_ValueError(translate("out of range of target")); + } + + int16_t x1 = args[ARG_x1].u_int; + int16_t y1 = args[ARG_y1].u_int; + int16_t x2 = args[ARG_x2].u_int; + int16_t y2 = args[ARG_y2].u_int; + + // verify points are within the bitmap boundary (inclusive) + if ( (x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0) || + (x1 >= destination->width) || (x2 >= destination->width) || + (y1 >= destination->height) || (y2 >= destination->height) ) { + mp_raise_ValueError(translate("out of range of target")); + } + + common_hal_bitmaptools_draw_line(destination, x1, y1, x2, y2, value); + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_line_obj, 0, bitmaptools_obj_draw_line); +// requires all 6 arguments STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) }, + { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table); - const mp_obj_module_t bitmaptools_module = { .base = {&mp_type_module }, .globals = (mp_obj_dict_t*)&bitmaptools_module_globals, diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h index e2bb6938b..1ab6e4129 100644 --- a/shared-bindings/bitmaptools/__init__.h +++ b/shared-bindings/bitmaptools/__init__.h @@ -39,4 +39,14 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16 float scale, uint32_t skip_index, bool skip_index_none); +void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, + int16_t x1, int16_t y1, + int16_t x2, int16_t y2, + uint32_t value); + +void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination, + int16_t x0, int16_t y0, + int16_t x1, int16_t y1, + uint32_t value); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index 7dc4024ef..6f168b555 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -26,10 +26,12 @@ #include "shared-bindings/displayio/Bitmap.h" +#include "shared-module/displayio/Bitmap.h" #include "py/runtime.h" #include "math.h" +#include "stdlib.h" void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy, int16_t dest_clip0_x, int16_t dest_clip0_y, @@ -172,3 +174,165 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16 rowv += dvCol; } } + +int16_t constrain(int16_t input, int16_t min, int16_t max) { + // constrain the input between the min and max values + if (input < min) { + return min; + } + if (input > max) { + return max; + } + return input; +} + +void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, + int16_t x1, int16_t y1, + int16_t x2, int16_t y2, + uint32_t value) { + // writes the value (a bitmap color index) into a bitmap in the specified rectangular region + // + // input checks should ensure that x1 < x2 and y1 < y2 and are within the bitmap region + + if (destination->read_only) { + mp_raise_RuntimeError(translate("Read-only object")); + } + + // Ensure x1 < x2 and y1 < y2 + if (x1 > x2) { + int16_t temp=x2; + x2=x1; + x1=temp; + } + if (y1 > y2) { + int16_t temp=y2; + y2=y1; + y1=temp; + } + + // constrain to bitmap dimensions + x1 = constrain(x1, 0, destination->width); + x2 = constrain(x2, 0, destination->width); + y1 = constrain(y1, 0, destination->height); + y2 = constrain(y2, 0, destination->height); + + // update the dirty rectangle + displayio_bitmap_set_dirty_area(destination, x1, y1, x2, y2); + + int16_t x, y; + for (x = x1; x < x2; x++) { + for (y = y1; y < y2; y++ ) { + displayio_bitmap_write_pixel(destination, x, y, value); + } + } +} + +void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination, + int16_t x0, int16_t y0, + int16_t x1, int16_t y1, + uint32_t value) { + + if (destination->read_only) { + mp_raise_RuntimeError(translate("Read-only object")); + } + + // + // adapted from Adafruit_CircuitPython_Display_Shapes.Polygon._line + // + + // update the dirty rectangle + int16_t xbb0, xbb1, ybb0, ybb1; + if (x0 < x1) { + xbb0 = x0; + xbb1 = x1 + 1; + } else { + xbb0 = x1; + xbb1 = x0 + 1; + } + if (y0 < y1) { + ybb0 = y0; + ybb1 = y1 + 1; + } else { + ybb0 = y1; + ybb1 = y0 + 1; + } + + xbb0 = constrain(xbb0, 0, destination->width); + xbb1 = constrain(xbb1, 0, destination->width); + ybb0 = constrain(ybb0, 0, destination->height); + ybb1 = constrain(ybb1, 0, destination->height); + + displayio_bitmap_set_dirty_area(destination, xbb0, ybb0, xbb1, ybb1); + + int16_t temp, x, y; + + if (x0 == x1) { // vertical line + if (y0 > y1) { // ensure y1 > y0 + temp = y0; + y0 = y1; + y1 = temp; + } + for (y = y0; y < (y1 + 1); y++) { // write a horizontal line + displayio_bitmap_write_pixel(destination, x0, y, value); + } + } + else if (y0 == y1) { // horizontal line + if (x0 > x1) { // ensure y1 > y0 + temp = x0; + x0 = x1; + x1 = temp; + } + for (x = x0; x < (x1 + 1); x++) { // write a horizontal line + displayio_bitmap_write_pixel(destination, x, y0, value); + } + } + else { + bool steep; + steep = ( abs(y1 - y0) > abs(x1 - x0) ); + + if ( steep ) { // flip x0<->y0 and x1<->y1 + temp = x0; + x0 = y0; + y0 = temp; + temp = x1; + x1 = y1; + y1 = temp; + } + + if (x0 > x1) { // flip x0<->x1 and y0<->y1 + temp = x0; + x0 = x1; + x1 = temp; + temp = y0; + y0 = y1; + y1 = temp; + } + + int16_t dx, dy, ystep; + dx = x1 - x0; + dy = abs(y1 - y0); + + float err = dx / 2; + + if (y0 < y1) { + ystep = 1; + } + else { + ystep = -1; + } + + for (x = x0; x < (x1 + 1); x++) { + if (steep) { + displayio_bitmap_write_pixel(destination, y0, x, value); + } + else { + displayio_bitmap_write_pixel(destination, x, y0, value); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } + } +} diff --git a/shared-module/displayio/Bitmap.h b/shared-module/displayio/Bitmap.h index f4bd7ce4d..d6aaaa8ba 100644 --- a/shared-module/displayio/Bitmap.h +++ b/shared-module/displayio/Bitmap.h @@ -49,5 +49,7 @@ typedef struct { void displayio_bitmap_finish_refresh(displayio_bitmap_t *self); displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail); +void displayio_bitmap_set_dirty_area(displayio_bitmap_t *self, int16_t x1, int16_t y1, int16_t x2, int16_t y2); +void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value); #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H |
