PicoVector: Better separation of concerns, add Alright Fonts support.

This commit is contained in:
Phil Howard 2023-08-14 15:58:40 +01:00
parent c9a8d5ef49
commit 9e430fd68c
15 changed files with 518 additions and 85 deletions

View File

@ -1,5 +1,4 @@
#include "pico_graphics.hpp"
#include "pretty-poly.hpp"
namespace pimoroni {
@ -17,13 +16,6 @@ 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};
@ -249,46 +241,7 @@ 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 = 0u; 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;
@ -332,7 +285,6 @@ 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) {

View File

@ -17,8 +17,6 @@
#include "common/pimoroni_common.hpp"
#include "pretty-poly-types.hpp"
// A tiny graphics library for our Pico products
// supports:
// - 16-bit (565) RGB
@ -262,9 +260,6 @@ 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;
@ -306,7 +301,6 @@ 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);

View File

@ -0,0 +1,128 @@
#include <cstdint>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <optional>
#include <map>
#include "alright_fonts.hpp"
using namespace pretty_poly;
namespace alright_fonts {
/*
render functions
*/
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin) {
if(tm.face.glyphs.count(codepoint) == 1) {
glyph_t glyph = tm.face.glyphs[codepoint];
// scale is a fixed point 16:16 value, our font data is already scaled to
// -128..127 so to get the pixel size we want we can just shift the
// users requested size up one bit
unsigned scale = tm.size << 9;
pretty_poly::draw_polygon<int8_t>(glyph.contours, origin, scale);
}
}
/*
load functions
*/
// big endian stream value helpers
uint16_t ru16(file_io &ifs) {uint8_t w[2]; ifs.read((char *)w, 2); return w[0] << 8 | w[1];}
int16_t rs16(file_io &ifs) {uint8_t w[2]; ifs.read((char *)w, 2); return w[0] << 8 | w[1];}
uint32_t ru32(file_io &ifs) {uint8_t dw[4]; ifs.read((char *)dw, 4); return dw[0] << 24 | dw[1] << 16 | dw[2] << 8 | dw[3];}
uint8_t ru8(file_io &ifs) {uint8_t w; ifs.read(&w, 1); return w;}
int8_t rs8(file_io &ifs) {int8_t w; ifs.read(&w, 1); return w;}
bool face_t::load(file_io &ifs) {
char marker[4];
ifs.read(marker, sizeof(marker));
// check header magic bytes are present
if(memcmp(marker, "af!?", 4) != 0) {
// doesn't start with magic marker
return false;
}
// number of glyphs embedded in font file
this->glyph_count = ru16(ifs);
// extract flags and ensure none set
this->flags = ru16(ifs);
if(this->flags != 0) {
// unknown flags set
return false;
}
// extract glyph dictionary
uint16_t glyph_entry_size = 9;
uint32_t contour_data_offset = 8 + this->glyph_count * glyph_entry_size;
for(auto i = 0; i < this->glyph_count; i++) {
glyph_t g;
g.codepoint = ru16(ifs);
g.bounds.x = rs8(ifs);
g.bounds.y = rs8(ifs);
g.bounds.w = ru8(ifs);
g.bounds.h = ru8(ifs);
g.advance = ru8(ifs);
if(ifs.fail()) {
// could not read glyph dictionary entry
return false;
}
// allocate space for the contour data and read it from the font file
uint16_t contour_data_length = ru16(ifs);
// remember where we are in the dictionary
int pos = ifs.tell();
// read contour data
ifs.seek(contour_data_offset);
while(true) {
// get number of points in contour
uint16_t count = ru16(ifs);
// if count is zero then this is the end of contour marker
if(count == 0) {
break;
}
// allocate space to store point data for contour and read
// from file
pretty_poly::point_t<int8_t> *points = new pretty_poly::point_t<int8_t>[count];
ifs.read((char *)points, count * 2);
g.contours.push_back({points, count});
}
// return back to position in dictionary
ifs.seek(pos);
contour_data_offset += contour_data_length;
if(ifs.fail()) {
// could not read glyph contour data
return false;
}
this->glyphs[g.codepoint] = g;
}
return true;
}
bool face_t::load(std::string_view path) {
file_io ifs(path);
if(ifs.fail()) {
// could not open file
return false;
}
return load(ifs);
}
}

View File

@ -0,0 +1,68 @@
#include <cstdint>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <optional>
#include <map>
#include "pretty_poly.hpp"
namespace alright_fonts {
struct glyph_t {
uint16_t codepoint;
pretty_poly::rect_t bounds;
uint8_t advance;
std::vector<pretty_poly::contour_t<int8_t>> contours;
};
struct face_t {
uint16_t glyph_count;
uint16_t flags;
std::map<uint16_t, glyph_t> glyphs;
face_t() {};
face_t(pretty_poly::file_io &ifs) {load(ifs);}
face_t(std::string_view path) {load(path);}
bool load(pretty_poly::file_io &ifs);
bool load(std::string_view path);
};
enum alignment_t {
left = 0,
center = 1,
right = 2,
justify = 4,
top = 8,
bottom = 16
};
struct text_metrics_t {
face_t face; // font to write in
int size; // text size in pixels
uint scroll; // vertical scroll offset
int line_height; // spacing between lines (%)
int letter_spacing; // spacing between characters
int word_spacing; // spacing between words
alignment_t align; // horizontal and vertical alignment
//optional<mat3_t> transform; // arbitrary transformation
pretty_poly::antialias_t antialiasing = pretty_poly::X4; // level of antialiasing to apply
void set_size(int s) {
size = s;
line_height = size * 1.2;
letter_spacing = 0;
word_spacing = size;
}
text_metrics_t() {};
};
/*
render functions
*/
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin);
}

View File

@ -0,0 +1,9 @@
add_library(pico_vector
${CMAKE_CURRENT_LIST_DIR}/pico_vector.cpp
${CMAKE_CURRENT_LIST_DIR}/pretty_poly.cpp
${CMAKE_CURRENT_LIST_DIR}/alright_fonts.cpp
)
target_include_directories(pico_vector INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(pico_vector pico_stdlib)

View File

@ -0,0 +1,30 @@
#include "pico_vector.hpp"
#include <vector>
namespace pimoroni {
void PicoVector::polygon(std::vector<pretty_poly::contour_t<int>> contours, Point origin, int scale) {
pretty_poly::draw_polygon<int>(
contours,
pretty_poly::point_t<int>(origin.x, origin.y),
scale);
}
Point PicoVector::text(std::string_view text, Point origin) {
// TODO: Normalize types somehow, so we're not converting?
pretty_poly::point_t<int> caret = pretty_poly::point_t<int>(origin.x, origin.y);
for (auto c : text) {
alright_fonts::render_character(text_metrics, c, caret);
if(text_metrics.face.glyphs.count(c) == 1) {
alright_fonts::glyph_t glyph = text_metrics.face.glyphs[c];
caret.x += ((glyph.advance * text_metrics.size) / 128);
if(caret.x > graphics->bounds.w) {
caret.y += text_metrics.size;
caret.x = origin.x;
}
}
}
return Point(caret.x, caret.y);
}
}

View File

@ -0,0 +1,43 @@
#include "pretty_poly.hpp"
#include "alright_fonts.hpp"
#include "pico_graphics.hpp"
namespace pimoroni {
class PicoVector {
private:
PicoGraphics *graphics;
alright_fonts::text_metrics_t text_metrics;
public:
PicoVector(PicoGraphics *graphics, void *mem = nullptr) : graphics(graphics) {
pretty_poly::init(mem);
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) {
this->graphics->pixel({x + tile.bounds.x, y + tile.bounds.y});
}
}
}
}, pretty_poly::NONE, {0, 0, graphics->bounds.w, graphics->bounds.h});
};
bool set_font(std::string_view font_path, unsigned int font_size) {
bool result = text_metrics.face.load(font_path);
text_metrics.set_size(font_size);
return result;
}
Point text(std::string_view text, Point origin);
void polygon(std::vector<pretty_poly::contour_t<int>> contours, Point origin = Point(0, 0), int scale=65536);
static constexpr size_t pretty_poly_buffer_size() {
return pretty_poly::buffer_size();
};
};
}

View File

@ -3,6 +3,10 @@
#include <optional>
#include <cstring>
#include <new>
#include <filesystem>
#include <fstream>
#include "pretty_poly.hpp"
#ifdef PP_DEBUG
@ -13,22 +17,8 @@
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;
@ -42,10 +32,6 @@ namespace pretty_poly {
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) {
uintptr_t m = (uintptr_t)memory;
tile_buffer = new(memory) uint8_t[tile_buffer_size];
@ -130,7 +116,7 @@ namespace pretty_poly {
}
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) {
void build_nodes(const contour_t<T> &contour, const tile_t &tile, point_t<int> origin, int scale) {
int ox = (origin.x - tile.bounds.x) << settings::antialias;
int oy = (origin.y - tile.bounds.y) << settings::antialias;
@ -186,7 +172,7 @@ namespace pretty_poly {
}
template<typename T>
void draw_polygon(std::vector<contour_t<T>> contours, point_t<int> origin = point_t<int>(0, 0), int scale = 65536) {
void draw_polygon(std::vector<contour_t<T>> contours, point_t<int> origin, int scale) {
debug("> draw polygon with %lu contours\n", contours.size());
@ -246,3 +232,7 @@ namespace pretty_poly {
}
}
}
template void pretty_poly::draw_polygon<int>(std::vector<contour_t<int>> contours, point_t<int> origin, int scale);
template void pretty_poly::draw_polygon<uint8_t>(std::vector<contour_t<uint8_t>> contours, point_t<int> origin, int scale);
template void pretty_poly::draw_polygon<int8_t>(std::vector<contour_t<int8_t>> contours, point_t<int> origin, int scale);

View File

@ -0,0 +1,65 @@
#pragma once
#include <cstdint>
#include <algorithm>
#include <optional>
#include <cstring>
#include <new>
#include <filesystem>
#include <fstream>
#include "pretty_poly_types.hpp"
namespace pretty_poly {
class file_io {
private:
void *state;
size_t filesize = 0;
public:
file_io(std::string_view path);
~file_io();
size_t seek(size_t pos);
size_t read(void *buf, size_t len);
size_t tell();
bool fail();
};
// buffer that each tile is rendered into before callback
constexpr unsigned tile_buffer_size = 1024;
// 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;
typedef std::function<void(const tile_t &tile)> tile_callback_t;
constexpr size_t buffer_size() {
return tile_buffer_size + (node_buffer_size * sizeof(unsigned)) + (node_buffer_size * 32 * sizeof(int));
}
constexpr size_t buffer_size();
void init(void *memory);
void set_options(tile_callback_t callback, antialias_t antialias, rect_t clip);
// dy step (returns 1, 0, or -1 if the supplied value is > 0, == 0, < 0)
inline constexpr int sign(int v);
// write out the tile bits
void debug_tile(const tile_t &tile);
void add_line_segment_to_nodes(const point_t<int> &start, const point_t<int> &end);
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);
void render_nodes(const tile_t &tile);
template<typename T>
void draw_polygon(T *points, unsigned count);
template<typename T>
void draw_polygon(std::vector<contour_t<T>> contours, point_t<int> origin = point_t<int>(0, 0), int scale = 65536);
}

View File

@ -7,7 +7,6 @@
#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"
@ -442,9 +441,6 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
if (display != DISPLAY_INKY_FRAME && display != DISPLAY_INKY_FRAME_4 && display != DISPLAY_INKY_PACK && display != DISPLAY_INKY_FRAME_7) {
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);
}

View File

@ -1,12 +1,17 @@
add_library(usermod_picovector INTERFACE)
target_sources(usermod_picovector INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_vector/pico_vector.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_vector/pretty_poly.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_vector/alright_fonts.cpp
${CMAKE_CURRENT_LIST_DIR}/picovector.c
${CMAKE_CURRENT_LIST_DIR}/picovector.cpp
)
target_include_directories(usermod_picovector INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_vector/
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/pico_graphics/
)
target_compile_definitions(usermod_picovector INTERFACE

View File

@ -2,11 +2,16 @@
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_polygon_obj, 2, VECTOR_polygon);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_regular_polygon_obj, 6, VECTOR_regular_polygon);
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);
// class
STATIC const mp_rom_map_elem_t VECTOR_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&VECTOR_polygon_obj) },
{ MP_ROM_QSTR(MP_QSTR_regular_polygon), MP_ROM_PTR(&VECTOR_regular_polygon_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_font), MP_ROM_PTR(&VECTOR_set_font_obj) },
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&VECTOR_text_obj) },
};
STATIC MP_DEFINE_CONST_DICT(VECTOR_locals_dict, VECTOR_locals_dict_table);

View File

@ -1,5 +1,6 @@
#include "micropython/modules/util.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "libraries/pico_vector/pico_vector.hpp"
using namespace pimoroni;
@ -19,9 +20,89 @@ typedef struct _ModPicoGraphics_obj_t {
typedef struct _VECTOR_obj_t {
mp_obj_base_t base;
ModPicoGraphics_obj_t *graphics;
PicoVector *vector;
} _VECTOR_obj_t;
pretty_poly::file_io::file_io(std::string_view filename) {
mp_obj_t fn = mp_obj_new_str(filename.data(), (mp_uint_t)filename.size());
//mp_printf(&mp_plat_print, "Opening file %s\n", filename.data());
mp_obj_t args[2] = {
fn,
MP_OBJ_NEW_QSTR(MP_QSTR_r),
};
// Stat the file to get its size
// example tuple response: (32768, 0, 0, 0, 0, 0, 5153, 1654709815, 1654709815, 1654709815)
mp_obj_t stat = mp_vfs_stat(fn);
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(stat, mp_obj_tuple_t);
filesize = mp_obj_get_int(tuple->items[6]);
mp_obj_t fhandle = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
this->state = (void *)fhandle;
}
pretty_poly::file_io::~file_io() {
mp_stream_close((mp_obj_t)this->state);
}
size_t pretty_poly::file_io::read(void *buf, size_t len) {
//mp_printf(&mp_plat_print, "Reading %lu bytes\n", len);
mp_obj_t fhandle = this->state;
int error;
return mp_stream_read_exactly(fhandle, buf, len, &error);
}
size_t pretty_poly::file_io::tell() {
mp_obj_t fhandle = this->state;
struct mp_stream_seek_t seek_s;
seek_s.offset = 0;
seek_s.whence = SEEK_CUR;
const mp_stream_p_t *stream_p = mp_get_stream(fhandle);
int error;
mp_uint_t res = stream_p->ioctl(fhandle, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
if (res == MP_STREAM_ERROR) {
mp_raise_OSError(error);
}
return seek_s.offset;
}
bool pretty_poly::file_io::fail() {
return false;
}
// Re-implementation of stream.c/STATIC mp_obj_t stream_seek(size_t n_args, const mp_obj_t *args)
size_t pretty_poly::file_io::seek(size_t pos) {
mp_obj_t fhandle = this->state;
struct mp_stream_seek_t seek_s;
seek_s.offset = pos;
seek_s.whence = SEEK_SET;
const mp_stream_p_t *stream_p = mp_get_stream(fhandle);
int error;
mp_uint_t res = stream_p->ioctl(fhandle, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
if (res == MP_STREAM_ERROR) {
mp_raise_OSError(error);
}
return seek_s.offset;
}
static const std::string_view mp_obj_to_string_r(const mp_obj_t &obj) {
if(mp_obj_is_str_or_bytes(obj)) {
GET_STR_DATA_LEN(obj, str, str_len);
return std::string_view((const char*)str, str_len);
}
mp_raise_TypeError("can't convert object to str implicitly");
}
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) {
enum {
ARG_picographics
@ -36,11 +117,60 @@ mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
_VECTOR_obj_t *self = m_new_obj(_VECTOR_obj_t);
self->base.type = &VECTOR_type;
self->graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj);
ModPicoGraphics_obj_t *graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj);
void *mem = m_tracked_calloc(PicoVector::pretty_poly_buffer_size(), sizeof(uint8_t));
self->vector = m_new_class(PicoVector, graphics->graphics, mem);
return self;
}
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);
int font_size = mp_obj_get_int(size);
bool result = false;
if (mp_obj_is_str(font)) {
result = self->vector->set_font(mp_obj_to_string_r(font), font_size);
}
else {
}
return result ? mp_const_true : mp_const_false;
}
mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_text, ARG_x, ARG_y };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _VECTOR_obj_t);
mp_obj_t text_obj = args[ARG_text].u_obj;
if(!mp_obj_is_str_or_bytes(text_obj)) mp_raise_TypeError("text: string required");
GET_STR_DATA_LEN(text_obj, str, str_len);
const std::string_view t((const char*)str, str_len);
int x = args[ARG_x].u_int;
int y = args[ARG_y].u_int;
self->vector->text(t, Point(x, y));
return mp_const_none;
}
mp_obj_t VECTOR_regular_polygon(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_rotation };
static const mp_arg_t allowed_args[] = {
@ -71,14 +201,14 @@ mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_
for(auto s = 0u; s < sides; s++) {
float current_angle = angle * s + rotation;
points[s] = {
int(cos(current_angle) * radius + o_x),
int(sin(current_angle) * radius + o_y)
int(cos(current_angle) * radius),
int(sin(current_angle) * radius)
};
}
std::vector<pretty_poly::contour_t<int>> contours;
contours.push_back({points, sides});
self->graphics->graphics->polygon(contours);
self->vector->polygon(contours, Point(o_x, o_y));
delete points;
@ -86,11 +216,27 @@ mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_
}
mp_obj_t VECTOR_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;
_VECTOR_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], _VECTOR_obj_t);
int offset_x = 0;
int offset_y = 0;
if(mp_obj_is_int(pos_args[1])) {
offset_x = mp_obj_get_int(pos_args[1]);
lists++;
num_tuples--;
}
if (mp_obj_is_int(pos_args[2])) {
offset_y = mp_obj_get_int(pos_args[2]);
lists++;
num_tuples--;
}
std::vector<pretty_poly::contour_t<int>> contours;
for(auto i = 0u; i < num_tuples; i++) {
@ -117,7 +263,7 @@ mp_obj_t VECTOR_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
contours.push_back({points, t_contour->len});
}
self->graphics->graphics->polygon(contours);
self->vector->polygon(contours, Point(offset_x, offset_y));
for(auto contour : contours) {
delete contour.points;

View File

@ -6,4 +6,6 @@ extern const mp_obj_type_t VECTOR_type;
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_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_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);