PicoVector: Big refactor, ppp primitives.

* Remove Polygon types in favour of primitives .circle, .rectangle etc
* Add a new Transform type for building up transformation matrices
* Add support to set/clear transform on drawing
pull/1019/head
Phil Howard 2024-07-25 15:07:26 +01:00 zatwierdzone przez Phil Howard
rodzic eae591ae3c
commit 75a01b2fb8
7 zmienionych plików z 658 dodań i 315 usunięć

Wyświetl plik

@ -1,8 +1,10 @@
#define PP_IMPLEMENTATION
#define AF_IMPLEMENTATION
#define PPP_IMPLEMENTATION
#include "pico_vector.hpp"
#include <vector>
namespace pimoroni {
PicoGraphics *PicoVector::graphics = nullptr;

Wyświetl plik

@ -17,6 +17,7 @@
#define AF_DEBUG(...) af_debug(__VA_ARGS__)
#include "pretty-poly.h"
#include "pretty-poly-primitives.h"
#include "alright-fonts.h"
#include "pico_graphics.hpp"
@ -29,10 +30,10 @@ namespace pimoroni {
class PicoVector {
private:
static PicoGraphics *graphics;
af_text_metrics_t text_metrics;
public:
static PicoGraphics *graphics;
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
PicoVector::graphics = graphics;

Wyświetl plik

@ -0,0 +1,181 @@
/*
Pretty Poly 🦜 - super-sampling polygon renderer for low resource platforms.
Jonathan Williamson, August 2022
Examples, source, and more: https://github.com/lowfatcode/pretty-poly
MIT License https://github.com/lowfatcode/pretty-poly/blob/main/LICENSE
An easy way to render high quality graphics in embedded applications running
on resource constrained microcontrollers such as the Cortex M0 and up.
- Renders polygons: concave, self-intersecting, multi contour, holes, etc.
- C11 header only library: simply copy the header file into your project
- Tile based renderer: low memory footprint, cache coherency
- Low memory usage: ~4kB of heap memory required
- High speed on low resource platforms: optionally no floating point
- Antialiasing modes: X1 (none), X4 and X16 super sampling
- Bounds clipping: all results clipped to supplied clip rectangle
- Pixel format agnostic: renders a "tile" to blend into your framebuffer
- Support for hardware interpolators on rp2040 (thanks @MichaelBell!)
Contributor bwaaaaaarks! 🦜
@MichaelBell - lots of bug fixes, performance boosts, and suggestions.
@gadgetoid - integrating into the PicoVector library and testing.
*/
#ifndef PPP_INCLUDE_H
#define PPP_INCLUDE_H
#include "pretty-poly.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
PP_COORD_TYPE x, y, w, h; // coordinates
PP_COORD_TYPE s; // stroke thickness (0 == filled)
PP_COORD_TYPE r1, r2, r3, r4; // corner radii (r1 = top left then clockwise)
} ppp_rect_def;
typedef struct {
PP_COORD_TYPE x, y; // coordinates
PP_COORD_TYPE r; // radius
int e; // edge count
PP_COORD_TYPE s; // stroke thickness (0 == filled)
} ppp_regular_def;
typedef struct {
PP_COORD_TYPE x, y; // coordinates
PP_COORD_TYPE r; // radius
PP_COORD_TYPE s; // stroke thickness (0 == filled)
} ppp_circle_def;
typedef struct {
PP_COORD_TYPE x, y; // coordinates
PP_COORD_TYPE r; // radius
PP_COORD_TYPE s; // stroke thickness (0 == filled)
PP_COORD_TYPE f, t; // angle from and to
} ppp_arc_def;
pp_poly_t* ppp_rect(ppp_rect_def d);
pp_poly_t* ppp_regular(ppp_regular_def d);
pp_poly_t* ppp_circle(ppp_circle_def d);
pp_poly_t* ppp_arc(ppp_arc_def d);
#ifdef __cplusplus
}
#endif
#ifdef PPP_IMPLEMENTATION
void _pp_round_rect_corner_points(pp_path_t *path, PP_COORD_TYPE cx, PP_COORD_TYPE cy, PP_COORD_TYPE r, int q) {
float quality = 5; // higher the number, lower the quality - selected by experiment
int steps = ceil(r / quality) + 2; // + 2 to include start and end
float delta = -(M_PI / 2) / steps;
float theta = (M_PI / 2) * q; // select start theta for this quadrant
for(int i = 0; i <= steps; i++) {
PP_COORD_TYPE xo = sin(theta) * r, yo = cos(theta) * r;
pp_path_add_point(path, (pp_point_t){cx + xo, cy + yo});
theta += delta;
}
}
void _ppp_rrect_corner(pp_path_t *path, PP_COORD_TYPE cx, PP_COORD_TYPE cy, PP_COORD_TYPE r, int q) {
float quality = 5; // higher the number, lower the quality - selected by experiment
int steps = ceil(r / quality) + 2; // + 2 to include start and end
float delta = -(M_PI / 2) / steps;
float theta = (M_PI / 2) * q; // select start theta for this quadrant
for(int i = 0; i <= steps; i++) {
PP_COORD_TYPE xo = sin(theta) * r, yo = cos(theta) * r;
pp_path_add_point(path, (pp_point_t){cx + xo, cy + yo});
theta += delta;
}
}
void _ppp_rrect_path(pp_path_t *path, ppp_rect_def d) {
d.r1 == 0 ? pp_path_add_point(path, (pp_point_t){d.x, d.y}) : _ppp_rrect_corner(path, d.x + d.r1, d.y + d.r1, d.r1, 3);
d.r2 == 0 ? pp_path_add_point(path, (pp_point_t){d.x + d.w, d.y}) : _ppp_rrect_corner(path, d.x + d.w - d.r2, d.y + d.r2, d.r2, 2);
d.r3 == 0 ? pp_path_add_point(path, (pp_point_t){d.x + d.w, d.y + d.h}) : _ppp_rrect_corner(path, d.x + d.w - d.r3, d.y + d.h - d.r3, d.r3, 1);
d.r4 == 0 ? pp_path_add_point(path, (pp_point_t){d.x, d.y}) : _ppp_rrect_corner(path, d.x + d.r4, d.y + d.h - d.r4, d.r4, 0);
}
pp_poly_t* ppp_rect(ppp_rect_def d) {
pp_poly_t *poly = pp_poly_new();
pp_path_t *path = pp_poly_add_path(poly);
if(d.r1 == 0.0f && d.r2 == 0.0f && d.r3 == 0.0f && d.r4 == 0.0f) { // non rounded rect
pp_point_t points[] = {{d.x, d.y}, {d.x + d.w, d.y}, {d.x + d.w, d.y + d.h}, {d.x, d.y + d.h}};
pp_path_add_points(path, points, 4);
if(d.s != 0) { // stroked, not filled
d.x += d.s; d.y += d.s; d.w -= 2 * d.s; d.h -= 2 * d.s;
pp_path_t *inner = pp_poly_add_path(poly);
pp_point_t points[] = {{d.x, d.y}, {d.x + d.w, d.y}, {d.x + d.w, d.y + d.h}, {d.x, d.y + d.h}};
pp_path_add_points(inner, points, 4);
}
}else{ // rounded rect
_ppp_rrect_path(path, d);
if(d.s != 0) { // stroked, not filled
d.x += d.s; d.y += d.s; d.w -= 2 * d.s; d.h -= 2 * d.s;
d.r1 = _pp_max(0, d.r1 - d.s);
d.r2 = _pp_max(0, d.r2 - d.s);
d.r3 = _pp_max(0, d.r3 - d.s);
d.r4 = _pp_max(0, d.r4 - d.s);
pp_path_t *inner = pp_poly_add_path(poly);
_ppp_rrect_path(inner, d);
}
}
return poly;
}
pp_poly_t* ppp_regular(ppp_regular_def d) {
pp_poly_t *poly = pp_poly_new();
pp_path_t *path = pp_poly_add_path(poly);
pp_path_t *inner = d.s != 0.0f ? pp_poly_add_path(poly) : NULL;
for(int i = 0; i < d.e; i++) {
float theta = ((M_PI * 2.0f) / (float)d.e) * (float)i;
pp_path_add_point(path, (pp_point_t){sin(theta) * d.r + d.x, cos(theta) * d.r + d.y});
if(inner) {
pp_path_add_point(inner, (pp_point_t){sin(theta) * (d.r - d.s) + d.x, cos(theta) * (d.r - d.s) + d.y});
}
}
return poly;
}
pp_poly_t* ppp_circle(ppp_circle_def d) {
int e = _pp_max(8, d.r); // edge count
ppp_regular_def r = {d.x, d.y, d.r, e, d.s};
return ppp_regular(r);
}
pp_poly_t* ppp_arc(ppp_arc_def d) {
pp_poly_t *poly = pp_poly_new();
pp_path_t *path = pp_poly_add_path(poly);
pp_path_t *inner = (pp_path_t *)(d.s == 0.0f ? NULL : calloc(1, sizeof(pp_path_t)));
// no thickness, so add centre point to make pie shape
if(!inner) pp_path_add_point(path, (pp_point_t){d.x, d.y});
d.f = d.f * (M_PI / 180.0f); d.t = d.t * (M_PI / 180.0f); // to radians
int s = _pp_max(8, d.r); float astep = (d.t - d.f) / s; float a = d.f;
for(int i = 0; i <= s; i++) {
pp_path_add_point(path, (pp_point_t){sin(a) * d.r + d.x, cos(a) * d.r + d.y});
if(inner) {
pp_path_add_point(inner, (pp_point_t){sin(d.t - (a - d.f)) * (d.r - d.s) + d.x, cos(d.t - (a - d.f)) * (d.r - d.s) + d.y});
}
a += astep;
}
if(inner) { // append the inner path
pp_path_add_points(path, inner->points, inner->count);
free(inner->points); free(inner);
}
return poly;
}
#endif // PPP_IMPLEMENTATION
#endif // PPP_INCLUDE_H

Wyświetl plik

@ -6,8 +6,8 @@
Examples, source, and more: https://github.com/lowfatcode/pretty-poly
MIT License https://github.com/lowfatcode/pretty-poly/blob/main/LICENSE
An easy way to render high quality graphics in embedded applications running
on resource constrained microcontrollers such as the Cortex M0 and up.
An easy way to render high quality graphics in embedded applications running
on resource constrained microcontrollers such as the Cortex M0 and up.
- Renders polygons: concave, self-intersecting, multi contour, holes, etc.
- C11 header only library: simply copy the header file into your project
@ -21,9 +21,9 @@
Contributor bwaaaaaarks! 🦜
@MichaelBell - lots of bug fixes, performance boosts, and suggestions.
@MichaelBell - lots of bug fixes, performance boosts, and suggestions.
@gadgetoid - integrating into the PicoVector library and testing.
*/
#ifndef PP_INCLUDE_H
@ -84,7 +84,7 @@ pp_point_t pp_point_transform(pp_point_t *p, pp_mat3_t *m);
// rect type
typedef struct {
int32_t x, y, w, h;
int32_t x, y, w, h;
} pp_rect_t;
bool pp_rect_empty(pp_rect_t *r);
pp_rect_t pp_rect_intersection(pp_rect_t *r1, pp_rect_t *r2);
@ -109,10 +109,11 @@ typedef struct _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);
void pp_path_union(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;
pp_path_t *paths;
} pp_poly_t;
pp_poly_t *pp_poly_new();
void pp_poly_free(pp_poly_t *poly);
@ -120,6 +121,7 @@ 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);
void pp_poly_merge(pp_poly_t *p, pp_poly_t *m);
// user settings
typedef void (*pp_tile_callback_t)(const pp_tile_t *tile);
@ -186,7 +188,7 @@ void pp_mat3_mul(pp_mat3_t *m1, pp_mat3_t *m2) {
r.v12 = m1->v10 * m2->v02 + m1->v11 * m2->v12 + m1->v12 * m2->v22;
r.v20 = m1->v20 * m2->v00 + m1->v21 * m2->v10 + m1->v22 * m2->v20;
r.v21 = m1->v20 * m2->v01 + m1->v21 * m2->v11 + m1->v22 * m2->v21;
r.v22 = m1->v20 * m2->v02 + m1->v21 * m2->v12 + m1->v22 * m2->v22;
r.v22 = m1->v20 * m2->v02 + m1->v21 * m2->v12 + m1->v22 * m2->v22;
*m1 = r;
}
@ -223,7 +225,7 @@ pp_rect_t pp_rect_intersection(pp_rect_t *r1, pp_rect_t *r2) {
}
pp_rect_t pp_rect_merge(pp_rect_t *r1, pp_rect_t *r2) {
return (pp_rect_t){
.x = _pp_min(r1->x, r2->x),
.x = _pp_min(r1->x, r2->x),
.y = _pp_min(r1->y, r2->y),
.w = _pp_max(r1->x + r1->w, r2->x + r2->w) - _pp_min(r1->x, r2->x),
.h = _pp_max(r1->y + r1->h, r2->y + r2->h) - _pp_min(r1->y, r2->y)
@ -246,9 +248,9 @@ pp_rect_t pp_rect_transform(pp_rect_t *r, pp_mat3_t *m) {
PP_COORD_TYPE maxy = _pp_max(tl.y, _pp_max(tr.y, _pp_max(bl.y, br.y)));
return (pp_rect_t){
.x = (int32_t)minx,
.y = (int32_t)miny,
.w = (int32_t)(maxx - minx),
.x = (int32_t)minx,
.y = (int32_t)miny,
.w = (int32_t)(maxx - minx),
.h = (int32_t)(maxy - miny)
};
}
@ -295,7 +297,7 @@ int pp_poly_path_count(pp_poly_t *poly) {
return i;
}
pp_path_t* pp_poly_add_path(pp_poly_t *poly) {
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;
@ -307,18 +309,34 @@ pp_path_t* pp_poly_add_path(pp_poly_t *poly) {
pp_path_t *tail = pp_poly_tail_path(poly);
tail->next = path;
}
return path;
}
void pp_poly_merge(pp_poly_t *p, pp_poly_t *m) {
if(!p->paths) {
p->paths = m->paths;
}else{
pp_poly_tail_path(p)->next = m->paths;
}
m->paths = NULL;
pp_poly_free(m);
}
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;
if(path->points) {
path->storage *= 2;
path->points = (pp_point_t *)PP_REALLOC(path->points, sizeof(pp_point_t) * (path->storage));
}else{
path->storage = 8;
path->points = (pp_point_t *)PP_MALLOC(sizeof(pp_point_t) * (path->storage));
}
}
path->points[path->count] = p;
path->count++;
@ -326,28 +344,32 @@ 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 *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;
path->storage = path->count + count;
path->points = (pp_point_t *)PP_REALLOC(path->points, sizeof(pp_point_t) * (path->storage));
}
memcpy(&path->points[count], points, sizeof(pp_point_t) * count);
path->count += count;
memcpy(&path->points[path->count], points, sizeof(pp_point_t) * count);
path->count += count;
}
// pp_contour_t implementation
pp_rect_t pp_path_bounds(const pp_path_t *path) {
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);
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) {
void pp_path_union(pp_path_t *path, pp_path_t *other) {
}
pp_rect_t pp_poly_bounds(pp_poly_t *p) {
pp_path_t *path = p->paths;
if(!path) return (pp_rect_t){};
if(!path) return (pp_rect_t){};
pp_rect_t b = pp_path_bounds(path);
path = path->next;
while(path) {
@ -397,13 +419,13 @@ void debug_tile(const pp_tile_t *tile) {
debug("[%3d]: ", y);
for(int32_t x = 0; x < tile->w; x++) {
debug("%02x", pp_tile_get(tile, x, y));
}
debug("\n");
}
debug("\n");
}
debug("-----------------------\n");
}
void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_rect_t *tb) {
int32_t sx = start.x, sy = start.y, ex = end.x, ey = end.y;
if(ey < sy) {
@ -415,13 +437,13 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
}
// early out if line is completely outside the tile, or has no gradient
if (ey < 0 || sy >= (int)(PP_TILE_BUFFER_SIZE << _pp_antialias) || sy == ey) return;
if (ey < 0 || sy >= (int)(tb->h << _pp_antialias) || sy == ey) return;
debug(" + line segment from %d, %d to %d, %d\n", sx, sy, ex, ey);
// determine how many in-bounds lines to render
int y = _pp_max(0, sy);
int count = _pp_min((int)(PP_TILE_BUFFER_SIZE << _pp_antialias), ey) - y;
int count = _pp_min((int)(tb->h << _pp_antialias), ey) - y;
int x = sx;
int e = 0;
@ -465,7 +487,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end) {
while(e > dy) {e -= dy; x += xinc;}
// clamp node x value to tile bounds
int nx = _pp_max(_pp_min(x, (PP_TILE_BUFFER_SIZE << _pp_antialias)), 0);
int nx = _pp_max(_pp_min(x, (tb->w << _pp_antialias)), 0);
//debug(" + adding node at %d, %d\n", x, y);
// add node to node list
nodes[y][node_counts[y]++] = nx;
@ -482,18 +504,18 @@ void build_nodes(pp_path_t *path, pp_rect_t *tb) {
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
// start with the last point to close the loop, transform it, scale for antialiasing, and offset to tile origin
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(int i = 0; i < path->count; i++) {
pp_point_t next = path->points[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);
add_line_segment_to_nodes(last, next, tb);
last = next;
}
}
@ -527,7 +549,7 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
// update render bounds
rb.x = _pp_min(rb.x, sx);
rb.y = _pp_min(rb.y, y);
rb.y = _pp_min(rb.y, y);
minx = _pp_min(_pp_min(sx, ex), minx);
maxx = _pp_max(_pp_max(sx, ex), maxx);
rb.h = y - rb.y + 1;
@ -563,7 +585,7 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
#if PP_SCALE_TO_ALPHA == 1
for(int y = rb.y; y < rb.y + rb.h; y++) {
unsigned char* row_data = &tile_buffer[y * PP_TILE_BUFFER_SIZE + rb.x];
for(int x = rb.x; x < rb.x + rb.w; x++) {
for(int x = rb.x; x < rb.x + rb.w; x++) {
*row_data = p_alpha_map[*row_data];
row_data++;
}
@ -582,7 +604,7 @@ void pp_render(pp_poly_t *polygon) {
if(!polygon->paths) return;
// determine extreme bounds
pp_rect_t pb = pp_polygon_bounds(polygon);
pp_rect_t pb = pp_poly_bounds(polygon);
if(_pp_transform) {
pb = pp_rect_transform(&pb, _pp_transform);
@ -634,7 +656,7 @@ void pp_render(pp_poly_t *polygon) {
if(pp_rect_empty(&tb)) { debug(" : empty after rendering, skipping\n"); continue; }
pp_tile_t tile = {
pp_tile_t tile = {
.x = tb.x, .y = tb.y, .w = tb.w, .h = tb.h,
.stride = PP_TILE_BUFFER_SIZE,
.data = tile_buffer + rb.x + (PP_TILE_BUFFER_SIZE * rb.y)

Wyświetl plik

@ -3,64 +3,77 @@
/* Polygon */
static MP_DEFINE_CONST_FUN_OBJ_1(POLYGON__del__obj, POLYGON__del__);
// Transformations
//static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_rotate_obj, 3, POLYGON_rotate);
//static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_translate_obj, 4, POLYGON_translate);
// Utility functions
static MP_DEFINE_CONST_FUN_OBJ_1(POLYGON_centroid_obj, POLYGON_centroid);
static MP_DEFINE_CONST_FUN_OBJ_1(POLYGON_bounds_obj, POLYGON_bounds);
static MP_DEFINE_CONST_FUN_OBJ_2(POLYGON_transform_obj, POLYGON_transform);
// Primitives
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_rectangle_obj, 5, POLYGON_rectangle);
static MP_DEFINE_CONST_FUN_OBJ_VAR(POLYGON_path_obj, 4, POLYGON_path);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_regular_obj, 5, POLYGON_regular);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_circle_obj, 4, POLYGON_circle);
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_arc_obj, 6, POLYGON_arc);
static const mp_rom_map_elem_t POLYGON_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&POLYGON__del__obj) },
// Transformations
//{ MP_ROM_QSTR(MP_QSTR_rotate), MP_ROM_PTR(&POLYGON_rotate_obj) },
//{ MP_ROM_QSTR(MP_QSTR_translate), MP_ROM_PTR(&POLYGON_translate_obj) },
// Utility functions
{ MP_ROM_QSTR(MP_QSTR_centroid), MP_ROM_PTR(&POLYGON_centroid_obj) },
{ MP_ROM_QSTR(MP_QSTR_bounds), MP_ROM_PTR(&POLYGON_bounds_obj) },
{ MP_ROM_QSTR(MP_QSTR_transform), MP_ROM_PTR(&POLYGON_transform_obj) },
// Primitives
{ MP_ROM_QSTR(MP_QSTR_rectangle), MP_ROM_PTR(&POLYGON_rectangle_obj) },
{ MP_ROM_QSTR(MP_QSTR_regular), MP_ROM_PTR(&POLYGON_regular_obj) },
{ MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&POLYGON_path_obj) },
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&POLYGON_circle_obj) },
{ MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&POLYGON_arc_obj) },
};
static MP_DEFINE_CONST_DICT(POLYGON_locals_dict, POLYGON_locals_dict_table);
#ifdef MP_DEFINE_CONST_OBJ_TYPE
MP_DEFINE_CONST_OBJ_TYPE(
POLYGON_type,
MP_QSTR_polygon,
MP_TYPE_FLAG_NONE,
make_new, POLYGON_make_new,
print, POLYGON_print,
iter, PATH_getiter,
iter, POLYGON_getiter,
locals_dict, (mp_obj_dict_t*)&POLYGON_locals_dict
);
/* Transform */
static MP_DEFINE_CONST_FUN_OBJ_3(TRANSFORM_rotate_obj, TRANSFORM_rotate);
static MP_DEFINE_CONST_FUN_OBJ_3(TRANSFORM_translate_obj, TRANSFORM_translate);
static MP_DEFINE_CONST_FUN_OBJ_1(TRANSFORM_reset_obj, TRANSFORM_reset);
static const mp_rom_map_elem_t TRANSFORM_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_rotate), MP_ROM_PTR(&TRANSFORM_rotate_obj) },
{ MP_ROM_QSTR(MP_QSTR_translate), MP_ROM_PTR(&TRANSFORM_translate_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&TRANSFORM_reset_obj) },
};
static MP_DEFINE_CONST_DICT(TRANSFORM_locals_dict, TRANSFORM_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
REGULAR_POLYGON_type,
MP_QSTR_regular_polygon,
TRANSFORM_type,
MP_QSTR_Transform,
MP_TYPE_FLAG_NONE,
make_new, REGULAR_POLYGON_make_new,
locals_dict, (mp_obj_dict_t*)&POLYGON_locals_dict
make_new, TRANSFORM_make_new,
locals_dict, (mp_obj_dict_t*)&TRANSFORM_locals_dict
);
MP_DEFINE_CONST_OBJ_TYPE(
RECTANGLE_type,
MP_QSTR_rectangle,
MP_TYPE_FLAG_NONE,
make_new, RECTANGLE_make_new,
locals_dict, (mp_obj_dict_t*)&POLYGON_locals_dict
);
#else
const mp_obj_type_t POLYGON_type = {
{ &mp_type_type },
.name = MP_QSTR_polygon,
.make_new = POLYGON_make_new,
.print = POLYGON_print,
.iter = PATH_getiter,
.locals_dict = (mp_obj_dict_t*)&POLYGON_locals_dict,
};
const mp_obj_type_t REGULAR_POLYGON_type = {
{ &mp_type_type },
.name = MP_QSTR_regular_polygon,
.make_new = REGULAR_POLYGON_make_new,
.locals_dict = (mp_obj_dict_t*)&POLYGON_locals_dict,
};
const mp_obj_type_t RECTANGLE_type = {
{ &mp_type_type },
.name = MP_QSTR_rectangle,
.make_new = RECTANGLE_make_new,
.locals_dict = (mp_obj_dict_t*)&POLYGON_locals_dict,
};
#endif
/* PicoVector */
@ -68,25 +81,24 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_text_obj, 4, VECTOR_text);
static MP_DEFINE_CONST_FUN_OBJ_3(VECTOR_set_font_obj, VECTOR_set_font);
static MP_DEFINE_CONST_FUN_OBJ_2(VECTOR_set_font_size_obj, VECTOR_set_font_size);
static MP_DEFINE_CONST_FUN_OBJ_2(VECTOR_set_antialiasing_obj, VECTOR_set_antialiasing);
static MP_DEFINE_CONST_FUN_OBJ_2(VECTOR_set_transform_obj, VECTOR_set_transform);
static MP_DEFINE_CONST_FUN_OBJ_2(VECTOR_set_clip_obj, VECTOR_set_clip);
static MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_draw_obj, 2, VECTOR_draw);
static MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_rotate_obj, 3, VECTOR_rotate);
static MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_translate_obj, 4, VECTOR_translate);
static MP_DEFINE_CONST_FUN_OBJ_2(VECTOR_draw_obj, VECTOR_draw);
static const mp_rom_map_elem_t VECTOR_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&VECTOR_set_font_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_font_size), MP_ROM_PTR(&VECTOR_set_font_size_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_antialiasing), MP_ROM_PTR(&VECTOR_set_antialiasing_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_transform), MP_ROM_PTR(&VECTOR_set_transform_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_clip), MP_ROM_PTR(&VECTOR_set_clip_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&VECTOR_text_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw), MP_ROM_PTR(&VECTOR_draw_obj) },
{ MP_ROM_QSTR(MP_QSTR_rotate), MP_ROM_PTR(&VECTOR_rotate_obj) },
{ MP_ROM_QSTR(MP_QSTR_translate), MP_ROM_PTR(&VECTOR_translate_obj) },
};
static MP_DEFINE_CONST_DICT(VECTOR_locals_dict, VECTOR_locals_dict_table);
#ifdef MP_DEFINE_CONST_OBJ_TYPE
MP_DEFINE_CONST_OBJ_TYPE(
VECTOR_type,
MP_QSTR_picovector,
@ -94,14 +106,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
make_new, VECTOR_make_new,
locals_dict, (mp_obj_dict_t*)&VECTOR_locals_dict
);
#else
const mp_obj_type_t VECTOR_type = {
{ &mp_type_type },
.name = MP_QSTR_picovector,
.make_new = VECTOR_make_new,
.locals_dict = (mp_obj_dict_t*)&VECTOR_locals_dict,
};
#endif
/* Module */
@ -109,8 +113,7 @@ static const mp_map_elem_t VECTOR_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picovector) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PicoVector), (mp_obj_t)&VECTOR_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Polygon), (mp_obj_t)&POLYGON_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RegularPolygon), (mp_obj_t)&REGULAR_POLYGON_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Rectangle), (mp_obj_t)&RECTANGLE_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Transform), (mp_obj_t)&TRANSFORM_type },
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_NONE), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_X4), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_ANTIALIAS_X16), MP_ROM_INT(2) },
@ -125,8 +128,4 @@ const mp_obj_module_t VECTOR_user_cmodule = {
.globals = (mp_obj_dict_t*)&mp_module_VECTOR_globals,
};
#if MICROPY_VERSION <= 70144
MP_REGISTER_MODULE(MP_QSTR_picovector, VECTOR_user_cmodule, MODULE_PICOVECTOR_ENABLED);
#else
MP_REGISTER_MODULE(MP_QSTR_picovector, VECTOR_user_cmodule);
#endif
MP_REGISTER_MODULE(MP_QSTR_picovector, VECTOR_user_cmodule);

Wyświetl plik

@ -25,10 +25,15 @@ typedef struct _VECTOR_obj_t {
PicoVector *vector;
} _VECTOR_obj_t;
typedef struct _PATH_obj_t {
typedef struct _TRANSFORM_obj_t {
mp_obj_base_t base;
pp_path_t *path;
} _PATH_obj_t;
pp_mat3_t transform;
} _TRANSFORM_obj_t;
typedef struct _POLY_obj_t {
mp_obj_base_t base;
pp_poly_t *poly;
} _POLY_obj_t;
void __printf_debug_flush() {
for(auto i = 0u; i < 10; i++) {
@ -54,20 +59,22 @@ void af_debug(const char *fmt, ...) {
void *af_malloc(size_t size) {
//mp_printf(&mp_plat_print, "af_malloc %lu\n", size);
//__printf_debug_flush();
void *addr = m_tracked_calloc(sizeof(uint8_t), size);
//void *addr = m_tracked_calloc(sizeof(uint8_t), size);
void *addr = m_malloc(size);
//mp_printf(&mp_plat_print, "addr %lu\n", addr);
//__printf_debug_flush();
return addr;
}
void *af_realloc(void *p, size_t size) {
return NULL;
return m_realloc(p, size);
}
void af_free(void *p) {
//mp_printf(&mp_plat_print, "af_free\n");
//__printf_debug_flush();
m_tracked_free(p);
//m_tracked_free(p);
m_free(p);
}
void* fileio_open(const char *filename) {
@ -157,89 +164,25 @@ static const std::string_view mp_obj_to_string_r(const mp_obj_t &obj) {
/* POLYGON */
mp_obj_t RECTANGLE_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_x, ARG_y, ARG_w, ARG_h };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
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);
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;
}
mp_obj_t REGULAR_POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_x, ARG_y, ARG_sides, ARG_radius, ARG_rotation };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sides, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_rotation, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
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);
Point origin(args[ARG_x].u_int, args[ARG_y].u_int);
unsigned int sides = args[ARG_sides].u_int;
float radius = mp_obj_get_float(args[ARG_radius].u_obj);
float rotation = 0.0f;
if (args[ARG_rotation].u_obj != mp_const_none) {
rotation = mp_obj_get_float(args[ARG_rotation].u_obj);
rotation *= (M_PI / 180.0f);
}
picovector_point_type o_x = mp_picovector_get_point_type(args[ARG_x].u_obj);
picovector_point_type o_y = mp_picovector_get_point_type(args[ARG_y].u_obj);
float angle = (360.0f / sides) * (M_PI / 180.0f);
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;
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;
}
mp_obj_t POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_PATH_obj_t *self = mp_obj_malloc_with_finaliser(_PATH_obj_t, &POLYGON_type);
_POLY_obj_t *self = mp_obj_malloc_with_finaliser(_POLY_obj_t, &POLYGON_type);
self->poly = pp_poly_new();
return self;
}
size_t num_points = n_args;
const mp_obj_t *points = all_args;
mp_obj_t POLYGON__del__(mp_obj_t self_in) {
_POLY_obj_t *self = MP_OBJ_TO_PTR2(self_in, _POLY_obj_t);
pp_poly_free(self->poly);
return mp_const_none;
}
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);
mp_obj_t POLYGON_path(size_t n_args, const mp_obj_t *all_args) {
_POLY_obj_t *self = MP_OBJ_TO_PTR2(all_args[0], _POLY_obj_t);
size_t num_points = n_args - 1;
const mp_obj_t *points = all_args + 1;
pp_path_t *path = pp_poly_add_path(self->poly);
if(num_points < 3) mp_raise_ValueError("Polygon: At least 3 points required.");
@ -252,28 +195,179 @@ 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");
pp_path_add_point(self->path, {
pp_path_add_point(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 mp_const_none;
}
mp_obj_t POLYGON_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_w, ARG_h, ARG_corners, ARG_stroke };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_w, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_h, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_corners, MP_ARG_OBJ, { .u_obj = mp_const_none }},
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
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);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
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);
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
picovector_point_type r1 = 0;
picovector_point_type r2 = 0;
picovector_point_type r3 = 0;
picovector_point_type r4 = 0;
if(mp_obj_is_exact_type(args[ARG_corners].u_obj, &mp_type_tuple)){
mp_obj_tuple_t *t_corners = MP_OBJ_TO_PTR2(args[ARG_corners].u_obj, mp_obj_tuple_t);
if(t_corners->len != 4) mp_raise_ValueError("Corners must have r1, r2, r3, r4");
r1 = mp_picovector_get_point_type(t_corners->items[0]);
r2 = mp_picovector_get_point_type(t_corners->items[1]);
r3 = mp_picovector_get_point_type(t_corners->items[2]);
r4 = mp_picovector_get_point_type(t_corners->items[3]);
}
pp_poly_merge(self->poly, ppp_rect({
x, y, w, h,
s,
r1, r2, r3, r4
}));
return self;
}
mp_obj_t POLYGON_regular(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_sides, ARG_radius, ARG_stroke };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sides, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
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);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
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 r = mp_picovector_get_point_type(args[ARG_radius].u_obj);
int e = args[ARG_sides].u_int;
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
pp_poly_merge(self->poly, ppp_regular({
x, y,
r,
e,
s
}));
return self;
}
mp_obj_t POLYGON_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_radius, ARG_stroke };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
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);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
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 r = mp_picovector_get_point_type(args[ARG_radius].u_obj);
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
pp_poly_merge(self->poly, ppp_circle({
x, y,
r,
s
}));
return self;
}
mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_radius, ARG_from, ARG_to, ARG_stroke };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_from, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_to, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
};
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);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
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 r = mp_picovector_get_point_type(args[ARG_radius].u_obj);
picovector_point_type f = mp_picovector_get_point_type(args[ARG_from].u_obj);
picovector_point_type t = mp_picovector_get_point_type(args[ARG_to].u_obj);
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
pp_poly_merge(self->poly, ppp_arc({
x, y,
r,
s,
f,
t
}));
return self;
}
// Utility functions
mp_obj_t POLYGON_centroid(mp_obj_t self_in) {
_PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(self_in, _POLY_obj_t);
PP_COORD_TYPE sum_x = (PP_COORD_TYPE)0;
PP_COORD_TYPE sum_y = (PP_COORD_TYPE)0;
for(auto i = 0; i < self->path->count; i++) {
sum_x += self->path->points[i].x;
sum_y += self->path->points[i].y;
// TODO: Maybe include in pretty-poly?
// Might need to handle multiple paths
pp_path_t *path = self->poly->paths;
for(auto i = 0; i < path->count; i++) {
sum_x += path->points[i].x;
sum_y += path->points[i].y;
}
sum_x /= (float)self->path->count;
sum_y /= (float)self->path->count;
sum_x /= (float)path->count;
sum_y /= (float)path->count;
mp_obj_t tuple[2];
tuple[0] = mp_picovector_set_point_type((int)(sum_x));
@ -283,9 +377,9 @@ 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);
_POLY_obj_t *self = MP_OBJ_TO_PTR2(self_in, _POLY_obj_t);
pp_rect_t bounds = pp_path_bounds(self->path);
pp_rect_t bounds = pp_poly_bounds(self->poly);
mp_obj_t tuple[4];
tuple[0] = mp_picovector_set_point_type((int)(bounds.x));
@ -296,65 +390,129 @@ mp_obj_t POLYGON_bounds(mp_obj_t self_in) {
return mp_obj_new_tuple(4, tuple);
}
void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
_PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t);
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_print_str(print, ", bounds = ");
mp_obj_print_helper(print, mp_picovector_set_point_type(bounds.x), PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_picovector_set_point_type(bounds.y), PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_picovector_set_point_type(bounds.w), PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_picovector_set_point_type(bounds.h), PRINT_REPR);
mp_print_str(print, ")");
void _pp_path_transform(pp_path_t *path, pp_mat3_t *transform) {
for (int i = 0; i < path->count; i++) {
path->points[i] = pp_point_transform(&path->points[i], transform);
}
}
mp_obj_t POLYGON__del__(mp_obj_t self_in) {
_PATH_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PATH_obj_t);
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
void _pp_poly_transform(pp_poly_t *poly, pp_mat3_t *transform) {
pp_path_t *path = poly->paths;
while(path) {
_pp_path_transform(path, transform);
path = path->next;
}
}
mp_obj_t POLYGON_transform(mp_obj_t self_in, mp_obj_t transform_in) {
_POLY_obj_t *self = MP_OBJ_TO_PTR2(self_in, _POLY_obj_t);
if (!MP_OBJ_IS_TYPE(transform_in, &TRANSFORM_type)) mp_raise_ValueError("Transform required");
_TRANSFORM_obj_t *transform = (_TRANSFORM_obj_t *)MP_OBJ_TO_PTR(transform_in);
_pp_poly_transform(self->poly, &transform->transform);
return mp_const_none;
}
void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
_POLY_obj_t *self = MP_OBJ_TO_PTR2(self_in, _POLY_obj_t);
(void)self;
// TODO: Make print better
mp_print_str(print, "Polygon();");
}
typedef struct _mp_obj_polygon_it_t {
mp_obj_base_t base;
mp_fun_1_t iternext;
mp_obj_t polygon;
int cur;
pp_path_t *cur;
} mp_obj_polygon_it_t;
static mp_obj_t py_path_it_iternext(mp_obj_t self_in) {
static mp_obj_t POLYGON_it_iternext(mp_obj_t self_in) {
mp_obj_polygon_it_t *self = MP_OBJ_TO_PTR2(self_in, mp_obj_polygon_it_t);
_PATH_obj_t *path = MP_OBJ_TO_PTR2(self->polygon, _PATH_obj_t);
//_POLY_obj_t *poly = MP_OBJ_TO_PTR2(self->polygon, _POLY_obj_t);
//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) 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));
mp_obj_t tuple[self->cur->count];
for (auto i = 0; i < self->cur->count; i++) {
mp_obj_t t_point[2] = {
mp_picovector_set_point_type((int)(self->cur->points[i].x)),
mp_picovector_set_point_type((int)(self->cur->points[i].y))
};
tuple[i] = mp_obj_new_tuple(2, t_point);
}
self->cur++;
return mp_obj_new_tuple(2, tuple);
self->cur = self->cur->next;
return mp_obj_new_tuple(self->cur->count, tuple);
}
mp_obj_t PATH_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_t POLYGON_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_polygon_it_t *o = (mp_obj_polygon_it_t *)iter_buf;
o->base.type = &mp_type_polymorph_iter;
o->iternext = py_path_it_iternext;
o->iternext = POLYGON_it_iternext;
o->polygon = o_in;
o->cur = 0;
o->cur = MP_OBJ_TO_PTR2(o_in, _POLY_obj_t)->poly->paths;
return MP_OBJ_FROM_PTR(o);
}
/* TRANSFORM */
mp_obj_t TRANSFORM_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
_TRANSFORM_obj_t *self = m_new_obj(_TRANSFORM_obj_t);
self->base.type = &TRANSFORM_type;
self->transform = pp_mat3_identity();
return self;
}
mp_obj_t TRANSFORM_rotate(mp_obj_t self_in, mp_obj_t angle_in, mp_obj_t origin_in) {
_TRANSFORM_obj_t *transform = MP_OBJ_TO_PTR2(self_in, _TRANSFORM_obj_t);
float angle = mp_obj_get_float(angle_in);
if(mp_obj_is_exact_type(origin_in, &mp_type_tuple)) {
mp_obj_tuple_t *t_origin = MP_OBJ_TO_PTR2(origin_in, mp_obj_tuple_t);
if(t_origin->len != 2) mp_raise_ValueError("Origin Tuple must have X, Y");
picovector_point_type x = mp_picovector_get_point_type(t_origin->items[0]);
picovector_point_type y = mp_picovector_get_point_type(t_origin->items[1]);
pp_mat3_translate(&transform->transform, x, y);
pp_mat3_rotate(&transform->transform, angle);
pp_mat3_translate(&transform->transform, -x, -y);
} else {
pp_mat3_rotate(&transform->transform, angle);
}
return mp_const_none;
}
mp_obj_t TRANSFORM_translate(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) {
_TRANSFORM_obj_t *transform = MP_OBJ_TO_PTR2(self_in, _TRANSFORM_obj_t);
picovector_point_type o_x = mp_picovector_get_point_type(x_in);
picovector_point_type o_y = mp_picovector_get_point_type(y_in);
pp_mat3_translate(&transform->transform, o_x, o_y);
return mp_const_none;
}
mp_obj_t TRANSFORM_reset(mp_obj_t self_in) {
_TRANSFORM_obj_t *transform = MP_OBJ_TO_PTR2(self_in, _TRANSFORM_obj_t);
transform->transform = pp_mat3_identity();
return mp_const_none;
}
/* VECTOR */
mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@ -383,6 +541,24 @@ mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
return self;
}
mp_obj_t VECTOR_set_transform(mp_obj_t self_in, mp_obj_t transform_in) {
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VECTOR_obj_t);
(void)self;
if(transform_in == mp_const_none) {
pp_mat3_t* old = pp_transform(NULL);
(void)old; // TODO: Return old transform?
} else if MP_OBJ_IS_TYPE(transform_in, &TRANSFORM_type) {
_TRANSFORM_obj_t *transform = (_TRANSFORM_obj_t *)MP_OBJ_TO_PTR(transform_in);
pp_mat3_t* old = pp_transform(&transform->transform);
(void)old;
} else {
// TODO: ValueError?
}
return mp_const_none;
}
mp_obj_t VECTOR_set_font(mp_obj_t self_in, mp_obj_t font, mp_obj_t size) {
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VECTOR_obj_t);
(void)self;
@ -413,6 +589,31 @@ mp_obj_t VECTOR_set_font_size(mp_obj_t self_in, mp_obj_t size) {
return mp_const_none;
}
mp_obj_t VECTOR_set_clip(mp_obj_t self_in, mp_obj_t clip_in) {
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VECTOR_obj_t);
(void)self;
picovector_point_type x = self->vector->graphics->bounds.x;
picovector_point_type y = self->vector->graphics->bounds.y;
picovector_point_type w = self->vector->graphics->bounds.w;
picovector_point_type h = self->vector->graphics->bounds.h;
if(mp_obj_is_exact_type(clip_in, &mp_type_tuple)){
mp_obj_tuple_t *t_clip = MP_OBJ_TO_PTR2(clip_in, mp_obj_tuple_t);
if(t_clip->len != 4) mp_raise_ValueError("Clip must have x, y, w, h");
x = mp_picovector_get_point_type(t_clip->items[0]);
y = mp_picovector_get_point_type(t_clip->items[1]);
w = mp_picovector_get_point_type(t_clip->items[2]);
h = mp_picovector_get_point_type(t_clip->items[3]);
}
pp_clip(x, y, w, h);
return mp_const_none;
}
mp_obj_t VECTOR_set_antialiasing(mp_obj_t self_in, mp_obj_t aa) {
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VECTOR_obj_t);
@ -465,94 +666,15 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
return mp_const_none;
}
mp_obj_t VECTOR_rotate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_polygon, ARG_angle, ARG_origin_x, ARG_origin_y };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_polygon, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_angle, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_origin_x, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_origin_y, MP_ARG_INT, {.u_int = 0} }
};
mp_obj_t VECTOR_draw(mp_obj_t self_in, mp_obj_t poly_in) {
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(self_in, _VECTOR_obj_t);
(void)self;
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(poly_in, &POLYGON_type)) mp_raise_TypeError("draw: Polygon required.");
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _VECTOR_obj_t);
_POLY_obj_t *poly = MP_OBJ_TO_PTR2(poly_in, _POLY_obj_t);
if(!MP_OBJ_IS_TYPE(args[ARG_polygon].u_obj, &POLYGON_type)) mp_raise_TypeError("rotate: polygon required");
_PATH_obj_t *poly = MP_OBJ_TO_PTR2(args[ARG_polygon].u_obj, _PATH_obj_t);
pp_point_t origin = {(PP_COORD_TYPE)args[ARG_origin_x].u_int, (PP_COORD_TYPE)args[ARG_origin_y].u_int};
float angle = mp_obj_get_float(args[ARG_angle].u_obj);
self->vector->rotate(poly->path, origin, angle);
return mp_const_none;
}
mp_obj_t VECTOR_translate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_polygon, ARG_x, ARG_y };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_polygon, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_y, MP_ARG_INT, {.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);
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _VECTOR_obj_t);
if(!MP_OBJ_IS_TYPE(args[ARG_polygon].u_obj, &POLYGON_type)) mp_raise_TypeError("rotate: polygon required");
_PATH_obj_t *poly = MP_OBJ_TO_PTR2(args[ARG_polygon].u_obj, _PATH_obj_t);
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);
return mp_const_none;
}
mp_obj_t VECTOR_draw(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
size_t num_polygons = n_args - 1;
const mp_obj_t *polygons = pos_args + 1;
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], _VECTOR_obj_t);
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);
pp_path_add_points(path, poly->path->points, poly->path->count);
}
self->vector->draw(group);
pp_poly_free(group);
pp_render(poly->poly);
return mp_const_none;
}

Wyświetl plik

@ -3,26 +3,42 @@
extern const mp_obj_type_t VECTOR_type;
extern const mp_obj_type_t POLYGON_type;
extern const mp_obj_type_t REGULAR_POLYGON_type;
extern const mp_obj_type_t RECTANGLE_type;
extern const mp_obj_type_t TRANSFORM_type;
/* Polygon */
extern mp_obj_t POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t REGULAR_POLYGON_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t RECTANGLE_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t POLYGON_path(size_t n_args, const mp_obj_t *all_args);
extern mp_obj_t POLYGON_regular(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
extern mp_obj_t POLYGON_centroid(mp_obj_t self_in);
extern mp_obj_t POLYGON_bounds(mp_obj_t self_in);
extern mp_obj_t PATH_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf);
extern mp_obj_t POLYGON_transform(mp_obj_t self_in, mp_obj_t transform_in);
extern mp_obj_t POLYGON_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf);
extern mp_obj_t POLYGON__del__(mp_obj_t self_in);
/* Transform */
extern mp_obj_t TRANSFORM_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t TRANSFORM_rotate(mp_obj_t self_in, mp_obj_t angle_in, mp_obj_t origin_in);
extern mp_obj_t TRANSFORM_translate(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in);
extern mp_obj_t TRANSFORM_reset(mp_obj_t self_in);
/* Vector */
extern mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
extern mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t VECTOR_set_font(mp_obj_t self_in, mp_obj_t font, mp_obj_t size);
extern mp_obj_t VECTOR_set_font_size(mp_obj_t self_in, mp_obj_t size);
extern mp_obj_t VECTOR_set_antialiasing(mp_obj_t self_in, mp_obj_t aa);
extern mp_obj_t VECTOR_set_transform(mp_obj_t self_in, mp_obj_t transform_in);
extern mp_obj_t VECTOR_set_clip(mp_obj_t self_in, mp_obj_t clip_in);
extern mp_obj_t VECTOR_draw(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t VECTOR_draw(mp_obj_t self_in, mp_obj_t poly_in);
extern mp_obj_t VECTOR_rotate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t VECTOR_translate(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);