-
Notifications
You must be signed in to change notification settings - Fork 497
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #783 from pimoroni/feature/ppaf
PicoVector.
- Loading branch information
Showing
22 changed files
with
1,944 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
#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 { | ||
/* | ||
utility functions | ||
*/ | ||
pretty_poly::rect_t measure_character(text_metrics_t &tm, uint16_t codepoint) { | ||
if(tm.face.glyphs.count(codepoint) == 1) { | ||
glyph_t glyph = tm.face.glyphs[codepoint]; | ||
|
||
return {0, 0, ((glyph.advance * tm.size) / 128), tm.size}; | ||
} | ||
|
||
return {0, 0, 0, 0}; | ||
} | ||
|
||
/* | ||
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); | ||
} | ||
} | ||
|
||
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin, pretty_poly::mat3_t transform) { | ||
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; | ||
|
||
std::vector<pretty_poly::contour_t<int8_t>> contours; | ||
|
||
for(auto i = 0u; i < glyph.contours.size(); i++) { | ||
unsigned int count = glyph.contours[i].count; | ||
point_t<int8_t> *points = (point_t<int8_t> *)malloc(sizeof(point_t<int8_t>) * count); | ||
for(auto j = 0u; j < count; j++) { | ||
point_t<float> point(glyph.contours[i].points[j].x, glyph.contours[i].points[j].y); | ||
point *= transform; | ||
points[j] = point_t<int8_t>(point.x, point.y); | ||
} | ||
contours.emplace_back(points, count); | ||
} | ||
|
||
pretty_poly::draw_polygon<int8_t>(contours, origin, scale); | ||
|
||
for(auto contour : contours) { | ||
free(contour.points); | ||
} | ||
} | ||
} | ||
|
||
/* | ||
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); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#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; | ||
letter_spacing = 0; | ||
word_spacing = size / 2; | ||
} | ||
|
||
text_metrics_t() {}; | ||
}; | ||
|
||
/* | ||
utility functions | ||
*/ | ||
pretty_poly::rect_t measure_character(text_metrics_t &tm, uint16_t codepoint); | ||
|
||
/* | ||
render functions | ||
*/ | ||
|
||
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin); | ||
void render_character(text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t<int> origin, pretty_poly::mat3_t transform); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
Oops, something went wrong.