summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2021-03-12 16:50:39 -0800
committerGitHub <noreply@github.com>2021-03-12 16:50:39 -0800
commitb413535ee14a5e7ce15eba816d3d985de3dbc6c2 (patch)
tree10c0fcc106eaccf8f67cbcf98d5461d9d8deaa7b
parent1b106de4e0d3227c427c9086ab5215566a7b211d (diff)
parenta9afa0d9d4c66cda8fe7e6c1a72765e704e94985 (diff)
Merge pull request #4376 from kmatch98/displayio_bitmap
add fill_region and draw_line to bitmap_tools
-rw-r--r--locale/circuitpython.pot2
-rw-r--r--shared-bindings/bitmaptools/__init__.c116
-rw-r--r--shared-bindings/bitmaptools/__init__.h10
-rw-r--r--shared-module/bitmaptools/__init__.c164
-rw-r--r--shared-module/displayio/Bitmap.h2
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