PicoVector: Better separation of concerns, add Alright Fonts support.
This commit is contained in:
parent
c9a8d5ef49
commit
9e430fd68c
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
};
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue