kopia lustrzana https://github.com/pimoroni/pimoroni-pico
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 drawingpull/1019/head
rodzic
eae591ae3c
commit
75a01b2fb8
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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)®ULAR_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);
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
Ładowanie…
Reference in New Issue