From 11159004438d4530efebf56c778b18bb3705983e Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 22 Jul 2024 17:33:52 +0100 Subject: [PATCH] PicoVector: Rewrite around new linked-lists poly. --- .../pico_graphics_pen_rgb332.cpp | 21 +- .../pico_graphics_pen_rgb565.cpp | 14 +- libraries/pico_vector/alright-fonts.h | 27 +-- libraries/pico_vector/pico_vector.cpp | 8 +- libraries/pico_vector/pico_vector.hpp | 14 +- libraries/pico_vector/pretty-poly.h | 182 +++++++++++++----- micropython/modules/picovector/picovector.cpp | 93 +++++---- 7 files changed, 236 insertions(+), 123 deletions(-) diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index cdb24da2..88fceba7 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -151,11 +151,28 @@ namespace pimoroni { uint8_t *pdest = &((uint8_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)]; for(int x = 0; x < tile->w; x++) { uint8_t alpha = *palpha; + uint8_t dest = *pdest; // TODO: Try to alpha blend RGB332... somewhat? - if(alpha == 0) { - } else { + if(alpha == 255) { *pdest = color; + }else if(alpha == 0) { + }else{ + // blend tha pixel + uint16_t sr = (color & 0b11100000) >> 5; + uint16_t sg = (color & 0b00011100) >> 2; + uint16_t sb = (color & 0b00000011); + + uint16_t dr = (dest & 0b11100000) >> 5; + uint16_t dg = (dest & 0b00011100) >> 2; + uint16_t db = (dest & 0b00000011); + + uint8_t r = ((sr * alpha) + (dr * (255 - alpha))) >> 8; + uint8_t g = ((sg * alpha) + (dg * (255 - alpha))) >> 8; + uint8_t b = ((sb * alpha) + (db * (255 - alpha))) >> 8; + + // recombine the channels + *pdest = (r << 5) | (g << 2) | (b); } pdest++; diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp index 6cf2d863..5e9d5f67 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp @@ -107,20 +107,20 @@ namespace pimoroni { }else if(alpha == 0) { }else{ // blend tha pixel - uint16_t sr = (color & 0b1111100000000000) >> 11; - uint16_t sg = (color & 0b0000011111100000) >> 5; - uint16_t sb = (color & 0b0000000000011111); + uint16_t sr = (__builtin_bswap16(color) & 0b1111100000000000) >> 11; + uint16_t sg = (__builtin_bswap16(color) & 0b0000011111100000) >> 5; + uint16_t sb = (__builtin_bswap16(color) & 0b0000000000011111); - uint16_t dr = (dest & 0b1111100000000000) >> 11; - uint16_t dg = (dest & 0b0000011111100000) >> 5; - uint16_t db = (dest & 0b0000000000011111); + uint16_t dr = (__builtin_bswap16(dest) & 0b1111100000000000) >> 11; + uint16_t dg = (__builtin_bswap16(dest) & 0b0000011111100000) >> 5; + uint16_t db = (__builtin_bswap16(dest) & 0b0000000000011111); uint8_t r = ((sr * alpha) + (dr * (255 - alpha))) >> 8; uint8_t g = ((sg * alpha) + (dg * (255 - alpha))) >> 8; uint8_t b = ((sb * alpha) + (db * (255 - alpha))) >> 8; // recombine the channels - *pdest = (r << 11) | (g << 5) | (b); + *pdest = __builtin_bswap16((r << 11) | (g << 5) | (b)); } pdest++; diff --git a/libraries/pico_vector/alright-fonts.h b/libraries/pico_vector/alright-fonts.h index e598764b..9e5a6ce9 100644 --- a/libraries/pico_vector/alright-fonts.h +++ b/libraries/pico_vector/alright-fonts.h @@ -216,27 +216,20 @@ af_glyph_t *find_glyph(af_face_t *face, char c) { void af_render_glyph(af_glyph_t* glyph, af_text_metrics_t *tm) { assert(glyph != NULL); - pp_poly_t poly; - poly.count = glyph->path_count; - poly.paths = (pp_path_t *)AF_MALLOC(poly.count * sizeof(pp_path_t)); - for(uint32_t i = 0; i < poly.count; i++) { - pp_path_t *path = &poly.paths[i]; - path->count = glyph->paths[i].point_count; - path->points = (pp_point_t *)AF_MALLOC(glyph->paths[i].point_count * sizeof(pp_point_t)); - for(uint32_t j = 0; j < path->count; j++) { - pp_point_t *point = &path->points[j]; - point->x = glyph->paths[i].points[j].x; - point->y = glyph->paths[i].points[j].y; + pp_poly_t *poly = pp_poly_new(); + for(uint32_t i = 0; i < glyph->path_count; i++) { + pp_path_t *path = pp_poly_add_path(poly); + for(uint32_t j = 0; j < glyph->paths[i].point_count; j++) { + pp_path_add_point(path, { + glyph->paths[i].points[j].x, + glyph->paths[i].points[j].y + }); } } - pp_render(&poly); + pp_render(poly); - for(uint32_t i = 0; i < poly.count; i++) { - pp_path_t *path = &poly.paths[i]; - AF_FREE(path->points); - } - AF_FREE(poly.paths); + pp_poly_free(poly); } void af_render_character(af_face_t *face, const char c, af_text_metrics_t *tm) { diff --git a/libraries/pico_vector/pico_vector.cpp b/libraries/pico_vector/pico_vector.cpp index 9c20f073..a3cb6bfc 100644 --- a/libraries/pico_vector/pico_vector.cpp +++ b/libraries/pico_vector/pico_vector.cpp @@ -31,7 +31,7 @@ namespace pimoroni { } void PicoVector::transform(pp_path_t *path, pp_mat3_t *t) { - for (auto j = 0u; j < path->count; j++) { + for (auto j = 0; j < path->count; j++) { path->points[j] = pp_point_transform(&path->points[j], t); } } @@ -51,8 +51,10 @@ namespace pimoroni { } void PicoVector::transform(pp_poly_t *poly, pp_mat3_t *t) { - for (auto i = 0u; i < poly->count; i++) { - transform(&poly->paths[i], t); + pp_path_t *path = poly->paths; + while(path) { + transform(path, t); + path = path->next; } } diff --git a/libraries/pico_vector/pico_vector.hpp b/libraries/pico_vector/pico_vector.hpp index 1bcaf340..db0a3412 100644 --- a/libraries/pico_vector/pico_vector.hpp +++ b/libraries/pico_vector/pico_vector.hpp @@ -109,13 +109,19 @@ namespace pimoroni { void draw(pp_poly_t *poly, pp_mat3_t *t); void draw(pp_path_t *path) { - pp_poly_t poly = {.paths = path, .count = 1}; - draw(&poly); + pp_poly_t *poly = pp_poly_new(); + poly->paths = path; + draw(poly); + poly->paths = NULL; // Don't free our non-owned path + pp_poly_free(poly); }; void draw(pp_path_t *path, pp_mat3_t *t) { - pp_poly_t poly = {.paths = path, .count = 1}; - draw(&poly, t); + pp_poly_t *poly = pp_poly_new(); + poly->paths = path; + draw(poly, t); + poly->paths = NULL; // Don't free our non-owned path + pp_poly_free(poly); }; static constexpr size_t pretty_poly_buffer_size() { diff --git a/libraries/pico_vector/pretty-poly.h b/libraries/pico_vector/pretty-poly.h index c7a7c10e..9c746837 100644 --- a/libraries/pico_vector/pretty-poly.h +++ b/libraries/pico_vector/pretty-poly.h @@ -100,15 +100,26 @@ typedef struct { uint8_t *data; } pp_tile_t; -typedef struct { +typedef struct _pp_path_t { pp_point_t *points; - uint32_t count; + int count; // number of points currently stored in points buffer + int storage; // size of *points buffer + struct _pp_path_t *next; // next path in the linked list } pp_path_t; +void pp_path_add_point(pp_path_t *path, pp_point_t p); +void pp_path_add_points(pp_path_t *path, pp_point_t *p, int count); +void pp_path_add_path(pp_path_t *path, pp_path_t *other); +pp_rect_t pp_path_bounds(const pp_path_t *c); typedef struct { - pp_path_t *paths; - uint32_t count; + pp_path_t *paths; } pp_poly_t; +pp_poly_t *pp_poly_new(); +void pp_poly_free(pp_poly_t *poly); +pp_path_t* pp_poly_tail_path(pp_poly_t *p); +pp_path_t* pp_poly_add_path(pp_poly_t *p); +pp_rect_t pp_poly_bounds(pp_poly_t *p); +int pp_poly_path_count(pp_poly_t *p); // user settings typedef void (*pp_tile_callback_t)(const pp_tile_t *tile); @@ -124,8 +135,6 @@ void pp_antialias(pp_antialias_t antialias); pp_mat3_t *pp_transform(pp_mat3_t *transform); void pp_render(pp_poly_t *polygon); -pp_rect_t pp_contour_bounds(const pp_path_t *c); -pp_rect_t pp_polygon_bounds(pp_poly_t *p); #ifdef __cplusplus } @@ -249,25 +258,102 @@ uint8_t pp_tile_get(const pp_tile_t *tile, const int32_t x, const int32_t y) { return tile->data[(x - tile->x) + (y - tile->y) * PP_TILE_BUFFER_SIZE]; } +pp_poly_t *pp_poly_new() { + pp_poly_t *poly = (pp_poly_t *)PP_MALLOC(sizeof(pp_poly_t)); + poly->paths = NULL; + return poly; +} + +void pp_poly_free(pp_poly_t *poly) { + if(poly->paths) { + pp_path_t *path = poly->paths; + while(path) { + PP_FREE(path->points); + pp_path_t *free_path = path; + path = path->next; + PP_FREE(free_path); + } + } + PP_FREE(poly); +} + +// polygon and path implementation +pp_path_t* pp_poly_tail_path(pp_poly_t *poly) { + pp_path_t *path = poly->paths; + while(path->next) path = path->next; + return path; +} + +int pp_poly_path_count(pp_poly_t *poly) { + if(!poly->paths) return 0; + pp_path_t *path = poly->paths; + int i = 0; + while(path->next) { + i++; + path = path->next; + } + return i; +} + +pp_path_t* pp_poly_add_path(pp_poly_t *poly) { + pp_path_t *path = (pp_path_t *)PP_MALLOC(sizeof(pp_path_t)); + memset(path, 0, sizeof(pp_path_t)); + path->storage = 8; + path->points = (pp_point_t *)PP_MALLOC(sizeof(pp_point_t) * path->storage); + + if(!poly->paths) { + poly->paths = path; + }else{ + pp_path_t *tail = pp_poly_tail_path(poly); + tail->next = path; + } + + return path; +} + +pp_point_t* pp_path_tail_point(pp_path_t *path) { + return (path->count > 0) ? &path->points[path->count -1] : NULL; +} + +void pp_path_add_point(pp_path_t *path, pp_point_t p) { + if(path->count == path->storage) { // no storage left, double buffer size + path->points = (pp_point_t *)PP_REALLOC(path->points, sizeof(pp_point_t) * (path->storage * 2)); + path->storage *= 2; + } + path->points[path->count] = p; + path->count++; +} + +void pp_path_add_points(pp_path_t *path, pp_point_t *points, int count) { + if(count + path->count > path->storage) { // not enough storage, allocate + path->points = (pp_point_t *)PP_REALLOC(path->points, sizeof(pp_point_t) * (count + path->count)); + path->storage = count + path->count; + } + memcpy(&path->points[count], points, sizeof(pp_point_t) * count); + path->count += count; +} + // pp_contour_t implementation -pp_rect_t pp_contour_bounds(const pp_path_t *c) { - int minx = c->points[0].x, maxx = minx; - int miny = c->points[0].y, maxy = miny; - for(uint32_t i = 1; i < c->count; i++) { - minx = _pp_min(minx, c->points[i].x); - miny = _pp_min(miny, c->points[i].y); - maxx = _pp_max(maxx, c->points[i].x); - maxy = _pp_max(maxy, c->points[i].y); - } - return (pp_rect_t){.x = minx, .y = miny, .w = maxx - minx, .h = maxy - miny}; +pp_rect_t pp_path_bounds(const pp_path_t *path) { + int minx = INT_MAX, maxx = -INT_MAX, miny = INT_MAX, maxy = -INT_MAX; + for(int i = 0; i < path->count; i++) { + minx = _pp_min(minx, path->points[i].x); + miny = _pp_min(miny, path->points[i].y); + maxx = _pp_max(maxx, path->points[i].x); + maxy = _pp_max(maxy, path->points[i].y); + } + return (pp_rect_t){minx, miny, maxx - minx, maxy - miny}; } pp_rect_t pp_polygon_bounds(pp_poly_t *p) { - if(p->count == 0) {return (pp_rect_t){};} - pp_rect_t b = pp_contour_bounds(&p->paths[0]); - for(uint32_t i = 1; i < p->count; i++) { - pp_rect_t cb = pp_contour_bounds(&p->paths[i]); + pp_path_t *path = p->paths; + if(!path) return (pp_rect_t){}; + pp_rect_t b = pp_path_bounds(path); + path = path->next; + while(path) { + pp_rect_t cb = pp_path_bounds(path); b = pp_rect_merge(&b, &cb); + path = path->next; } return b; } @@ -391,30 +477,24 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) { //#endif } -void build_nodes(pp_path_t *contour, pp_rect_t *bounds) { +void build_nodes(pp_path_t *path, pp_rect_t *tb) { PP_COORD_TYPE aa_scale = (PP_COORD_TYPE)(1 << _pp_antialias); - pp_point_t tile_origin = (pp_point_t) { - .x = bounds->x * aa_scale, - .y = bounds->y * aa_scale - }; + pp_point_t tile_origin = (pp_point_t){tb->x * aa_scale, tb->y * aa_scale}; // start with the last point to close the loop, transform it, scale for antialiasing, and offset to tile origin - pp_point_t last = contour->points[contour->count - 1]; + pp_point_t last = path->points[path->count - 1]; if(_pp_transform) last = pp_point_transform(&last, _pp_transform); last.x *= aa_scale; last.y *= aa_scale; last = pp_point_sub(&last, &tile_origin); - - for(uint32_t i = 0; i < contour->count; i++) { - // fetch next point, transform it, scale for antialiasing, and offset to tile origin - pp_point_t point = contour->points[i]; - if(_pp_transform) point = pp_point_transform(&point, _pp_transform); - point.x *= aa_scale; point.y *= aa_scale; - point = pp_point_sub(&point, &tile_origin); - - add_line_segment_to_nodes(last, point); - - last = point; + + for(int i = 0; i < path->count; i++) { + pp_point_t next = path->points[i]; + if(_pp_transform) next = pp_point_transform(&next, _pp_transform); + next.x *= aa_scale; next.y *= aa_scale; + next = pp_point_sub(&next, &tile_origin); + add_line_segment_to_nodes(last, next); + last = next; } } @@ -497,20 +577,18 @@ pp_rect_t render_nodes(pp_rect_t *tb) { void pp_render(pp_poly_t *polygon) { - debug("> draw polygon with %u contours\n", polygon->count); + debug("> draw polygon with %u contours\n", pp_poly_path_count(polygon)); - if(polygon->count == 0) { - return; - } + if(!polygon->paths) return; // determine extreme bounds - pp_rect_t polygon_bounds = pp_polygon_bounds(polygon); + pp_rect_t pb = pp_polygon_bounds(polygon); if(_pp_transform) { - polygon_bounds = pp_rect_transform(&polygon_bounds, _pp_transform); + pb = pp_rect_transform(&pb, _pp_transform); } - debug(" - polygon bounds %d, %d (%d x %d)\n", polygon_bounds.x, polygon_bounds.y, polygon_bounds.w, polygon_bounds.h); + debug(" - polygon bounds %d, %d (%d x %d)\n", pb.x, pb.y, pb.w, pb.h); debug(" - clip %d, %d (%d x %d)\n", _pp_clip.x, _pp_clip.y, _pp_clip.w, _pp_clip.h); #ifdef USE_RP2040_INTERP @@ -526,8 +604,8 @@ void pp_render(pp_poly_t *polygon) { // iterate over tiles debug(" - processing tiles\n"); - for(int32_t y = polygon_bounds.y; y < polygon_bounds.y + polygon_bounds.h; y += PP_TILE_BUFFER_SIZE) { - for(int32_t x = polygon_bounds.x; x < polygon_bounds.x + polygon_bounds.w; x += PP_TILE_BUFFER_SIZE) { + for(int32_t y = pb.y; y < pb.y + pb.h; y += PP_TILE_BUFFER_SIZE) { + for(int32_t x = pb.x; x < pb.x + pb.w; x += PP_TILE_BUFFER_SIZE) { pp_rect_t tb = (pp_rect_t){.x = x, .y = y, .w = PP_TILE_BUFFER_SIZE, .h = PP_TILE_BUFFER_SIZE}; tb = pp_rect_intersection(&tb, &_pp_clip); debug(" : %d, %d (%d x %d)\n", tb.x, tb.y, tb.w, tb.h); @@ -540,11 +618,13 @@ void pp_render(pp_poly_t *polygon) { memset(tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE); // build the nodes for each pp_path_t - for(uint32_t i = 0; i < polygon->count; i++) { - pp_path_t pp_path_t = polygon->paths[i]; - debug(" : build nodes for path\n"); - build_nodes(&pp_path_t, &tb); - } + pp_path_t *path = polygon->paths; + if(!path) return; + do { + debug(" : build nodes for path (%d points)\n", path->count); + build_nodes(path, &tb); + path = path->next; + } while(path); debug(" : render the tile\n"); // render the tile diff --git a/micropython/modules/picovector/picovector.cpp b/micropython/modules/picovector/picovector.cpp index 5cba3cea..8da08e4f 100644 --- a/micropython/modules/picovector/picovector.cpp +++ b/micropython/modules/picovector/picovector.cpp @@ -27,7 +27,7 @@ typedef struct _VECTOR_obj_t { typedef struct _PATH_obj_t { mp_obj_base_t base; - pp_path_t path; + pp_path_t *path; } _PATH_obj_t; void __printf_debug_flush() { @@ -170,19 +170,19 @@ mp_obj_t RECTANGLE_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_k mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); _PATH_obj_t *self = mp_obj_malloc_with_finaliser(_PATH_obj_t, &POLYGON_type); + self->path = (pp_path_t *)PP_MALLOC(sizeof(pp_path_t)); + self->path->storage = 4; + self->path->points = (pp_point_t *)PP_MALLOC(sizeof(pp_point_t) * self->path->storage); picovector_point_type x = mp_picovector_get_point_type(args[ARG_x].u_obj); picovector_point_type y = mp_picovector_get_point_type(args[ARG_y].u_obj); picovector_point_type w = mp_picovector_get_point_type(args[ARG_w].u_obj); picovector_point_type h = mp_picovector_get_point_type(args[ARG_h].u_obj); - self->path.points = m_new(pp_point_t, 4); - self->path.count = 4; - - self->path.points[0] = {picovector_point_type(x), picovector_point_type(y)}; - self->path.points[1] = {picovector_point_type(x + w), picovector_point_type(y)}; - self->path.points[2] = {picovector_point_type(x + w), picovector_point_type(y + h)}; - self->path.points[3] = {picovector_point_type(x), picovector_point_type(y + h)}; + pp_path_add_point(self->path, {picovector_point_type(x), picovector_point_type(y)}); + pp_path_add_point(self->path, {picovector_point_type(x + w), picovector_point_type(y)}); + pp_path_add_point(self->path, {picovector_point_type(x + w), picovector_point_type(y + h)}); + pp_path_add_point(self->path, {picovector_point_type(x), picovector_point_type(y + h)}); return self; } @@ -215,15 +215,17 @@ mp_obj_t REGULAR_POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size float angle = (360.0f / sides) * (M_PI / 180.0f); - self->path.points = m_new(pp_point_t, sides); - self->path.count = sides; + + self->path = (pp_path_t *)PP_MALLOC(sizeof(pp_path_t)); + self->path->storage = sides; + self->path->points = (pp_point_t *)PP_MALLOC(sizeof(pp_point_t) * self->path->storage); for(auto s = 0u; s < sides; s++) { float current_angle = angle * s + rotation; - self->path.points[s] = { + pp_path_add_point(self->path, { (picovector_point_type)(cos(current_angle) * radius) + o_x, (picovector_point_type)(sin(current_angle) * radius) + o_y - }; + }); } return self; @@ -235,10 +237,11 @@ mp_obj_t POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, size_t num_points = n_args; const mp_obj_t *points = all_args; - if(num_points < 3) mp_raise_ValueError("Polygon: At least 3 points required."); + self->path = (pp_path_t *)PP_MALLOC(sizeof(pp_path_t)); + self->path->storage = num_points; + self->path->points = (pp_point_t *)PP_MALLOC(sizeof(pp_point_t) * self->path->storage); - self->path.points = m_new(pp_point_t, num_points); - self->path.count = num_points; + if(num_points < 3) mp_raise_ValueError("Polygon: At least 3 points required."); for(auto i = 0u; i < num_points; i++) { mp_obj_t c_obj = points[i]; @@ -249,10 +252,10 @@ mp_obj_t POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, if(t_point->len != 2) mp_raise_ValueError("Tuple must have X, Y"); - self->path.points[i] = { + pp_path_add_point(self->path, { (picovector_point_type)mp_picovector_get_point_type(t_point->items[0]), (picovector_point_type)mp_picovector_get_point_type(t_point->items[1]), - }; + }); } return self; @@ -264,13 +267,13 @@ mp_obj_t POLYGON_centroid(mp_obj_t self_in) { PP_COORD_TYPE sum_x = (PP_COORD_TYPE)0; PP_COORD_TYPE sum_y = (PP_COORD_TYPE)0; - for(auto i = 0u; i < self->path.count; i++) { - sum_x += self->path.points[i].x; - sum_y += self->path.points[i].y; + for(auto i = 0; i < self->path->count; i++) { + sum_x += self->path->points[i].x; + sum_y += self->path->points[i].y; } - sum_x /= (float)self->path.count; - sum_y /= (float)self->path.count; + sum_x /= (float)self->path->count; + sum_y /= (float)self->path->count; mp_obj_t tuple[2]; tuple[0] = mp_picovector_set_point_type((int)(sum_x)); @@ -282,7 +285,7 @@ mp_obj_t POLYGON_centroid(mp_obj_t self_in) { mp_obj_t POLYGON_bounds(mp_obj_t self_in) { _PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t); - pp_rect_t bounds = pp_contour_bounds(&self->path); + pp_rect_t bounds = pp_path_bounds(self->path); mp_obj_t tuple[4]; tuple[0] = mp_picovector_set_point_type((int)(bounds.x)); @@ -297,10 +300,10 @@ void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki (void)kind; _PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t); - pp_rect_t bounds = pp_contour_bounds(&self->path); + pp_rect_t bounds = pp_path_bounds(self->path); mp_print_str(print, "Polygon(points = "); - mp_obj_print_helper(print, mp_picovector_set_point_type(self->path.count), PRINT_REPR); + mp_obj_print_helper(print, mp_picovector_set_point_type(self->path->count), PRINT_REPR); mp_print_str(print, ", bounds = "); mp_obj_print_helper(print, mp_picovector_set_point_type(bounds.x), PRINT_REPR); mp_print_str(print, ", "); @@ -314,7 +317,8 @@ void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki mp_obj_t POLYGON__del__(mp_obj_t self_in) { _PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t); - (void)self; + PP_FREE(self->path->points); + PP_FREE(self->path); // TODO: Do we actually need to free anything here, if it's on GC heap it should get collected return mp_const_none; } @@ -323,7 +327,7 @@ typedef struct _mp_obj_polygon_it_t { mp_obj_base_t base; mp_fun_1_t iternext; mp_obj_t polygon; - size_t cur; + int cur; } mp_obj_polygon_it_t; static mp_obj_t py_path_it_iternext(mp_obj_t self_in) { @@ -332,11 +336,11 @@ static mp_obj_t py_path_it_iternext(mp_obj_t self_in) { //mp_printf(&mp_plat_print, "points: %d, current: %d\n", polygon->contour.count, self->cur); - if(self->cur >= path->path.count) return MP_OBJ_STOP_ITERATION; + if(self->cur >= path->path->count) return MP_OBJ_STOP_ITERATION; mp_obj_t tuple[2]; - tuple[0] = mp_picovector_set_point_type((int)(path->path.points[self->cur].x)); - tuple[1] = mp_picovector_set_point_type((int)(path->path.points[self->cur].y)); + tuple[0] = mp_picovector_set_point_type((int)(path->path->points[self->cur].x)); + tuple[1] = mp_picovector_set_point_type((int)(path->path->points[self->cur].y)); self->cur++; return mp_obj_new_tuple(2, tuple); @@ -484,7 +488,7 @@ mp_obj_t VECTOR_rotate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg float angle = mp_obj_get_float(args[ARG_angle].u_obj); - self->vector->rotate(&poly->path, origin, angle); + self->vector->rotate(poly->path, origin, angle); return mp_const_none; } @@ -509,7 +513,7 @@ mp_obj_t VECTOR_translate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ pp_point_t translate = {(PP_COORD_TYPE)args[ARG_x].u_int, (PP_COORD_TYPE)args[ARG_y].u_int}; - self->vector->translate(&poly->path, translate); + self->vector->translate(poly->path, translate); return mp_const_none; } @@ -521,23 +525,34 @@ mp_obj_t VECTOR_draw(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) _VECTOR_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], _VECTOR_obj_t); - pp_poly_t group; - group.count = num_polygons; - group.paths = (pp_path_t *)m_new(pp_path_t, num_polygons); + if(num_polygons == 1) { + mp_obj_t poly_obj = polygons[0]; + + if(!MP_OBJ_IS_TYPE(poly_obj, &POLYGON_type)) mp_raise_TypeError("draw: Polygon required."); + + _PATH_obj_t *poly = MP_OBJ_TO_PTR2(poly_obj, _PATH_obj_t); + + self->vector->draw(poly->path); + + return mp_const_none; + } + + + pp_poly_t *group = pp_poly_new(); for(auto i = 0u; i < num_polygons; i++) { + pp_path_t *path = pp_poly_add_path(group); mp_obj_t poly_obj = polygons[i]; if(!MP_OBJ_IS_TYPE(poly_obj, &POLYGON_type)) mp_raise_TypeError("draw: Polygon required."); _PATH_obj_t *poly = MP_OBJ_TO_PTR2(poly_obj, _PATH_obj_t); - group.paths[i].points = poly->path.points; - group.paths[i].count = poly->path.count; + pp_path_add_points(path, poly->path->points, poly->path->count); } - self->vector->draw(&group); + self->vector->draw(group); - m_free(group.paths); + pp_poly_free(group); return mp_const_none; }