Skip to content

Commit a334899

Browse files
authored
Merge pull request #783 from pimoroni/feature/ppaf
PicoVector.
2 parents 3d8f8c9 + cca2d56 commit a334899

22 files changed

+1944
-13
lines changed

libraries/pico_graphics/pico_graphics.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace pimoroni {
88
int PicoGraphics::reset_pen(uint8_t i) {return -1;};
99
int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;};
1010
int PicoGraphics::create_pen_hsv(float h, float s, float v){return -1;};
11+
void PicoGraphics::set_pixel_alpha(const Point &p, const uint8_t a) {};
1112
void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {};
1213
void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {};
1314
void PicoGraphics::set_pixel_dither(const Point &p, const uint8_t &c) {};
@@ -16,6 +17,7 @@ namespace pimoroni {
1617

1718
int PicoGraphics::get_palette_size() {return 0;}
1819
RGB* PicoGraphics::get_palette() {return nullptr;}
20+
bool PicoGraphics::supports_alpha_blend() {return false;}
1921

2022
void PicoGraphics::set_dimensions(int width, int height) {
2123
bounds = clip = {0, 0, width, height};

libraries/pico_graphics/pico_graphics.hpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,19 @@ namespace pimoroni {
4747
g((c >> 8) & 0xff),
4848
b(c & 0xff) {}
4949
constexpr RGB(int16_t r, int16_t g, int16_t b) : r(r), g(g), b(b) {}
50-
50+
51+
constexpr uint8_t blend(uint8_t s, uint8_t d, uint8_t a) {
52+
return d + ((a * (s - d) + 127) >> 8);
53+
}
54+
55+
constexpr RGB blend(RGB with, const uint8_t alpha) {
56+
return RGB(
57+
blend(with.r, r, alpha),
58+
blend(with.g, g, alpha),
59+
blend(with.b, b, alpha)
60+
);
61+
}
62+
5163
static RGB from_hsv(float h, float s, float v) {
5264
float i = floor(h * 6.0f);
5365
float f = h * 6.0f - i;
@@ -268,6 +280,7 @@ namespace pimoroni {
268280

269281
virtual int get_palette_size();
270282
virtual RGB* get_palette();
283+
virtual bool supports_alpha_blend();
271284

272285
virtual int create_pen(uint8_t r, uint8_t g, uint8_t b);
273286
virtual int create_pen_hsv(float h, float s, float v);
@@ -276,6 +289,7 @@ namespace pimoroni {
276289
virtual void set_pixel_dither(const Point &p, const RGB &c);
277290
virtual void set_pixel_dither(const Point &p, const RGB565 &c);
278291
virtual void set_pixel_dither(const Point &p, const uint8_t &c);
292+
virtual void set_pixel_alpha(const Point &p, const uint8_t a);
279293
virtual void frame_convert(PenType type, conversion_callback_func callback);
280294
virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent);
281295

@@ -471,6 +485,9 @@ namespace pimoroni {
471485
void set_pixel_span(const Point &p, uint l) override;
472486
void set_pixel_dither(const Point &p, const RGB &c) override;
473487
void set_pixel_dither(const Point &p, const RGB565 &c) override;
488+
void set_pixel_alpha(const Point &p, const uint8_t a) override;
489+
490+
bool supports_alpha_blend() override {return true;}
474491

475492
void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override;
476493

libraries/pico_graphics/pico_graphics_pen_rgb332.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ namespace pimoroni {
3434
*buf++ = color;
3535
}
3636
}
37+
void PicoGraphics_PenRGB332::set_pixel_alpha(const Point &p, const uint8_t a) {
38+
if(!bounds.contains(p)) return;
39+
40+
uint8_t *buf = (uint8_t *)frame_buffer;
41+
42+
RGB332 blended = RGB(buf[p.y * bounds.w + p.x]).blend(RGB(color), a).to_rgb332();
43+
44+
buf[p.y * bounds.w + p.x] = blended;
45+
};
3746
void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB &c) {
3847
if(!bounds.contains(p)) return;
3948
uint8_t _dmv = dither16_pattern[(p.x & 0b11) | ((p.y & 0b11) << 2)];
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include <cstdint>
2+
#include <math.h>
3+
#include <string.h>
4+
#include <algorithm>
5+
#include <vector>
6+
#include <optional>
7+
#include <map>
8+
9+
#include "alright_fonts.hpp"
10+
11+
using namespace pretty_poly;
12+
13+
namespace alright_fonts {
14+
/*
15+
utility functions
16+
*/
17+
pretty_poly::rect_t measure_character(text_metrics_t &tm, uint16_t codepoint) {
18+
if(tm.face.glyphs.count(codepoint) == 1) {
19+
glyph_t glyph = tm.face.glyphs[codepoint];
20+
21+
return {0, 0, ((glyph.advance * tm.size) / 128), tm.size};
22+
}
23+
24+
return {0, 0, 0, 0};
25+
}
26+
27+
/*
28+
render functions
29+
*/
30+
31+
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin) {
32+
if(tm.face.glyphs.count(codepoint) == 1) {
33+
glyph_t glyph = tm.face.glyphs[codepoint];
34+
35+
// scale is a fixed point 16:16 value, our font data is already scaled to
36+
// -128..127 so to get the pixel size we want we can just shift the
37+
// users requested size up one bit
38+
unsigned scale = tm.size << 9;
39+
40+
pretty_poly::draw_polygon<int8_t>(glyph.contours, origin, scale);
41+
}
42+
}
43+
44+
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin, pretty_poly::mat3_t transform) {
45+
if(tm.face.glyphs.count(codepoint) == 1) {
46+
glyph_t glyph = tm.face.glyphs[codepoint];
47+
48+
// scale is a fixed point 16:16 value, our font data is already scaled to
49+
// -128..127 so to get the pixel size we want we can just shift the
50+
// users requested size up one bit
51+
unsigned scale = tm.size << 9;
52+
53+
std::vector<pretty_poly::contour_t<int8_t>> contours;
54+
55+
for(auto i = 0u; i < glyph.contours.size(); i++) {
56+
unsigned int count = glyph.contours[i].count;
57+
point_t<int8_t> *points = (point_t<int8_t> *)malloc(sizeof(point_t<int8_t>) * count);
58+
for(auto j = 0u; j < count; j++) {
59+
point_t<float> point(glyph.contours[i].points[j].x, glyph.contours[i].points[j].y);
60+
point *= transform;
61+
points[j] = point_t<int8_t>(point.x, point.y);
62+
}
63+
contours.emplace_back(points, count);
64+
}
65+
66+
pretty_poly::draw_polygon<int8_t>(contours, origin, scale);
67+
68+
for(auto contour : contours) {
69+
free(contour.points);
70+
}
71+
}
72+
}
73+
74+
/*
75+
load functions
76+
*/
77+
78+
// big endian stream value helpers
79+
uint16_t ru16(file_io &ifs) {uint8_t w[2]; ifs.read((char *)w, 2); return w[0] << 8 | w[1];}
80+
int16_t rs16(file_io &ifs) {uint8_t w[2]; ifs.read((char *)w, 2); return w[0] << 8 | w[1];}
81+
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];}
82+
uint8_t ru8(file_io &ifs) {uint8_t w; ifs.read(&w, 1); return w;}
83+
int8_t rs8(file_io &ifs) {int8_t w; ifs.read(&w, 1); return w;}
84+
85+
bool face_t::load(file_io &ifs) {
86+
char marker[4];
87+
ifs.read(marker, sizeof(marker));
88+
89+
// check header magic bytes are present
90+
if(memcmp(marker, "af!?", 4) != 0) {
91+
// doesn't start with magic marker
92+
return false;
93+
}
94+
95+
// number of glyphs embedded in font file
96+
this->glyph_count = ru16(ifs);
97+
98+
// extract flags and ensure none set
99+
this->flags = ru16(ifs);
100+
if(this->flags != 0) {
101+
// unknown flags set
102+
return false;
103+
}
104+
105+
// extract glyph dictionary
106+
uint16_t glyph_entry_size = 9;
107+
uint32_t contour_data_offset = 8 + this->glyph_count * glyph_entry_size;
108+
for(auto i = 0; i < this->glyph_count; i++) {
109+
glyph_t g;
110+
g.codepoint = ru16(ifs);
111+
g.bounds.x = rs8(ifs);
112+
g.bounds.y = rs8(ifs);
113+
g.bounds.w = ru8(ifs);
114+
g.bounds.h = ru8(ifs);
115+
g.advance = ru8(ifs);
116+
117+
if(ifs.fail()) {
118+
// could not read glyph dictionary entry
119+
return false;
120+
}
121+
122+
// allocate space for the contour data and read it from the font file
123+
uint16_t contour_data_length = ru16(ifs);
124+
125+
// remember where we are in the dictionary
126+
int pos = ifs.tell();
127+
128+
// read contour data
129+
ifs.seek(contour_data_offset);
130+
while(true) {
131+
// get number of points in contour
132+
uint16_t count = ru16(ifs);
133+
134+
// if count is zero then this is the end of contour marker
135+
if(count == 0) {
136+
break;
137+
}
138+
139+
// allocate space to store point data for contour and read
140+
// from file
141+
pretty_poly::point_t<int8_t> *points = new pretty_poly::point_t<int8_t>[count];
142+
ifs.read((char *)points, count * 2);
143+
144+
g.contours.push_back({points, count});
145+
}
146+
147+
// return back to position in dictionary
148+
ifs.seek(pos);
149+
contour_data_offset += contour_data_length;
150+
151+
if(ifs.fail()) {
152+
// could not read glyph contour data
153+
return false;
154+
}
155+
156+
this->glyphs[g.codepoint] = g;
157+
}
158+
159+
return true;
160+
}
161+
162+
bool face_t::load(std::string_view path) {
163+
file_io ifs(path);
164+
if(ifs.fail()) {
165+
// could not open file
166+
return false;
167+
}
168+
return load(ifs);
169+
}
170+
171+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include <cstdint>
2+
#include <math.h>
3+
#include <string.h>
4+
#include <algorithm>
5+
#include <vector>
6+
#include <optional>
7+
#include <map>
8+
9+
#include "pretty_poly.hpp"
10+
11+
namespace alright_fonts {
12+
13+
struct glyph_t {
14+
uint16_t codepoint;
15+
pretty_poly::rect_t bounds;
16+
uint8_t advance;
17+
std::vector<pretty_poly::contour_t<int8_t>> contours;
18+
};
19+
20+
struct face_t {
21+
uint16_t glyph_count;
22+
uint16_t flags;
23+
std::map<uint16_t, glyph_t> glyphs;
24+
25+
face_t() {};
26+
face_t(pretty_poly::file_io &ifs) {load(ifs);}
27+
face_t(std::string_view path) {load(path);}
28+
29+
bool load(pretty_poly::file_io &ifs);
30+
bool load(std::string_view path);
31+
};
32+
33+
enum alignment_t {
34+
left = 0,
35+
center = 1,
36+
right = 2,
37+
justify = 4,
38+
top = 8,
39+
bottom = 16
40+
};
41+
42+
struct text_metrics_t {
43+
face_t face; // font to write in
44+
int size; // text size in pixels
45+
uint scroll; // vertical scroll offset
46+
int line_height; // spacing between lines (%)
47+
int letter_spacing; // spacing between characters
48+
int word_spacing; // spacing between words
49+
alignment_t align; // horizontal and vertical alignment
50+
//optional<mat3_t> transform; // arbitrary transformation
51+
pretty_poly::antialias_t antialiasing = pretty_poly::X4; // level of antialiasing to apply
52+
53+
void set_size(int s) {
54+
size = s;
55+
line_height = size;
56+
letter_spacing = 0;
57+
word_spacing = size / 2;
58+
}
59+
60+
text_metrics_t() {};
61+
};
62+
63+
/*
64+
utility functions
65+
*/
66+
pretty_poly::rect_t measure_character(text_metrics_t &tm, uint16_t codepoint);
67+
68+
/*
69+
render functions
70+
*/
71+
72+
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin);
73+
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin, pretty_poly::mat3_t transform);
74+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
add_library(pico_vector
2+
${CMAKE_CURRENT_LIST_DIR}/pico_vector.cpp
3+
${CMAKE_CURRENT_LIST_DIR}/pretty_poly.cpp
4+
${CMAKE_CURRENT_LIST_DIR}/alright_fonts.cpp
5+
)
6+
7+
target_include_directories(pico_vector INTERFACE ${CMAKE_CURRENT_LIST_DIR})
8+
9+
target_link_libraries(pico_vector pico_stdlib)

0 commit comments

Comments
 (0)