PicoGraphicS: Hershey support, bugfixes, tidyup.
This commit is contained in:
parent
fc1561e54b
commit
49b62515c2
|
@ -5,4 +5,4 @@ add_library(pico_graphics
|
|||
|
||||
target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
target_link_libraries(pico_graphics bitmap_fonts pico_stdlib)
|
||||
target_link_libraries(pico_graphics bitmap_fonts hershey_fonts pico_stdlib)
|
|
@ -4,10 +4,10 @@ namespace pimoroni {
|
|||
|
||||
void PicoGraphics::set_pen(uint c) {};
|
||||
void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {};
|
||||
void PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {};
|
||||
void PicoGraphics::reset_pen(uint8_t i) {};
|
||||
int PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {return -1;};
|
||||
int PicoGraphics::reset_pen(uint8_t i) {return -1;};
|
||||
int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;};
|
||||
void PicoGraphics::set_pixel(void *frame_buffer, uint x, uint y, uint stride) {};
|
||||
void PicoGraphics::set_pixel(const Point &p) {};
|
||||
void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {};
|
||||
|
||||
void PicoGraphics::set_dimensions(int width, int height) {
|
||||
|
@ -27,16 +27,27 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void PicoGraphics::set_font(const bitmap::font_t *font){
|
||||
this->font = font;
|
||||
this->bitmap_font = font;
|
||||
this->hershey_font = nullptr;
|
||||
}
|
||||
|
||||
void PicoGraphics::set_font(std::string font){
|
||||
if (font == "bitmap6") {
|
||||
this->font = &font6;
|
||||
} else if (font == "bitmap8") {
|
||||
this->font = &font8;
|
||||
} else if (font == "bitmap14_outline") {
|
||||
this->font = &font14_outline;
|
||||
void PicoGraphics::set_font(const hershey::font_t *font){
|
||||
this->bitmap_font = nullptr;
|
||||
this->hershey_font = font;
|
||||
}
|
||||
|
||||
void PicoGraphics::set_font(std::string name){
|
||||
if (name == "bitmap6") {
|
||||
set_font(&font6);
|
||||
} else if (name == "bitmap8") {
|
||||
set_font(&font8);
|
||||
} else if (name == "bitmap14_outline") {
|
||||
set_font(&font14_outline);
|
||||
} else {
|
||||
// check that font exists and assign it
|
||||
if(hershey::fonts.find(name) != hershey::fonts.end()) {
|
||||
set_font(hershey::fonts[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +65,7 @@ namespace pimoroni {
|
|||
|
||||
void PicoGraphics::pixel(const Point &p) {
|
||||
if(!clip.contains(p)) return;
|
||||
set_pixel(frame_buffer, p.x, p.y, bounds.w);
|
||||
set_pixel(p);
|
||||
}
|
||||
|
||||
void PicoGraphics::pixel_span(const Point &p, int32_t l) {
|
||||
|
@ -69,7 +80,7 @@ namespace pimoroni {
|
|||
|
||||
Point dest(clipped.x, clipped.y);
|
||||
while(l--) {
|
||||
set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
|
||||
set_pixel(dest);
|
||||
dest.x++;
|
||||
}
|
||||
}
|
||||
|
@ -117,20 +128,42 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
void PicoGraphics::character(const char c, const Point &p, uint8_t scale) {
|
||||
bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){
|
||||
rectangle(Rect(x, y, w, h));
|
||||
}, c, p.x, p.y, scale);
|
||||
void PicoGraphics::character(const char c, const Point &p, float s, float a) {
|
||||
if (bitmap_font) {
|
||||
bitmap::character(bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
rectangle(Rect(x, y, w, h));
|
||||
}, c, p.x, p.y, std::max(1.0f, s));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hershey_font) {
|
||||
hershey::glyph(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
|
||||
line(Point(x1, y1), Point(x2, y2));
|
||||
}, c, p.x, p.y, s, a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) {
|
||||
bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){
|
||||
rectangle(Rect(x, y, w, h));
|
||||
}, t, p.x, p.y, wrap, scale);
|
||||
void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) {
|
||||
if (bitmap_font) {
|
||||
bitmap::text(bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
rectangle(Rect(x, y, w, h));
|
||||
}, t, p.x, p.y, wrap, std::max(1.0f, s), letter_spacing);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hershey_font) {
|
||||
hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
|
||||
line(Point(x1, y1), Point(x2, y2));
|
||||
}, t, p.x, p.y, s, a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) {
|
||||
return bitmap::measure_text(font, t, scale);
|
||||
int32_t PicoGraphics::measure_text(const std::string &t, float s, uint8_t letter_spacing) {
|
||||
if (bitmap_font) return bitmap::measure_text(bitmap_font, t, std::max(1.0f, s), letter_spacing);
|
||||
if (hershey_font) return hershey::measure_text(hershey_font, t, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t orient2d(Point p1, Point p2, Point p3) {
|
||||
|
@ -186,7 +219,7 @@ namespace pimoroni {
|
|||
Point dest = Point(triangle_bounds.x, triangle_bounds.y + y);
|
||||
for (int32_t x = 0; x < triangle_bounds.w; x++) {
|
||||
if ((w0 | w1 | w2) >= 0) {
|
||||
set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
|
||||
set_pixel(dest);
|
||||
}
|
||||
|
||||
dest.x++;
|
||||
|
@ -251,24 +284,29 @@ namespace pimoroni {
|
|||
void PicoGraphics::line(Point p1, Point p2) {
|
||||
// fast horizontal line
|
||||
if(p1.y == p2.y) {
|
||||
int32_t start = std::max(clip.x, std::min(p1.x, p2.x));
|
||||
int32_t end = std::min(clip.x + clip.w, std::max(p1.x, p2.x));
|
||||
p1 = p1.clamp(clip);
|
||||
p2 = p2.clamp(clip);
|
||||
int32_t start = std::min(p1.x, p2.x);
|
||||
int32_t end = std::max(p1.x, p2.x);
|
||||
pixel_span(Point(start, p1.y), end - start);
|
||||
return;
|
||||
}
|
||||
|
||||
// fast vertical line
|
||||
if(p1.x == p2.x) {
|
||||
int32_t start = std::max(clip.y, std::min(p1.y, p2.y));
|
||||
int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start;
|
||||
p1 = p1.clamp(clip);
|
||||
p2 = p2.clamp(clip);
|
||||
int32_t start = std::min(p1.y, p2.y);
|
||||
int32_t length = std::max(p1.y, p2.y) - start;
|
||||
Point dest(p1.x, start);
|
||||
while(length--) {
|
||||
set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
|
||||
set_pixel(dest);
|
||||
dest.y++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// general purpose line
|
||||
// lines are either "shallow" or "steep" based on whether the x delta
|
||||
// is greater than the y delta
|
||||
|
@ -283,7 +321,8 @@ namespace pimoroni {
|
|||
int32_t x = p1.x;
|
||||
int32_t y = p1.y << 16;
|
||||
while(s--) {
|
||||
set_pixel(frame_buffer, x, y >> 16, bounds.w);
|
||||
Point p(x, y >> 16);
|
||||
if(clip.contains(p)) set_pixel(p);
|
||||
y += sy;
|
||||
x += sx;
|
||||
}
|
||||
|
@ -295,7 +334,8 @@ namespace pimoroni {
|
|||
int32_t y = p1.y;
|
||||
int32_t x = p1.x << 16;
|
||||
while(s--) {
|
||||
set_pixel(frame_buffer, x >> 16, y, bounds.w);
|
||||
Point p(x >> 16, y);
|
||||
if(clip.contains(p)) set_pixel(p);
|
||||
y += sy;
|
||||
x += sx;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "libraries/hershey_fonts/hershey_fonts.hpp"
|
||||
#include "libraries/bitmap_fonts/bitmap_fonts.hpp"
|
||||
#include "libraries/bitmap_fonts/font6_data.hpp"
|
||||
#include "libraries/bitmap_fonts/font8_data.hpp"
|
||||
#include "libraries/bitmap_fonts/font14_outline_data.hpp"
|
||||
|
||||
#include "common/pimoroni_common.hpp"
|
||||
|
||||
// A tiny graphics library for our Pico products
|
||||
|
@ -72,7 +76,8 @@ namespace pimoroni {
|
|||
Rect bounds;
|
||||
Rect clip;
|
||||
|
||||
const bitmap::font_t *font;
|
||||
const bitmap::font_t *bitmap_font;
|
||||
const hershey::font_t *hershey_font;
|
||||
|
||||
static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6);
|
||||
|
@ -100,13 +105,14 @@ namespace pimoroni {
|
|||
|
||||
virtual void set_pen(uint c);
|
||||
virtual void set_pen(uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual void reset_pen(uint8_t i);
|
||||
virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual int reset_pen(uint8_t i);
|
||||
virtual int create_pen(uint8_t r, uint8_t g, uint8_t b);
|
||||
virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride);
|
||||
virtual void set_pixel(const Point &p);
|
||||
virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length);
|
||||
|
||||
void set_font(const bitmap::font_t *font);
|
||||
void set_font(const hershey::font_t *font);
|
||||
void set_font(std::string font);
|
||||
|
||||
void set_dimensions(int width, int height);
|
||||
|
@ -123,9 +129,9 @@ namespace pimoroni {
|
|||
void pixel_span(const Point &p, int32_t l);
|
||||
void rectangle(const Rect &r);
|
||||
void circle(const Point &p, int32_t r);
|
||||
void character(const char c, const Point &p, uint8_t scale = 2);
|
||||
void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2);
|
||||
int32_t measure_text(const std::string &t, uint8_t scale = 2);
|
||||
void character(const char c, const Point &p, float s = 2.0f, float a = 0.0f);
|
||||
void text(const std::string &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1);
|
||||
int32_t measure_text(const std::string &t, float s = 2.0f, uint8_t letter_spacing = 1);
|
||||
void polygon(const std::vector<Point> &points);
|
||||
void triangle(Point p1, Point p2, Point p3);
|
||||
void line(Point p1, Point p2);
|
||||
|
@ -163,26 +169,28 @@ namespace pimoroni {
|
|||
void set_pen(uint8_t r, uint8_t g, uint8_t b) override {
|
||||
// TODO look up closest palette colour, or just NOOP?
|
||||
}
|
||||
void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override {
|
||||
int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override {
|
||||
i &= 0xf;
|
||||
palette[i].color = rgb_to_rgb565(r, g, b);
|
||||
palette[i].used = true;
|
||||
return i;
|
||||
}
|
||||
void reset_pen(uint8_t i) override {
|
||||
int reset_pen(uint8_t i) override {
|
||||
i &= 0xf;
|
||||
palette[i].color = default_palette[i];
|
||||
return i;
|
||||
}
|
||||
void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override {
|
||||
void set_pixel(const Point &p) override {
|
||||
// pointer to byte in framebuffer that contains this pixel
|
||||
uint8_t *buf = (uint8_t *)frame_buffer;
|
||||
uint8_t *p = &buf[(x / 2) + (y * stride / 2)];
|
||||
uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)];
|
||||
|
||||
uint8_t o = (~x & 0b1) * 4; // bit offset within byte
|
||||
uint8_t m = ~(0b1111 << o); // bit mask for byte
|
||||
uint8_t b = color << o; // bit value shifted to position
|
||||
uint8_t o = (~p.x & 0b1) * 4; // bit offset within byte
|
||||
uint8_t m = ~(0b1111 << o); // bit mask for byte
|
||||
uint8_t b = color << o; // bit value shifted to position
|
||||
|
||||
*p &= m; // clear bits
|
||||
*p |= b; // set value
|
||||
*f &= m; // clear bits
|
||||
*f |= b; // set value
|
||||
}
|
||||
void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
|
||||
uint8_t *src = (uint8_t *)frame_buffer;
|
||||
|
@ -219,15 +227,17 @@ namespace pimoroni {
|
|||
void set_pen(uint8_t r, uint8_t g, uint8_t b) override {
|
||||
// TODO look up closest palette colour, or just NOOP?
|
||||
}
|
||||
void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override {
|
||||
int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override {
|
||||
i &= 0xff;
|
||||
palette[i].color = rgb_to_rgb565(r, g, b);
|
||||
palette[i].used = true;
|
||||
return i;
|
||||
}
|
||||
void reset_pen(uint8_t i) override {
|
||||
int reset_pen(uint8_t i) override {
|
||||
i &= 0xff;
|
||||
palette[i].color = 0;
|
||||
palette[i].used = false;
|
||||
return i;
|
||||
}
|
||||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override {
|
||||
// Create a colour and place it in the palette if there's space
|
||||
|
@ -241,9 +251,9 @@ namespace pimoroni {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override {
|
||||
void set_pixel(const Point &p) override {
|
||||
uint8_t *buf = (uint8_t *)frame_buffer;
|
||||
buf[y * stride + x] = color;
|
||||
buf[p.y * bounds.w + p.x] = color;
|
||||
}
|
||||
void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
|
||||
uint8_t *src = (uint8_t *)frame_buffer;
|
||||
|
@ -281,9 +291,9 @@ namespace pimoroni {
|
|||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override {
|
||||
return rgb_to_rgb332(r, g, b);
|
||||
}
|
||||
void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override {
|
||||
void set_pixel(const Point &p) override {
|
||||
uint8_t *buf = (uint8_t *)frame_buffer;
|
||||
buf[y * stride + x] = color;
|
||||
buf[p.y * bounds.w + p.x] = color;
|
||||
}
|
||||
void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
|
||||
uint8_t *src = (uint8_t *)frame_buffer;
|
||||
|
@ -316,9 +326,9 @@ namespace pimoroni {
|
|||
int create_pen(uint8_t r, uint8_t g, uint8_t b) override {
|
||||
return rgb_to_rgb565(r, g, b);
|
||||
}
|
||||
void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override {
|
||||
void set_pixel(const Point &p) override {
|
||||
uint16_t *buf = (uint16_t *)frame_buffer;
|
||||
buf[y * stride + x] = color;
|
||||
buf[p.y * bounds.w + p.x] = color;
|
||||
}
|
||||
static size_t buffer_size(uint w, uint h) {
|
||||
return w * h * sizeof(RGB565);
|
||||
|
|
|
@ -29,6 +29,7 @@ include(pico_unicorn/micropython)
|
|||
include(pico_wireless/micropython)
|
||||
include(pico_explorer/micropython)
|
||||
|
||||
include(hershey_fonts/micropython)
|
||||
include(bitmap_fonts/micropython)
|
||||
|
||||
include(plasma/micropython)
|
||||
|
|
|
@ -443,14 +443,16 @@ mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
}
|
||||
|
||||
mp_obj_t ModPicoGraphics_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, ARG_wrap, ARG_scale };
|
||||
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale, ARG_angle, ARG_spacing };
|
||||
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_x1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} },
|
||||
{ MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_angle, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
@ -469,19 +471,22 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
|||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int wrap = args[ARG_wrap].u_int;
|
||||
int scale = args[ARG_scale].u_int;
|
||||
float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj);
|
||||
int angle = args[ARG_angle].u_int;
|
||||
int letter_spacing = args[ARG_spacing].u_int;
|
||||
|
||||
self->graphics->text(t, Point(x, y), wrap, scale);
|
||||
self->graphics->text(t, Point(x, y), wrap, scale, angle, letter_spacing);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_text, ARG_scale };
|
||||
enum { ARG_self, ARG_text, ARG_scale, ARG_spacing };
|
||||
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_scale, MP_ARG_INT, {.u_int = 2} },
|
||||
{ MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
@ -497,9 +502,10 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m
|
|||
|
||||
std::string t((const char*)str);
|
||||
|
||||
int scale = args[ARG_scale].u_int;
|
||||
float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj);
|
||||
int letter_spacing = args[ARG_spacing].u_int;
|
||||
|
||||
int width = self->graphics->measure_text(t, scale);
|
||||
int width = self->graphics->measure_text(t, scale, letter_spacing);
|
||||
|
||||
return mp_obj_new_int(width);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue