Merge pull request #326 from pimoroni/feature/font-rework

Hershey & Pixel fonts as libraries + Pixel fonts for Badger 2040
rewrite/pico-wireless
Philip Howard 2022-03-30 15:24:50 +01:00 zatwierdzone przez GitHub
commit 9926481385
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
24 zmienionych plików z 385 dodań i 1025 usunięć

Wyświetl plik

@ -1,3 +1,5 @@
add_subdirectory(hershey_fonts)
add_subdirectory(bitmap_fonts)
add_subdirectory(breakout_dotmatrix)
add_subdirectory(breakout_encoder)
add_subdirectory(breakout_ioexpander)

Wyświetl plik

@ -8,5 +8,4 @@ target_sources(${LIB_NAME} INTERFACE
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib hardware_pwm uc8151)
target_link_libraries(${LIB_NAME} INTERFACE bitmap_fonts hershey_fonts pico_stdlib hardware_pwm uc8151)

Wyświetl plik

@ -322,103 +322,66 @@ namespace pimoroni {
uc8151.update(blocking);
}
const hershey_font_glyph_t* Badger2040::glyph_data(unsigned char c) {
if(c < 32 || c > 127) {
return nullptr;
}
return &_font->chars[c - 32];
}
inline float deg2rad(float degrees) {
return (degrees * M_PI) / 180.0f;
const hershey::font_glyph_t* Badger2040::glyph_data(unsigned char c) {
return hershey::glyph_data(_font, c);
}
int32_t Badger2040::glyph(unsigned char c, int32_t x, int32_t y, float s, float a) {
const hershey_font_glyph_t *gd = glyph_data(c);
// if glyph data not found (id too great) then skip
if(!gd) {
return 0;
}
a = deg2rad(a);
float as = sin(a);
float ac = cos(a);
const int8_t *pv = gd->vertices;
int8_t cx = (*pv++) * s;
int8_t cy = (*pv++) * s;
bool pen_down = true;
for(uint32_t i = 1; i < gd->vertex_count; i++) {
if(pv[0] == -128 && pv[1] == -128) {
pen_down = false;
pv += 2;
}else{
int8_t nx = (*pv++) * s;
int8_t ny = (*pv++) * s;
int rcx = (cx * ac - cy * as) + 0.5f;
int rcy = (cx * as + cy * ac) + 0.5f;
int rnx = (nx * ac - ny * as) + 0.5f;
int rny = (nx * as + ny * ac) + 0.5f;
if(pen_down) {
line(rcx + x, rcy + y, rnx + x, rny + y);
if (_bitmap_font) {
bitmap::character(_bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) {
for(auto px = 0; px < w; px++) {
for(auto py = 0; py < h; py++) {
pixel(x + px, y + py);
}
}
cx = nx;
cy = ny;
pen_down = true;
}
}, c, x, y, std::max(1.0f, s));
return 0;
} else {
return hershey::glyph(_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
line(x1, y1, x2, y2);
}, c, x, y, s, a);
}
return gd->width * s;
}
void Badger2040::text(std::string message, int32_t x, int32_t y, float s, float a) {
int32_t cx = x;
int32_t cy = y;
int32_t ox = 0;
float as = sin(deg2rad(a));
float ac = cos(deg2rad(a));
for(auto &c : message) {
int rcx = (ox * ac) + 0.5f;
int rcy = (ox * as) + 0.5f;
ox += glyph(c, cx + rcx, cy + rcy, s, a);
if (_bitmap_font) {
bitmap::text(_bitmap_font, [this](int32_t x, int32_t y, int32_t w, int32_t h) {
for(auto px = 0; px < w; px++) {
for(auto py = 0; py < h; py++) {
pixel(x + px, y + py);
}
}
}, message, x, y, 296 - x, std::max(1.0f, s));
} else {
hershey::text(_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
line(x1, y1, x2, y2);
}, message, x, y, s, a);
}
}
int32_t Badger2040::measure_text(std::string message, float s) {
int32_t width = 0;
for(auto &c : message) {
width += measure_glyph(c, s);
}
return width;
if (_bitmap_font) return bitmap::measure_text(_bitmap_font, message, std::max(1.0f, s));
return hershey::measure_text(_font, message, s);
}
int32_t Badger2040::measure_glyph(unsigned char c, float s) {
const hershey_font_glyph_t *gd = glyph_data(c);
// if glyph data not found (id too great) then skip
if(!gd) {
return 0;
}
return gd->width * s;
if (_bitmap_font) return bitmap::measure_character(_bitmap_font, c, std::max(1.0f, s));
return hershey::measure_glyph(_font, c, s);
}
void Badger2040::font(std::string name) {
// check that font exists and assign it
if(fonts.find(name) != fonts.end()) {
_font = fonts[name];
if (name == "bitmap6") {
_bitmap_font = &font6;
_font = nullptr;
} else if (name == "bitmap8") {
_bitmap_font = &font8;
_font = nullptr;
} else {
// check that font exists and assign it
if(hershey::fonts.find(name) != hershey::fonts.end()) {
_bitmap_font = nullptr;
_font = hershey::fonts[name];
}
}
}

Wyświetl plik

@ -4,14 +4,18 @@
#include "drivers/uc8151/uc8151.hpp"
#include "fonts.hpp"
#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"
namespace pimoroni {
class Badger2040 {
protected:
UC8151 uc8151;
const hershey_font_t *_font = &futural;
const hershey::font_t *_font = &hershey::futural;
const bitmap::font_t *_bitmap_font = nullptr;
uint8_t _pen = 0;
uint8_t _thickness = 1;
uint32_t _button_states = 0;
@ -62,7 +66,7 @@ namespace pimoroni {
void image(const uint8_t *data, int stride, int sx, int sy, int dw, int dh, int dx, int dy);
// text (fonts: sans, sans_bold, gothic, cursive_bold, cursive, serif_italic, serif, serif_bold)
const hershey_font_glyph_t* glyph_data(unsigned char c);
const hershey::font_glyph_t* glyph_data(unsigned char c);
void text(std::string message, int32_t x, int32_t y, float s = 1.0f, float a = 0.0f);
int32_t glyph(unsigned char c, int32_t x, int32_t y, float s = 1.0f, float a = 0.0f);

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1 @@
include(bitmap_fonts.cmake)

Wyświetl plik

@ -0,0 +1,6 @@
add_library(bitmap_fonts
${CMAKE_CURRENT_LIST_DIR}/bitmap_fonts.cpp
)
target_include_directories(bitmap_fonts INTERFACE ${CMAKE_CURRENT_LIST_DIR})

Wyświetl plik

@ -0,0 +1,67 @@
#include "bitmap_fonts.hpp"
namespace bitmap {
int32_t measure_character(const font_t *font, const char c, const uint8_t scale) {
uint8_t char_index = c - 32;
return font->widths[char_index] * scale;
}
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale) {
int32_t text_width = 0;
for(auto c : t) {
text_width += measure_character(font, c, scale);
}
return text_width;
}
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale) {
uint8_t char_index = c - 32;
const uint8_t *d = &font->data[char_index * font->max_width];
for(uint8_t cx = 0; cx < font->widths[char_index]; cx++) {
for(uint8_t cy = 0; cy < font->height; cy++) {
if((1U << cy) & *d) {
rectangle(x + (cx * scale), y + (cy * scale), scale, scale);
}
}
d++;
}
}
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale) {
uint32_t co = 0, lo = 0; // character and line (if wrapping) offset
size_t i = 0;
while(i < t.length()) {
// find length of current word
size_t next_space = t.find(' ', i + 1);
if(next_space == std::string::npos) {
next_space = t.length();
}
uint16_t word_width = 0;
for(size_t j = i; j < next_space; j++) {
word_width += font->widths[t[j] - 32] * scale;
}
// if this word would exceed the wrap limit then
// move to the next line
if(co != 0 && co + word_width > (uint32_t)wrap) {
co = 0;
lo += (font->height + 1) * scale;
}
// draw word
for(size_t j = i; j < next_space; j++) {
character(font, rectangle, t[j], x + co, y + lo, scale);
co += font->widths[t[j] - 32] * scale;
}
// move character offset to end of word and add a space
co += font->widths[0] * scale;
i = next_space + 1;
}
}
}

Wyświetl plik

@ -0,0 +1,22 @@
#pragma once
#include <functional>
#include <string>
#include <cstdint>
namespace bitmap {
struct font_t {
const uint8_t height;
const uint8_t max_width;
const uint8_t widths[96];
const uint8_t data[];
};
typedef std::function<void(int32_t x, int32_t y, int32_t w, int32_t h)> rect_func;
int32_t measure_character(const font_t *font, const char c, const uint8_t scale);
int32_t measure_text(const font_t *font, const std::string &t, const uint8_t scale);
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2);
void text(const font_t *font, rect_func rectangle, const std::string &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2);
}

Wyświetl plik

@ -1,8 +1,8 @@
#pragma once
#include "font.hpp"
#include "bitmap_fonts.hpp"
const pimoroni::Font font6 {
const bitmap::font_t font6 {
.height = 6,
.max_width = 6,
.widths = {

Wyświetl plik

@ -1,8 +1,8 @@
#pragma once
#include "font.hpp"
#include "bitmap_fonts.hpp"
const pimoroni::Font font8 {
const bitmap::font_t font8 {
.height = 8,
.max_width = 6,
.widths = {

Wyświetl plik

@ -0,0 +1 @@
include(hershey_fonts.cmake)

Wyświetl plik

@ -0,0 +1,9 @@
set(LIB_NAME hershey_fonts)
add_library(${LIB_NAME} INTERFACE)
target_sources(${LIB_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}_data.cpp
)
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})

Wyświetl plik

@ -0,0 +1,107 @@
#include "hershey_fonts.hpp"
#include <cmath>
namespace hershey {
std::map<std::string, const font_t*> fonts = {
{ "sans", &futural },
//{ "sans_bold", &futuram },
{ "gothic", &gothgbt },
//{ "cursive_bold", &scriptc },
{ "cursive", &scripts },
{ "serif_italic", &timesi },
{ "serif", &timesr },
//{ "serif_bold", &timesrb }
};
inline float deg2rad(float degrees) {
return (degrees * M_PI) / 180.0f;
}
const font_glyph_t* glyph_data(const font_t* font, unsigned char c) {
if(c < 32 || c > 127) {
return nullptr;
}
return &font->chars[c - 32];
}
int32_t measure_glyph(const font_t* font, unsigned char c, float s) {
const font_glyph_t *gd = glyph_data(font, c);
// if glyph data not found (id too great) then skip
if(!gd) {
return 0;
}
return gd->width * s;
}
int32_t measure_text(const font_t* font, std::string message, float s) {
int32_t width = 0;
for(auto &c : message) {
width += measure_glyph(font, c, s);
}
return width;
}
int32_t glyph(const font_t* font, line_func line, unsigned char c, int32_t x, int32_t y, float s, float a) {
const font_glyph_t *gd = glyph_data(font, c);
// if glyph data not found (id too great) then skip
if(!gd) {
return 0;
}
a = deg2rad(a);
float as = sin(a);
float ac = cos(a);
const int8_t *pv = gd->vertices;
int8_t cx = (*pv++) * s;
int8_t cy = (*pv++) * s;
bool pen_down = true;
for(uint32_t i = 1; i < gd->vertex_count; i++) {
if(pv[0] == -128 && pv[1] == -128) {
pen_down = false;
pv += 2;
}else{
int8_t nx = (*pv++) * s;
int8_t ny = (*pv++) * s;
int rcx = (cx * ac - cy * as) + 0.5f;
int rcy = (cx * as + cy * ac) + 0.5f;
int rnx = (nx * ac - ny * as) + 0.5f;
int rny = (nx * as + ny * ac) + 0.5f;
if(pen_down) {
line(rcx + x, rcy + y, rnx + x, rny + y);
}
cx = nx;
cy = ny;
pen_down = true;
}
}
return gd->width * s;
}
void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a) {
int32_t cx = x;
int32_t cy = y;
int32_t ox = 0;
float as = sin(deg2rad(a));
float ac = cos(deg2rad(a));
for(auto &c : message) {
int rcx = (ox * ac) + 0.5f;
int rcy = (ox * as) + 0.5f;
ox += glyph(font, line, c, cx + rcx, cy + rcy, s, a);
}
}
}

Wyświetl plik

@ -0,0 +1,50 @@
#include <map>
#include <string>
#include <functional>
namespace hershey {
struct font_glyph_t {
uint32_t width; // character width
uint32_t vertex_count; // number of vertices
const int8_t *vertices; // vertex data (indices: even = x, odd = y)
};
struct font_t {
font_glyph_t chars[95];
};
extern const int8_t futural_vertices[2442];
extern const font_t futural;
extern const int8_t futuram_vertices[4802];
extern const font_t futuram;
extern const int8_t gothgbt_vertices[9046];
extern const font_t gothgbt;
extern const int8_t scriptc_vertices[5530];
extern const font_t scriptc;
extern const int8_t scripts_vertices[4472];
extern const font_t scripts;
extern const int8_t timesi_vertices[4848];
extern const font_t timesi;
extern const int8_t timesr_vertices[4600];
extern const font_t timesr;
extern const int8_t timesrb_vertices[7994];
extern const font_t timesrb;
typedef std::function<void(int32_t x1, int32_t y1, int32_t x2, int32_t y2)> line_func;
extern std::map<std::string, const font_t*> fonts;
inline float deg2rad(float degrees);
const font_glyph_t* glyph_data(const font_t* font, unsigned char c);
int32_t measure_glyph(const font_t* font, unsigned char c, float s);
int32_t measure_text(const font_t* font, std::string message, float s);
int32_t glyph(const font_t* font, line_func line, unsigned char c, int32_t x, int32_t y, float s, float a);
void text(const font_t* font, line_func line, std::string message, int32_t x, int32_t y, float s, float a);
}

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -1,12 +0,0 @@
#pragma once
#include <cstdint>
namespace pimoroni {
struct Font {
const uint8_t height;
const uint8_t max_width;
const uint8_t widths[96];
const uint8_t data[];
};
}

Wyświetl plik

@ -5,3 +5,4 @@ add_library(pico_graphics
target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(pico_graphics bitmap_fonts)

Wyświetl plik

@ -6,7 +6,7 @@ namespace pimoroni {
set_font(&font6);
};
void PicoGraphics::set_font(const Font *font){
void PicoGraphics::set_font(const bitmap::font_t *font){
this->font = font;
}
@ -110,57 +110,15 @@ namespace pimoroni {
}
void PicoGraphics::character(const char c, const Point &p, uint8_t scale) {
uint8_t char_index = c - 32;
Rect char_bounds(p.x, p.y, font->widths[char_index] * scale, font->height * scale);
if(!clip.intersects(char_bounds)) return;
const uint8_t *d = &font->data[char_index * font->max_width];
for(uint8_t cx = 0; cx < font->widths[char_index]; cx++) {
for(uint8_t cy = 0; cy < font->height; cy++) {
if((1U << cy) & *d) {
rectangle(Rect(p.x + (cx * scale), p.y + (cy * scale), scale, scale));
}
}
d++;
}
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::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) {
uint32_t co = 0, lo = 0; // character and line (if wrapping) offset
size_t i = 0;
while(i < t.length()) {
// find length of current word
size_t next_space = t.find(' ', i + 1);
if(next_space == std::string::npos) {
next_space = t.length();
}
uint16_t word_width = 0;
for(size_t j = i; j < next_space; j++) {
word_width += font->widths[t[j] - 32] * scale;
}
// if this word would exceed the wrap limit then
// move to the next line
if(co != 0 && co + word_width > (uint32_t)wrap) {
co = 0;
lo += (font->height + 1) * scale;
}
// draw word
for(size_t j = i; j < next_space; j++) {
character(t[j], Point(p.x + co, p.y + lo), scale);
co += font->widths[t[j] - 32] * scale;
}
// move character offset to end of word and add a space
co += font->widths[0] * scale;
i = next_space + 1;
}
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);
}
int32_t orient2d(Point p1, Point p2, Point p3) {

Wyświetl plik

@ -4,7 +4,7 @@
#include <cstdint>
#include <algorithm>
#include <vector>
#include "font6_data.hpp"
#include "libraries/bitmap_fonts/font6_data.hpp"
// a tiny little graphics library for our Pico products
// supports only 16-bit (565) RGB framebuffers
@ -52,11 +52,11 @@ namespace pimoroni {
Pen pen;
const Font *font;
const bitmap::font_t *font;
public:
PicoGraphics(uint16_t width, uint16_t height, uint16_t *frame_buffer);
void set_font(const Font *font);
void set_font(const bitmap::font_t *font);
void set_pen(uint8_t r, uint8_t g, uint8_t b);
void set_pen(Pen p);

Wyświetl plik

@ -29,6 +29,9 @@ include(breakout_bmp280/micropython)
include(breakout_icp10125/micropython)
include(breakout_scd41/micropython)
include(hershey_fonts/micropython)
include(bitmap_fonts/micropython)
include(badger2040/micropython)
include(micropython/examples/badger2040/micropython-builtins)
include(plasma/micropython)

Wyświetl plik

@ -0,0 +1,14 @@
set(MOD_NAME bitmap_fonts)
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/bitmap_fonts/bitmap_fonts.cpp
)
target_include_directories(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/bitmap_fonts
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})

Wyświetl plik

@ -0,0 +1,15 @@
set(MOD_NAME hershey_fonts)
string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER)
add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/hershey_fonts/hershey_fonts.cpp
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/hershey_fonts/hershey_fonts_data.cpp
)
target_include_directories(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/../../../libraries/hershey_fonts
)
target_link_libraries(usermod INTERFACE usermod_${MOD_NAME})

Wyświetl plik

@ -38,6 +38,8 @@ include(pico_display_2/micropython)
include(pico_explorer/micropython)
include(pico_wireless/micropython)
include(bitmap_fonts/micropython)
include(plasma/micropython)
include(hub75/micropython)
include(servo/micropython)