PicoGraphics: Experimental Pretty Poly bring-up.
This commit is contained in:
parent
57042bfed3
commit
cc7219b44a
|
@ -1,4 +1,5 @@
|
|||
#include "pico_graphics.hpp"
|
||||
#include "pretty-poly.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
|
@ -16,6 +17,13 @@ namespace pimoroni {
|
|||
|
||||
int PicoGraphics::get_palette_size() {return 0;}
|
||||
RGB* PicoGraphics::get_palette() {return nullptr;}
|
||||
size_t PicoGraphics::pretty_poly_buffer_size() {
|
||||
return pretty_poly::buffer_size();
|
||||
}
|
||||
|
||||
void PicoGraphics::pretty_poly_init(void *mem) {
|
||||
pretty_poly::init(mem);
|
||||
}
|
||||
|
||||
void PicoGraphics::set_dimensions(int width, int height) {
|
||||
bounds = clip = {0, 0, width, height};
|
||||
|
@ -241,7 +249,46 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
void PicoGraphics::polygon(std::vector<pretty_poly::contour_t<int>> contours) {
|
||||
set_options([this](const pretty_poly::tile_t &tile) -> void {
|
||||
for(auto y = 0; y < tile.bounds.h; y++) {
|
||||
for(auto x = 0; x < tile.bounds.w; x++) {
|
||||
uint8_t alpha = tile.get_value(x, y);
|
||||
if (alpha > 0) {
|
||||
pixel({x + tile.bounds.x, y + tile.bounds.y});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, pretty_poly::NONE, {0, 0, bounds.w, bounds.h});
|
||||
|
||||
pretty_poly::draw_polygon<int>(contours);
|
||||
}
|
||||
|
||||
void PicoGraphics::polygon(const std::vector<Point> &points) {
|
||||
|
||||
pretty_poly::contour_t<int> contour(new pretty_poly::point_t<int>[points.size()], points.size());
|
||||
|
||||
for(auto i = 0; i < points.size(); i++) {
|
||||
contour.points[i] = pretty_poly::point_t<int>(points[i].x, points[i].y);
|
||||
}
|
||||
|
||||
set_options([this](const pretty_poly::tile_t &tile) -> void {
|
||||
for(auto y = 0; y < tile.bounds.h; y++) {
|
||||
for(auto x = 0; x < tile.bounds.w; x++) {
|
||||
uint8_t alpha = tile.get_value(x, y);
|
||||
if (alpha > 0) {
|
||||
pixel({x + tile.bounds.x, y + tile.bounds.y});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, pretty_poly::NONE, {0, 0, bounds.w, bounds.h});
|
||||
|
||||
std::vector<pretty_poly::contour_t<int>> contours;
|
||||
contours.push_back(contour);
|
||||
|
||||
pretty_poly::draw_polygon(contours);
|
||||
|
||||
/*
|
||||
static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering
|
||||
|
||||
int32_t miny = points[0].y, maxy = points[0].y;
|
||||
|
@ -285,6 +332,7 @@ namespace pimoroni {
|
|||
pixel_span(Point(nodes[i], p.y), nodes[i + 1] - nodes[i] + 1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void PicoGraphics::thick_line(Point p1, Point p2, uint thickness) {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
|
||||
#include "pretty-poly-types.hpp"
|
||||
|
||||
// A tiny graphics library for our Pico products
|
||||
// supports:
|
||||
// - 16-bit (565) RGB
|
||||
|
@ -260,6 +262,9 @@ namespace pimoroni {
|
|||
set_font(&font6);
|
||||
};
|
||||
|
||||
size_t pretty_poly_buffer_size();
|
||||
void pretty_poly_init(void *mem);
|
||||
|
||||
virtual void set_pen(uint c) = 0;
|
||||
virtual void set_pen(uint8_t r, uint8_t g, uint8_t b) = 0;
|
||||
virtual void set_pixel(const Point &p) = 0;
|
||||
|
@ -301,6 +306,7 @@ namespace pimoroni {
|
|||
void text(const std::string_view &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1, bool fixed_width = false);
|
||||
int32_t measure_text(const std::string_view &t, float s = 2.0f, uint8_t letter_spacing = 1, bool fixed_width = false);
|
||||
void polygon(const std::vector<Point> &points);
|
||||
void polygon(std::vector<pretty_poly::contour_t<int>> contours);
|
||||
void triangle(Point p1, Point p2, Point p3);
|
||||
void line(Point p1, Point p2);
|
||||
void thick_line(Point p1, Point p2, uint thickness);
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <math.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef PP_DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...)
|
||||
#endif
|
||||
|
||||
namespace pretty_poly {
|
||||
|
||||
enum antialias_t {NONE = 0, X4 = 1, X16 = 2};
|
||||
|
||||
// 3x3 matrix for coordinate transformations
|
||||
struct mat3_t {
|
||||
float v00, v10, v20, v01, v11, v21, v02, v12, v22 = 0.0f;
|
||||
mat3_t() = default;
|
||||
mat3_t(const mat3_t &m) = default;
|
||||
inline mat3_t& operator*= (const mat3_t &m) {
|
||||
float r00 = this->v00 * m.v00 + this->v01 * m.v10 + this->v02 * m.v20;
|
||||
float r01 = this->v00 * m.v01 + this->v01 * m.v11 + this->v02 * m.v21;
|
||||
float r02 = this->v00 * m.v02 + this->v01 * m.v12 + this->v02 * m.v22;
|
||||
float r10 = this->v10 * m.v00 + this->v11 * m.v10 + this->v12 * m.v20;
|
||||
float r11 = this->v10 * m.v01 + this->v11 * m.v11 + this->v12 * m.v21;
|
||||
float r12 = this->v10 * m.v02 + this->v11 * m.v12 + this->v12 * m.v22;
|
||||
float r20 = this->v20 * m.v00 + this->v21 * m.v10 + this->v22 * m.v20;
|
||||
float r21 = this->v20 * m.v01 + this->v21 * m.v11 + this->v22 * m.v21;
|
||||
float r22 = this->v20 * m.v02 + this->v21 * m.v12 + this->v22 * m.v22;
|
||||
this->v00 = r00; this->v01 = r01; this->v02 = r02;
|
||||
this->v10 = r10; this->v11 = r11; this->v12 = r12;
|
||||
this->v20 = r20; this->v21 = r21; this->v22 = r22;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static mat3_t identity() {mat3_t m; m.v00 = m.v11 = m.v22 = 1.0f; return m;}
|
||||
static mat3_t rotation(float a) {
|
||||
float c = cosf(a), s = sinf(a); mat3_t r = mat3_t::identity();
|
||||
r.v00 = c; r.v01 = s; r.v10 = -s; r.v11 = c; return r;}
|
||||
static mat3_t translation(float x, float y) {
|
||||
mat3_t r = mat3_t::identity(); r.v02 = x; r.v12 = y; return r;}
|
||||
static mat3_t scale(float x, float y) {
|
||||
mat3_t r = mat3_t::identity(); r.v00 = x; r.v11 = y; return r;}
|
||||
};
|
||||
|
||||
// point type for contour points
|
||||
template<typename T = int>
|
||||
struct __attribute__ ((packed)) point_t {
|
||||
T x, y;
|
||||
point_t(T x, T y) : x(x), y(y) {}
|
||||
point_t() : x(0), y(0) {}
|
||||
inline point_t& operator-= (const point_t &a) {x -= a.x; y -= a.y; return *this;}
|
||||
inline point_t& operator+= (const point_t &a) {x += a.x; y += a.y; return *this;}
|
||||
inline point_t& operator*= (const float a) {x *= a; y *= a; return *this;}
|
||||
inline point_t& operator*= (const mat3_t &a) {this->transform(a); return *this;}
|
||||
inline point_t& operator/= (const float a) {x /= a; y /= a; return *this;}
|
||||
inline point_t& operator/= (const point_t &a) {x /= a.x; y /= a.y; return *this;}
|
||||
void transform(const mat3_t &m) {
|
||||
this->x = (m.v00 * float(this->x) + m.v01 * float(this->y) + m.v02);
|
||||
this->y = (m.v10 * float(this->x) + m.v11 * float(this->y) + m.v12);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T> inline point_t<T> operator- (point_t<T> lhs, const point_t<T> &rhs) { lhs -= rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator- (const point_t<T> &rhs) { return point_t<T>(-rhs.x, -rhs.y); }
|
||||
template<typename T> inline point_t<T> operator+ (point_t<T> lhs, const point_t<T> &rhs) { lhs += rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator* (point_t<T> lhs, const float rhs) { lhs *= rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator* (point_t<T> lhs, const point_t<T> &rhs) { lhs *= rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator* (point_t<T> lhs, const mat3_t &rhs) { lhs *= rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator/ (point_t<T> lhs, const float rhs) { lhs /= rhs; return lhs; }
|
||||
template<typename T> inline point_t<T> operator/ (point_t<T> lhs, const point_t<T> &rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; }
|
||||
|
||||
|
||||
// rect type for bounds and clipping rectangles
|
||||
struct rect_t {
|
||||
int x, y, w, h;
|
||||
rect_t() : x(0), y(0), w(0), h(0) {}
|
||||
rect_t(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {}
|
||||
bool empty() const {return this->w == 0 && this->h == 0;}
|
||||
rect_t intersection(const rect_t &c) {
|
||||
return rect_t(max(this->x, c.x), max(this->y, c.y),
|
||||
max(0, min(this->x + this->w, c.x + c.w) - max(this->x, c.x)),
|
||||
max(0, min(this->y + this->h, c.y + c.h) - max(this->y, c.y)));
|
||||
}
|
||||
rect_t merge(const rect_t &c) {
|
||||
return rect_t(min(this->x, c.x), min(this->y, c.y),
|
||||
max(this->x + this->w, c.x + c.w) - min(this->x, c.x),
|
||||
max(this->y + this->h, c.y + c.h) - min(this->y, c.y));
|
||||
}
|
||||
};
|
||||
|
||||
struct tile_t {
|
||||
rect_t bounds;
|
||||
unsigned stride;
|
||||
uint8_t *data;
|
||||
|
||||
tile_t() {};
|
||||
|
||||
int get_value(int x, int y) const {
|
||||
return this->data[x + y * this->stride];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct contour_t {
|
||||
point_t<T> *points;
|
||||
unsigned count;
|
||||
|
||||
contour_t() {}
|
||||
contour_t(vector<point_t<T>> v) : points(v.data()), count(v.size()) {};
|
||||
contour_t(point_t<T> *points, unsigned count) : points(points), count(count) {};
|
||||
|
||||
rect_t bounds() {
|
||||
T minx = this->points[0].x, maxx = minx;
|
||||
T miny = this->points[0].y, maxy = miny;
|
||||
for(auto i = 1; i < this->count; i++) {
|
||||
minx = min(minx, this->points[i].x);
|
||||
miny = min(miny, this->points[i].y);
|
||||
maxx = max(maxx, this->points[i].x);
|
||||
maxy = max(maxy, this->points[i].y);
|
||||
}
|
||||
return rect_t(minx, miny, maxx - minx, maxy - miny);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef PP_DEBUG
|
||||
#define debug(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define debug(...)
|
||||
#endif
|
||||
|
||||
namespace pretty_poly {
|
||||
|
||||
//typedef void (*tile_callback_t)(const tile_t &tile);
|
||||
|
||||
typedef std::function<void(const tile_t &tile)> tile_callback_t;
|
||||
|
||||
// buffer that each tile is rendered into before callback
|
||||
constexpr unsigned tile_buffer_size = 1024;
|
||||
//uint8_t tile_buffer[tile_buffer_size];
|
||||
uint8_t *tile_buffer;
|
||||
|
||||
// polygon node buffer handles at most 16 line intersections per scanline
|
||||
// is this enough for cjk/emoji? (requires a 2kB buffer)
|
||||
constexpr unsigned node_buffer_size = 32;
|
||||
|
||||
//int nodes[node_buffer_size][32];
|
||||
//unsigned node_counts[node_buffer_size];
|
||||
|
||||
int (*nodes)[32];
|
||||
unsigned *node_counts;
|
||||
|
||||
// default tile bounds to X1 antialiasing
|
||||
rect_t tile_bounds(0, 0, tile_buffer_size / node_buffer_size, node_buffer_size);
|
||||
|
||||
// user settings
|
||||
namespace settings {
|
||||
rect_t clip(0, 0, 320, 240);
|
||||
tile_callback_t callback;
|
||||
antialias_t antialias = antialias_t::NONE;
|
||||
}
|
||||
|
||||
size_t buffer_size() {
|
||||
return tile_buffer_size + (node_buffer_size * sizeof(unsigned)) + (node_buffer_size * 32 * sizeof(int));
|
||||
}
|
||||
|
||||
void init(void *memory) {
|
||||
tile_buffer = new(memory) uint8_t[tile_buffer_size];
|
||||
node_counts = new(memory + tile_buffer_size) unsigned[node_buffer_size];
|
||||
nodes = new(memory + tile_buffer_size + (node_buffer_size * sizeof(unsigned))) int[node_buffer_size][32];
|
||||
}
|
||||
|
||||
void set_options(tile_callback_t callback, antialias_t antialias, rect_t clip) {
|
||||
settings::callback = callback;
|
||||
settings::antialias = antialias;
|
||||
settings::clip = clip;
|
||||
|
||||
// recalculate the tile size for rendering based on antialiasing level
|
||||
int tile_height = node_buffer_size >> antialias;
|
||||
tile_bounds = rect_t(0, 0, tile_buffer_size / tile_height, tile_height);
|
||||
}
|
||||
|
||||
// dy step (returns 1, 0, or -1 if the supplied value is > 0, == 0, < 0)
|
||||
__attribute__((always_inline)) int sign(int v) {
|
||||
// assumes 32-bit int/unsigned
|
||||
return ((unsigned)-v >> 31) - ((unsigned)v >> 31);
|
||||
}
|
||||
|
||||
// write out the tile bits
|
||||
void debug_tile(const tile_t &tile) {
|
||||
debug(" - tile %d, %d (%d x %d)\n", tile.bounds.x, tile.bounds.y, tile.bounds.w, tile.bounds.h);
|
||||
for(auto y = 0; y < tile.bounds.h; y++) {
|
||||
debug("[%3d]: ", y);
|
||||
for(auto x = 0; x < tile.bounds.w; x++) {
|
||||
debug("%d", tile.get_value(x, y));
|
||||
}
|
||||
debug("\n");
|
||||
}
|
||||
debug("-----------------------\n");
|
||||
}
|
||||
|
||||
void add_line_segment_to_nodes(const point_t<int> &start, const point_t<int> &end) {
|
||||
// swap endpoints if line "pointing up", we do this because we
|
||||
// alway skip the last scanline (so that polygons can but cleanly
|
||||
// up against each other without overlap)
|
||||
int sx = start.x, sy = start.y, ex = end.x, ey = end.y;
|
||||
|
||||
if(ey < sy) {
|
||||
swap(sy, ey);
|
||||
swap(sx, ex);
|
||||
}
|
||||
|
||||
/*sx <<= settings::antialias;
|
||||
ex <<= settings::antialias;
|
||||
sy <<= settings::antialias;
|
||||
ey <<= settings::antialias;*/
|
||||
|
||||
int x = sx;
|
||||
int y = sy;
|
||||
int e = 0;
|
||||
|
||||
int xinc = sign(ex - sx);
|
||||
int einc = abs(ex - sx) + 1;
|
||||
|
||||
// todo: preclamp sy and ey (and therefore count) no need to perform
|
||||
// that test inside the loop
|
||||
int dy = ey - sy;
|
||||
int count = dy;
|
||||
debug(" + line segment from %d, %d to %d, %d\n", sx, sy, ex, ey);
|
||||
// loop over scanlines
|
||||
while(count--) {
|
||||
// consume accumulated error
|
||||
while(e > dy) {e -= dy; x += xinc;}
|
||||
|
||||
if(y >= 0 && y < node_buffer_size) {
|
||||
// clamp node x value to tile bounds
|
||||
int nx = max(min(x, (int)(tile_bounds.w << settings::antialias)), 0);
|
||||
debug(" + adding node at %d, %d\n", x, y);
|
||||
// add node to node list
|
||||
nodes[y][node_counts[y]++] = nx;
|
||||
}
|
||||
|
||||
// step to next scanline and accumulate error
|
||||
y++;
|
||||
e += einc;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void build_nodes(const contour_t<T> &contour, const tile_t &tile, point_t<int> origin = point_t<int>(0, 0), int scale = 65536) {
|
||||
int ox = (origin.x - tile.bounds.x) << settings::antialias;
|
||||
int oy = (origin.y - tile.bounds.y) << settings::antialias;
|
||||
|
||||
// start with the last point to close the loop
|
||||
point_t<int> last(
|
||||
(((contour.points[contour.count - 1].x * scale) << settings::antialias) / 65536) + ox,
|
||||
(((contour.points[contour.count - 1].y * scale) << settings::antialias) / 65536) + oy
|
||||
);
|
||||
|
||||
for(int i = 0; i < contour.count; i++) {
|
||||
point_t<int> point(
|
||||
(((contour.points[i].x * scale) << settings::antialias) / 65536) + ox,
|
||||
(((contour.points[i].y * scale) << settings::antialias) / 65536) + oy
|
||||
);
|
||||
|
||||
add_line_segment_to_nodes(last, point);
|
||||
|
||||
last = point;
|
||||
}
|
||||
}
|
||||
|
||||
void render_nodes(const tile_t &tile) {
|
||||
for(auto y = 0; y < node_buffer_size; y++) {
|
||||
if(node_counts[y] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::sort(&nodes[y][0], &nodes[y][0] + node_counts[y]);
|
||||
|
||||
for(auto i = 0; i < node_counts[y]; i += 2) {
|
||||
int sx = nodes[y][i + 0];
|
||||
int ex = nodes[y][i + 1];
|
||||
|
||||
if(sx == ex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug(" - render span at %d from %d to %d\n", y, sx, ex);
|
||||
|
||||
for(int x = sx; x < ex; x++) {
|
||||
tile.data[(x >> settings::antialias) + (y >> settings::antialias) * tile.stride]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void draw_polygon(T *points, unsigned count) {
|
||||
std::vector<contour_t<T>> contours;
|
||||
contour_t<T> c(points, count);
|
||||
contours.push_back(c);
|
||||
draw_polygon<T>(contours);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void draw_polygon(std::vector<contour_t<T>> contours, point_t<int> origin = point_t<int>(0, 0), int scale = 65536) {
|
||||
|
||||
debug("> draw polygon with %lu contours\n", contours.size());
|
||||
|
||||
if(contours.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// determine extreme bounds
|
||||
rect_t polygon_bounds = contours[0].bounds();
|
||||
for(auto &contour : contours) {
|
||||
polygon_bounds = polygon_bounds.merge(contour.bounds());
|
||||
}
|
||||
|
||||
polygon_bounds.x = ((polygon_bounds.x * scale) / 65536) + origin.x;
|
||||
polygon_bounds.y = ((polygon_bounds.y * scale) / 65536) + origin.y;
|
||||
polygon_bounds.w = ((polygon_bounds.w * scale) / 65536);
|
||||
polygon_bounds.h = ((polygon_bounds.h * scale) / 65536);
|
||||
|
||||
debug(" - bounds %d, %d (%d x %d)\n", polygon_bounds.x, polygon_bounds.y, polygon_bounds.w, polygon_bounds.h);
|
||||
debug(" - clip %d, %d (%d x %d)\n", settings::clip.x, settings::clip.y, settings::clip.w, settings::clip.h);
|
||||
|
||||
|
||||
memset(nodes, 0, node_buffer_size * sizeof(unsigned) * 32);
|
||||
|
||||
// iterate over tiles
|
||||
debug(" - processing tiles\n");
|
||||
for(auto y = polygon_bounds.y; y < polygon_bounds.y + polygon_bounds.h; y += tile_bounds.h) {
|
||||
for(auto x = polygon_bounds.x; x < polygon_bounds.x + polygon_bounds.w; x += tile_bounds.w) {
|
||||
tile_t tile;
|
||||
tile.bounds = rect_t(x, y, tile_bounds.w, tile_bounds.h).intersection(settings::clip);
|
||||
tile.stride = tile_bounds.w;
|
||||
tile.data = tile_buffer;
|
||||
debug(" : %d, %d (%d x %d)\n", tile.bounds.x, tile.bounds.y, tile.bounds.w, tile.bounds.h);
|
||||
|
||||
// if no intersection then skip tile
|
||||
if(tile.bounds.empty()) {
|
||||
debug(" : empty when clipped, skipping\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// clear existing tile data and nodes
|
||||
memset(node_counts, 0, node_buffer_size * sizeof(unsigned));
|
||||
memset(tile.data, 0, tile_buffer_size);
|
||||
|
||||
// build the nodes for each contour
|
||||
for(contour_t<T> &contour : contours) {
|
||||
debug(" : build nodes for contour\n");
|
||||
build_nodes(contour, tile, origin, scale);
|
||||
}
|
||||
|
||||
debug(" : render the tile\n");
|
||||
// render the tile
|
||||
render_nodes(tile);
|
||||
|
||||
settings::callback(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_character_obj, 1, ModPicoGraphics_cha
|
|||
MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_text_obj, 1, ModPicoGraphics_text);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_measure_text_obj, 1, ModPicoGraphics_measure_text);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_polygon_obj, 2, ModPicoGraphics_polygon);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_pretty_polygon_obj, 2, ModPicoGraphics_pretty_polygon);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_triangle_obj, 7, 7, ModPicoGraphics_triangle);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 6, ModPicoGraphics_line);
|
||||
|
||||
|
@ -72,6 +73,7 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&ModPicoGraphics_text_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&ModPicoGraphics_measure_text_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&ModPicoGraphics_polygon_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pretty_polygon), MP_ROM_PTR(&ModPicoGraphics_pretty_polygon_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&ModPicoGraphics_triangle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) },
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "drivers/inky73/inky73.hpp"
|
||||
#include "drivers/psram_display/psram_display.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "libraries/pico_graphics/pretty-poly-types.hpp"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_bus.hpp"
|
||||
#include "common/pimoroni_i2c.hpp"
|
||||
|
@ -298,17 +299,17 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|
|||
pimoroni::ParallelPins parallel_bus = {10, 11, 12, 13, 14, 2}; // Default for Tufty 2040 parallel
|
||||
pimoroni::I2C *i2c_bus = nullptr;
|
||||
|
||||
if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) {
|
||||
if (mp_obj_is_exact_type(args[ARG_bus].u_obj, &SPIPins_type)) {
|
||||
if(bus_type != BUS_SPI) mp_raise_ValueError("unexpected SPI bus!");
|
||||
_PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
|
||||
spi_bus = *(SPIPins *)(bus->pins);
|
||||
|
||||
} else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) {
|
||||
} else if (mp_obj_is_exact_type(args[ARG_bus].u_obj, &ParallelPins_type)) {
|
||||
if(bus_type != BUS_PARALLEL) mp_raise_ValueError("unexpected Parallel bus!");
|
||||
_PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
|
||||
parallel_bus = *(ParallelPins *)(bus->pins);
|
||||
|
||||
} else if (mp_obj_is_type(args[ARG_bus].u_obj, &PimoroniI2C_type) || MP_OBJ_IS_TYPE(args[ARG_bus].u_obj, &machine_i2c_type)) {
|
||||
} else if (mp_obj_is_exact_type(args[ARG_bus].u_obj, &PimoroniI2C_type) || mp_obj_is_exact_type(args[ARG_bus].u_obj, &machine_hw_i2c_type)) {
|
||||
if(bus_type != BUS_I2C) mp_raise_ValueError("unexpected I2C bus!");
|
||||
self->i2c = PimoroniI2C_from_machine_i2c_or_native(args[ARG_bus].u_obj);
|
||||
i2c_bus = (pimoroni::I2C *)(self->i2c->i2c);
|
||||
|
@ -442,6 +443,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|
|||
self->display->update(self->graphics);
|
||||
}
|
||||
|
||||
self->graphics->pretty_poly_init(m_tracked_calloc(self->graphics->pretty_poly_buffer_size(), sizeof(uint8_t)));
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
|
@ -807,7 +810,7 @@ mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp
|
|||
|
||||
// Check if there is only one argument, which might be a list
|
||||
if(n_args == 2) {
|
||||
if(mp_obj_is_type(pos_args[1], &mp_type_list)) {
|
||||
if(mp_obj_is_exact_type(pos_args[1], &mp_type_list)) {
|
||||
mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t);
|
||||
|
||||
if(points->len <= 0) mp_raise_ValueError("set_palette(): cannot provide an empty list");
|
||||
|
@ -822,7 +825,7 @@ mp_obj_t ModPicoGraphics_set_palette(size_t n_args, const mp_obj_t *pos_args, mp
|
|||
|
||||
for(size_t i = 0; i < num_tuples; i++) {
|
||||
mp_obj_t obj = tuples[i];
|
||||
if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("set_palette(): can't convert object to tuple");
|
||||
if(!mp_obj_is_exact_type(obj, &mp_type_tuple)) mp_raise_ValueError("set_palette(): can't convert object to tuple");
|
||||
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t);
|
||||
|
||||
|
@ -1019,6 +1022,58 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m
|
|||
return mp_obj_new_int(width);
|
||||
}
|
||||
|
||||
/*
|
||||
pretty_polygon((
|
||||
(0, 0),
|
||||
(0, 0)
|
||||
), (
|
||||
|
||||
), (
|
||||
|
||||
))
|
||||
*/
|
||||
|
||||
mp_obj_t ModPicoGraphics_pretty_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
size_t num_tuples = n_args - 1;
|
||||
const mp_obj_t *lists = pos_args + 1;
|
||||
|
||||
ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], ModPicoGraphics_obj_t);
|
||||
|
||||
std::vector<pretty_poly::contour_t<int>> contours;
|
||||
|
||||
for(auto i = 0; i < num_tuples; i++) {
|
||||
mp_obj_t c_obj = lists[i];
|
||||
|
||||
if(!mp_obj_is_exact_type(c_obj, &mp_type_list)) mp_raise_ValueError("Not a list");
|
||||
|
||||
mp_obj_list_t *t_contour = MP_OBJ_TO_PTR2(c_obj, mp_obj_list_t);
|
||||
|
||||
pretty_poly::point_t<int> *points = new pretty_poly::point_t<int>[t_contour->len];
|
||||
|
||||
for(auto p = 0; p < t_contour->len; p++) {
|
||||
mp_obj_t p_obj = t_contour->items[p];
|
||||
|
||||
if(!mp_obj_is_exact_type(p_obj, &mp_type_tuple)) mp_raise_ValueError("Not a tuple");
|
||||
|
||||
mp_obj_tuple_t *t_point = MP_OBJ_TO_PTR2(p_obj, mp_obj_tuple_t);
|
||||
points[p] = {
|
||||
mp_obj_get_int(t_point->items[0]),
|
||||
mp_obj_get_int(t_point->items[1]),
|
||||
};
|
||||
}
|
||||
|
||||
contours.push_back({points, t_contour->len});
|
||||
}
|
||||
|
||||
self->graphics->polygon(contours);
|
||||
|
||||
for(auto contour : contours) {
|
||||
delete contour.points;
|
||||
}
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
size_t num_tuples = n_args - 1;
|
||||
const mp_obj_t *tuples = pos_args + 1;
|
||||
|
@ -1027,7 +1082,7 @@ mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map
|
|||
|
||||
// Check if there is only one argument, which might be a list
|
||||
if(n_args == 2) {
|
||||
if(mp_obj_is_type(pos_args[1], &mp_type_list)) {
|
||||
if(mp_obj_is_exact_type(pos_args[1], &mp_type_list)) {
|
||||
mp_obj_list_t *points = MP_OBJ_TO_PTR2(pos_args[1], mp_obj_list_t);
|
||||
|
||||
if(points->len <= 0) mp_raise_ValueError("poly(): cannot provide an empty list");
|
||||
|
@ -1044,7 +1099,7 @@ mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map
|
|||
std::vector<Point> points;
|
||||
for(size_t i = 0; i < num_tuples; i++) {
|
||||
mp_obj_t obj = tuples[i];
|
||||
if(!mp_obj_is_type(obj, &mp_type_tuple)) mp_raise_ValueError("poly(): can't convert object to tuple");
|
||||
if(!mp_obj_is_exact_type(obj, &mp_type_tuple)) mp_raise_ValueError("poly(): can't convert object to tuple");
|
||||
|
||||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(obj, mp_obj_tuple_t);
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ extern mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_arg
|
|||
extern mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t ModPicoGraphics_pretty_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args);
|
||||
extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args);
|
||||
|
||||
|
|
Loading…
Reference in New Issue