kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Porównaj commity
17 Commity
225ecfcff9
...
34b8b4d81f
Autor | SHA1 | Data |
---|---|---|
Phil Howard | 34b8b4d81f | |
Phil Howard | a2c48a8f44 | |
Mike Bell | c1e0631102 | |
Jonathan Williamson | c91b498505 | |
Phil Howard | ad5120a8d2 | |
Mike Bell | 18d3ed3940 | |
Phil Howard | acf6e517f6 | |
Phil Howard | 896353af11 | |
Phil Howard | b184475bc0 | |
Phil Howard | d8c6883fc0 | |
Phil Howard | adfa429d47 | |
Phil Howard | d44f00886b | |
Mike Bell | 5f08e113bd | |
Mike Bell | 0807dc6810 | |
Mike Bell | 8471580c71 | |
Phil Howard | 6b0195a00b | |
Phil Howard | ab81c5df56 |
|
@ -37,10 +37,48 @@ Hub75::Hub75(uint width, uint height, Pixel *buffer, PanelType panel_type, bool
|
|||
}
|
||||
|
||||
if (brightness == 0) {
|
||||
#if PICO_RP2350
|
||||
brightness = 6;
|
||||
#else
|
||||
if (width >= 64) brightness = 6;
|
||||
if (width >= 96) brightness = 3;
|
||||
if (width >= 128) brightness = 2;
|
||||
if (width >= 160) brightness = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (color_order) {
|
||||
case COLOR_ORDER::RGB:
|
||||
r_shift = 0;
|
||||
g_shift = 10;
|
||||
b_shift = 20;
|
||||
break;
|
||||
case COLOR_ORDER::RBG:
|
||||
r_shift = 0;
|
||||
g_shift = 20;
|
||||
b_shift = 10;
|
||||
break;
|
||||
case COLOR_ORDER::GRB:
|
||||
r_shift = 20;
|
||||
g_shift = 0;
|
||||
b_shift = 10;
|
||||
break;
|
||||
case COLOR_ORDER::GBR:
|
||||
r_shift = 10;
|
||||
g_shift = 20;
|
||||
b_shift = 0;
|
||||
break;
|
||||
case COLOR_ORDER::BRG:
|
||||
r_shift = 10;
|
||||
g_shift = 00;
|
||||
b_shift = 20;
|
||||
break;
|
||||
case COLOR_ORDER::BGR:
|
||||
r_shift = 20;
|
||||
g_shift = 10;
|
||||
b_shift = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,26 +96,16 @@ void Hub75::set_color(uint x, uint y, Pixel c) {
|
|||
}
|
||||
|
||||
void Hub75::set_pixel(uint x, uint y, uint8_t r, uint8_t g, uint8_t b) {
|
||||
switch(color_order) {
|
||||
case COLOR_ORDER::RGB:
|
||||
set_color(x, y, Pixel(r, g, b));
|
||||
break;
|
||||
case COLOR_ORDER::RBG:
|
||||
set_color(x, y, Pixel(r, b, g));
|
||||
break;
|
||||
case COLOR_ORDER::GRB:
|
||||
set_color(x, y, Pixel(g, r, b));
|
||||
break;
|
||||
case COLOR_ORDER::GBR:
|
||||
set_color(x, y, Pixel(g, b, r));
|
||||
break;
|
||||
case COLOR_ORDER::BRG:
|
||||
set_color(x, y, Pixel(b, r, g));
|
||||
break;
|
||||
case COLOR_ORDER::BGR:
|
||||
set_color(x, y, Pixel(b, g, r));
|
||||
break;
|
||||
int offset = 0;
|
||||
if(x >= width || y >= height) return;
|
||||
if(y >= height / 2) {
|
||||
y -= height / 2;
|
||||
offset = (y * width + x) * 2;
|
||||
offset += 1;
|
||||
} else {
|
||||
offset = (y * width + x) * 2;
|
||||
}
|
||||
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
|
||||
}
|
||||
|
||||
void Hub75::FM6126A_write_register(uint16_t value, uint8_t position) {
|
||||
|
@ -249,28 +277,88 @@ void Hub75::dma_complete() {
|
|||
|
||||
void Hub75::update(PicoGraphics *graphics) {
|
||||
if(graphics->pen_type == PicoGraphics::PEN_RGB888) {
|
||||
uint32_t *p = (uint32_t *)graphics->frame_buffer;
|
||||
for(uint y = 0; y < height; y++) {
|
||||
for(uint x = 0; x < width; x++) {
|
||||
uint32_t col = *p;
|
||||
uint8_t r = (col & 0xff0000) >> 16;
|
||||
uint8_t g = (col & 0x00ff00) >> 8;
|
||||
uint8_t b = (col & 0x0000ff) >> 0;
|
||||
set_pixel(x, y, r, g, b);
|
||||
p++;
|
||||
uint8_t *p = (uint8_t *)graphics->frame_buffer;
|
||||
if(graphics->bounds.w == int32_t(width / 2) && graphics->bounds.h == int32_t(height * 2)) {
|
||||
for(int y = 0; y < graphics->bounds.h; y++) {
|
||||
int offsety = 0;
|
||||
int sy = y;
|
||||
int basex = 0;
|
||||
|
||||
// Assuming our canvas is 128x128 and our display is 256x64,
|
||||
// consisting of 2x128x64 panels, remap the bottom half
|
||||
// of the canvas to the right-half of the display,
|
||||
// This gives us an optional square arrangement.
|
||||
if (sy >= int(height)) {
|
||||
sy -= height;
|
||||
basex = width / 2;
|
||||
} else {
|
||||
// Awkward hack to *TEMPORARILY* rotate the top panel
|
||||
sy = height - 1 - sy;
|
||||
basex = (width / 2) - 1;
|
||||
}
|
||||
|
||||
// Interlace the top and bottom halves of the panel.
|
||||
// Since these are scanned out simultaneously to two chains
|
||||
// of shift registers we need each pair of rows
|
||||
// (N and N + height / 2) to be adjacent in the buffer.
|
||||
offsety = width * 2;
|
||||
if(sy >= int(height / 2)) {
|
||||
sy -= height / 2;
|
||||
offsety *= sy;
|
||||
offsety += 1;
|
||||
} else {
|
||||
offsety *= sy;
|
||||
}
|
||||
|
||||
for(int x = 0; x < graphics->bounds.w; x++) {
|
||||
int sx = x;
|
||||
uint8_t b = *p++;
|
||||
uint8_t g = *p++;
|
||||
uint8_t r = *p++;
|
||||
|
||||
// Assumes width / 2 is even.
|
||||
if (basex & 1) {
|
||||
sx = basex - sx;
|
||||
} else {
|
||||
sx += basex;
|
||||
}
|
||||
int offset = offsety + sx * 2;
|
||||
|
||||
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
|
||||
|
||||
// Skip the empty byte in out 32-bit aligned 24-bit colour.
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(graphics->pen_type == PicoGraphics::PEN_RGB565) {
|
||||
uint16_t *p = (uint16_t *)graphics->frame_buffer;
|
||||
for(uint y = 0; y < height; y++) {
|
||||
for(uint x = 0; x < width; x++) {
|
||||
uint16_t col = __builtin_bswap16(*p);
|
||||
uint8_t r = (col & 0b1111100000000000) >> 8;
|
||||
uint8_t g = (col & 0b0000011111100000) >> 3;
|
||||
uint8_t b = (col & 0b0000000000011111) << 3;
|
||||
set_pixel(x, y, r, g, b);
|
||||
p++;
|
||||
} else {
|
||||
for(uint y = 0; y < height; y++) {
|
||||
for(uint x = 0; x < width; x++) {
|
||||
int offset = 0;
|
||||
int sy = y;
|
||||
int sx = x;
|
||||
uint8_t b = *p++;
|
||||
uint8_t g = *p++;
|
||||
uint8_t r = *p++;
|
||||
|
||||
// Interlace the top and bottom halves of the panel.
|
||||
// Since these are scanned out simultaneously to two chains
|
||||
// of shift registers we need each pair of rows
|
||||
// (N and N + height / 2) to be adjacent in the buffer.
|
||||
offset = width * 2;
|
||||
if(sy >= int(height / 2)) {
|
||||
sy -= height / 2;
|
||||
offset *= sy;
|
||||
offset += 1;
|
||||
} else {
|
||||
offset *= sy;
|
||||
}
|
||||
offset += sx * 2;
|
||||
|
||||
back_buffer[offset] = (GAMMA_10BIT[b] << b_shift) | (GAMMA_10BIT[g] << g_shift) | (GAMMA_10BIT[r] << r_shift);
|
||||
|
||||
// Skip the empty byte in out 32-bit aligned 24-bit colour.
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,9 @@ class Hub75 {
|
|||
};
|
||||
uint width;
|
||||
uint height;
|
||||
uint r_shift = 0;
|
||||
uint g_shift = 10;
|
||||
uint b_shift = 20;
|
||||
Pixel *back_buffer;
|
||||
bool managed_buffer = false;
|
||||
PanelType panel_type;
|
||||
|
|
|
@ -51,7 +51,7 @@ int main() {
|
|||
pp_mat3_translate(&pos, 50, 50);
|
||||
pp_mat3_rotate(&pos, a);
|
||||
vector.draw(poly);
|
||||
vector.text("Hello World", &pos);
|
||||
vector.text("Hello World", 320, 240, &pos);
|
||||
|
||||
// update screen
|
||||
st7789.update(&graphics);
|
||||
|
|
|
@ -38,19 +38,35 @@ namespace pimoroni {
|
|||
}
|
||||
bool PicoGraphics_PenRGB888::render_tile(const Tile *tile) {
|
||||
for(int y = 0; y < tile->h; y++) {
|
||||
uint8_t *palpha = &tile->data[(y * tile->stride)];
|
||||
uint32_t *pdest = &((uint32_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
uint8_t *p_alpha = &tile->data[(y * tile->stride)];
|
||||
uint32_t *p_dest = &((uint32_t *)frame_buffer)[tile->x + ((tile->y + y) * bounds.w)];
|
||||
for(int x = 0; x < tile->w; x++) {
|
||||
uint8_t alpha = *palpha;
|
||||
uint16_t dest = *p_dest;
|
||||
uint8_t alpha = *p_alpha;
|
||||
|
||||
// TODO: Alpha blending
|
||||
if(alpha == 0) {
|
||||
if(alpha == 255) {
|
||||
*p_dest = color;
|
||||
}else if(alpha == 0) {
|
||||
} else {
|
||||
*pdest = color;
|
||||
// blend tha pixel
|
||||
uint32_t sr = (color >> 16) & 0xff;
|
||||
uint32_t sg = (color >> 8) & 0xff;
|
||||
uint32_t sb = (color >> 0) & 0xff;
|
||||
|
||||
uint32_t dr = (dest >> 16) & 0xff;
|
||||
uint32_t dg = (dest >> 8) & 0xff;
|
||||
uint32_t db = (dest >> 0) & 0xff;
|
||||
|
||||
uint8_t r = ((sr * alpha) + (dr * (255 - alpha))) >> 8;
|
||||
uint8_t g = ((sg * alpha) + (dg * (255 - alpha))) >> 8;
|
||||
uint8_t b = ((sb * alpha) + (db * (255 - alpha))) >> 8;
|
||||
|
||||
*p_dest = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
pdest++;
|
||||
palpha++;
|
||||
p_dest++;
|
||||
p_alpha++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <wchar.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifdef AF_MALLOC
|
||||
#ifndef PP_MALLOC
|
||||
|
@ -104,8 +105,8 @@ typedef struct {
|
|||
|
||||
bool af_load_font_file(AF_FILE file, af_face_t *face);
|
||||
void af_render_character(af_face_t *face, const char codepoint, af_text_metrics_t *tm);
|
||||
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
|
||||
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
|
||||
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm);
|
||||
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm);
|
||||
|
||||
#ifdef AF_USE_PRETTY_POLY
|
||||
#endif
|
||||
|
@ -240,20 +241,30 @@ void af_render_character(af_face_t *face, const char c, af_text_metrics_t *tm) {
|
|||
af_render_glyph(glyph, tm);
|
||||
}
|
||||
|
||||
int get_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
|
||||
int line_width = 0;
|
||||
char *end = (char *)text + tlen;
|
||||
float get_line_width(af_face_t *face, const char *text, size_t *tlen, float max_line_width, af_text_metrics_t *tm) {
|
||||
float line_width = 0;
|
||||
const char *start = text;
|
||||
const char *end = text + *tlen;
|
||||
const char *last_space = nullptr;
|
||||
for(char c = *text; text < end; text++, c = *text) {
|
||||
af_glyph_t *glyph = find_glyph(face, c);
|
||||
if(!glyph) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float char_width;
|
||||
if(c == L' ') {
|
||||
line_width += (glyph->advance * tm->word_spacing) / 100.0f;
|
||||
char_width = (glyph->advance * tm->word_spacing) / 100.0f;
|
||||
last_space = text;
|
||||
} else {
|
||||
line_width += (glyph->advance * tm->letter_spacing) / 100.0f;
|
||||
char_width = (glyph->advance * tm->letter_spacing) / 100.0f;
|
||||
}
|
||||
|
||||
if (max_line_width > 0 && line_width + char_width > max_line_width && last_space) {
|
||||
*tlen = last_space - start;
|
||||
break;
|
||||
}
|
||||
line_width += char_width;
|
||||
}
|
||||
return line_width;
|
||||
}
|
||||
|
@ -270,14 +281,14 @@ size_t line_length(const char *text, const char *end) {
|
|||
return line_ending - text;
|
||||
}
|
||||
|
||||
int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
|
||||
int max_width = 0;
|
||||
float get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
|
||||
float max_width = 0;
|
||||
char *line = (char *)text;
|
||||
char *tend = line + tlen;
|
||||
|
||||
size_t line_len = line_length(line, tend);
|
||||
while(line_len) {
|
||||
int width = get_line_width(face, line, line_len, tm);
|
||||
float width = get_line_width(face, line, &line_len, 0, tm);
|
||||
max_width = max_width < width ? width : max_width;
|
||||
line += line_len + 1;
|
||||
line_len = line_length(line, tend);
|
||||
|
@ -286,7 +297,7 @@ int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_m
|
|||
return max_width;
|
||||
}
|
||||
|
||||
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
|
||||
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm) {
|
||||
char *line = (char *)text;
|
||||
char *tend = line + tlen;
|
||||
size_t line_len = 0;
|
||||
|
@ -304,15 +315,23 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
|
|||
caret.y = 0;
|
||||
|
||||
// find maximum line length
|
||||
int max_line_width = get_max_line_width(face, text, tlen, tm);
|
||||
if (max_line_width == 0.f) {
|
||||
max_line_width = get_max_line_width(face, text, tlen, tm);
|
||||
} else {
|
||||
max_line_width /= scale;
|
||||
}
|
||||
if (max_height == 0.f) {
|
||||
max_height = FLT_MAX;
|
||||
} else {
|
||||
max_height /= scale;
|
||||
}
|
||||
|
||||
line_len = line_length(line, tend);
|
||||
|
||||
while(line_len) {
|
||||
while(line_len && caret.y + line_height <= max_height) {
|
||||
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
|
||||
char *end = line + line_len;
|
||||
|
||||
int line_width = get_line_width(face, line, line_len, tm);
|
||||
|
||||
for(char c = *line; line < end; line++, c = *line) {
|
||||
af_glyph_t *glyph = find_glyph(face, c);
|
||||
if(!glyph) {
|
||||
|
@ -331,7 +350,9 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
|
|||
pp_mat3_translate(&caret_transform, (max_line_width - line_width), 0);
|
||||
}
|
||||
|
||||
pp_transform(&caret_transform);
|
||||
pp_mat3_t final_transform = *old;
|
||||
pp_mat3_mul(&final_transform, &caret_transform);
|
||||
pp_transform(&final_transform);
|
||||
|
||||
af_render_glyph(glyph, tm);
|
||||
|
||||
|
@ -356,10 +377,10 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
|
|||
}
|
||||
|
||||
void _af_render(af_face_t *face, const char *text, af_text_metrics_t *tm) {
|
||||
af_render(face, text, strlen(text), tm);
|
||||
af_render(face, text, strlen(text), 0, 0, tm);
|
||||
}
|
||||
|
||||
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
|
||||
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm) {
|
||||
pp_rect_t result;
|
||||
bool first = true;
|
||||
char *line = (char *)text;
|
||||
|
@ -377,15 +398,14 @@ pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_met
|
|||
caret.y = 0;
|
||||
|
||||
// find maximum line length
|
||||
int max_line_width = get_max_line_width(face, text, tlen, tm);
|
||||
if (max_line_width == 0.f) max_line_width = get_max_line_width(face, text, tlen, tm);
|
||||
|
||||
line_len = line_length(line, tend);
|
||||
|
||||
while(line_len) {
|
||||
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
|
||||
char *end = line + line_len;
|
||||
|
||||
int line_width = get_line_width(face, line, line_len, tm);
|
||||
|
||||
for(char c = *line; line < end; line++, c = *line) {
|
||||
af_glyph_t *glyph = find_glyph(face, c);
|
||||
if(!glyph) {
|
||||
|
|
|
@ -60,93 +60,13 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
pp_point_t PicoVector::text(std::string_view text, pp_mat3_t *t) {
|
||||
pp_point_t PicoVector::text(std::string_view text, int max_width, int max_height, pp_mat3_t *t) {
|
||||
pp_point_t caret = {0, 0};
|
||||
|
||||
text_metrics.transform = t;
|
||||
|
||||
af_render(text_metrics.face, text.data(), text.size(), &text_metrics);
|
||||
af_render(text_metrics.face, text.data(), text.size(), max_width, max_height, &text_metrics);
|
||||
|
||||
return caret;
|
||||
/*
|
||||
// Align text from the bottom left
|
||||
caret.y += (PP_COORD_TYPE)text_metrics.line_height;
|
||||
|
||||
caret = pp_point_transform(&caret, t);
|
||||
caret.x += offset.x;
|
||||
caret.y += offset.y;
|
||||
|
||||
pp_point_t space;
|
||||
pp_point_t carriage_return = {0, -(PP_COORD_TYPE)text_metrics.line_height};
|
||||
|
||||
char spc = ' ';
|
||||
|
||||
space.x = af_measure(text_metrics.face, &spc, &text_metrics).w;
|
||||
if (space.x == 0) {
|
||||
space.x = text_metrics.word_spacing;
|
||||
}
|
||||
|
||||
space = pp_point_transform(&space, t);
|
||||
carriage_return = pp_point_transform(&carriage_return, t);
|
||||
|
||||
pp_point_t initial_carriage_return = carriage_return;
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
while(i < text.length()) {
|
||||
size_t next_space = text.find(' ', i + 1);
|
||||
|
||||
if(next_space == std::string::npos) {
|
||||
next_space = text.length();
|
||||
}
|
||||
|
||||
size_t next_linebreak = text.find('\n', i + 1);
|
||||
|
||||
if(next_linebreak == std::string::npos) {
|
||||
next_linebreak = text.length();
|
||||
}
|
||||
|
||||
size_t next_break = std::min(next_space, next_linebreak);
|
||||
|
||||
uint16_t word_width = 0;
|
||||
for(size_t j = i; j < next_break; j++) {
|
||||
word_width += af_measure(text_metrics.face, &text[j], &text_metrics).w;
|
||||
word_width += text_metrics.letter_spacing;
|
||||
}
|
||||
|
||||
if(caret.x != 0 && caret.x + word_width > graphics->clip.w) {
|
||||
caret = pp_point_sub(&caret, &carriage_return);
|
||||
carriage_return = initial_carriage_return;
|
||||
}
|
||||
|
||||
for(size_t j = i; j < std::min(next_break + 1, text.length()); j++) {
|
||||
if (text[j] == '\n') { // Linebreak
|
||||
caret = pp_point_sub(&caret, &carriage_return);
|
||||
carriage_return = initial_carriage_return;
|
||||
} else if (text[j] == ' ') { // Space
|
||||
caret = pp_point_add(&caret, &space);
|
||||
carriage_return = pp_point_add(&carriage_return, &space);
|
||||
} else {
|
||||
// apply the caret offset...
|
||||
pp_mat3_t pos = pp_mat3_identity();
|
||||
pp_mat3_mul(&pos, t);
|
||||
pp_mat3_translate(&pos, caret.x, caret.y);
|
||||
text_metrics.transform = &pos;
|
||||
af_render_character(text_metrics.face, text[j], &text_metrics);
|
||||
}
|
||||
pp_point_t advance = {
|
||||
(PP_COORD_TYPE)af_measure(text_metrics.face, &text[j], &text_metrics).w + text_metrics.letter_spacing,
|
||||
(PP_COORD_TYPE)0
|
||||
};
|
||||
advance = pp_point_transform(&advance, t);
|
||||
caret = pp_point_add(&caret, &advance);
|
||||
carriage_return = pp_point_add(&carriage_return, &advance);
|
||||
}
|
||||
|
||||
i = next_break + 1;
|
||||
}
|
||||
|
||||
return {caret.x, caret.y};
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -31,12 +31,22 @@ namespace pimoroni {
|
|||
class PicoVector {
|
||||
private:
|
||||
af_text_metrics_t text_metrics;
|
||||
// Hold copies of pretty-poly's pointers
|
||||
// so MicroPython does not garbage collect them!
|
||||
void *_pp_nodes;
|
||||
void *_pp_node_counts;
|
||||
|
||||
public:
|
||||
static PicoGraphics *graphics;
|
||||
PicoVector(PicoGraphics *graphics, void *mem = nullptr) {
|
||||
PicoVector(PicoGraphics *graphics) {
|
||||
PicoVector::graphics = graphics;
|
||||
|
||||
// TODO: Make these configurable?
|
||||
// Tile buffer size, Max nodes per scanline
|
||||
pp_init(16);
|
||||
_pp_nodes = pp_nodes;
|
||||
_pp_node_counts = pp_node_counts;
|
||||
|
||||
pp_tile_callback(PicoVector::tile_callback);
|
||||
|
||||
set_antialiasing(graphics->supports_alpha_blend() ? PP_AA_X4 : PP_AA_NONE);
|
||||
|
@ -48,11 +58,15 @@ namespace pimoroni {
|
|||
text_metrics.letter_spacing = 95;
|
||||
text_metrics.word_spacing = 200;
|
||||
text_metrics.size = 48;
|
||||
// Shoud be set before rendering chars
|
||||
// Should be set before rendering chars
|
||||
//text_metrics.transform = (pp_mat3_t *)af_malloc(sizeof(pp_mat3_t));
|
||||
//*text_metrics.transform = pp_mat3_identity();
|
||||
}
|
||||
|
||||
~PicoVector() {
|
||||
pp_deinit();
|
||||
}
|
||||
|
||||
static void tile_callback(const pp_tile_t *tile) {
|
||||
// TODO: we're using a cast here to avoid a hard dependency link between
|
||||
// PicoGraphics and PicoVector. These types might subtly mismatch, though...
|
||||
|
@ -85,7 +99,7 @@ namespace pimoroni {
|
|||
|
||||
pp_rect_t measure_text(std::string_view text, pp_mat3_t *t) {
|
||||
text_metrics.transform = t;
|
||||
return af_measure(text_metrics.face, text.data(), text.size(), &text_metrics);
|
||||
return af_measure(text_metrics.face, text.data(), text.size(), 0, &text_metrics);
|
||||
}
|
||||
|
||||
bool set_font(std::string_view font_path, unsigned int font_size) {
|
||||
|
@ -116,7 +130,7 @@ namespace pimoroni {
|
|||
return result;
|
||||
}
|
||||
|
||||
pp_point_t text(std::string_view text, pp_mat3_t *t=nullptr);
|
||||
pp_point_t text(std::string_view text, int max_width, int max_height, pp_mat3_t *t=nullptr);
|
||||
|
||||
void transform(pp_path_t *path, pp_mat3_t *t);
|
||||
void transform(pp_poly_t *poly, pp_mat3_t *t);
|
||||
|
|
|
@ -61,10 +61,25 @@ typedef struct {
|
|||
PP_COORD_TYPE f, t; // angle from and to
|
||||
} ppp_arc_def;
|
||||
|
||||
typedef struct {
|
||||
PP_COORD_TYPE x, y; // coordinates
|
||||
int c; // number of points on star
|
||||
PP_COORD_TYPE ro, ri; // outer and inner radius for points
|
||||
PP_COORD_TYPE s; // stroke thickness (0 == filled)
|
||||
} ppp_star_def;
|
||||
|
||||
typedef struct {
|
||||
PP_COORD_TYPE x1, y1; // start point
|
||||
PP_COORD_TYPE x2, y2; // end point
|
||||
PP_COORD_TYPE s; // thickness
|
||||
} ppp_line_def;
|
||||
|
||||
pp_poly_t* ppp_rect(ppp_rect_def d);
|
||||
pp_poly_t* ppp_regular(ppp_regular_def d);
|
||||
pp_poly_t* ppp_circle(ppp_circle_def d);
|
||||
pp_poly_t* ppp_arc(ppp_arc_def d);
|
||||
pp_poly_t* ppp_star(ppp_star_def d);
|
||||
pp_poly_t* ppp_line(ppp_line_def d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -176,6 +191,36 @@ pp_poly_t* ppp_arc(ppp_arc_def d) {
|
|||
return poly;
|
||||
}
|
||||
|
||||
pp_poly_t* ppp_star(ppp_star_def d) {
|
||||
pp_poly_t *poly = pp_poly_new();
|
||||
pp_path_t *path = pp_poly_add_path(poly);
|
||||
pp_path_t *inner = d.s != 0.0f ? pp_poly_add_path(poly) : NULL;
|
||||
for(int i = 0; i < d.c * 2; i++) {
|
||||
float step = ((M_PI * 2) / (float)(d.c * 2)) * (float)i;
|
||||
PP_COORD_TYPE r = i % 2 == 0 ? d.ro : d.ri;
|
||||
pp_path_add_point(path, (pp_point_t){sin(step) * r + d.x, cos(step) * r + d.y});
|
||||
if(inner) { // append the inner path
|
||||
PP_COORD_TYPE ior = d.ro - (d.s * d.ro / d.ri);
|
||||
PP_COORD_TYPE iir = d.ri - d.s;
|
||||
PP_COORD_TYPE ir = i % 2 == 0 ? ior : iir;
|
||||
pp_path_add_point(inner, (pp_point_t){sin(step) * ir + d.x, cos(step) * ir + d.y});
|
||||
}
|
||||
}
|
||||
return poly;
|
||||
}
|
||||
|
||||
pp_poly_t* ppp_line(ppp_line_def d) {
|
||||
pp_poly_t *poly = pp_poly_new();
|
||||
pp_path_t *path = pp_poly_add_path(poly);
|
||||
// create a normalised perpendicular vector
|
||||
pp_point_t v = {d.y2 - d.y1, d.x2 - d.x1};
|
||||
float mag = sqrt(v.x * v.x + v.y * v.y);
|
||||
v.x /= mag; v.y /= mag; v.x *= -(d.s / 2.0f); v.y *= (d.s / 2.0f);
|
||||
pp_point_t points[] = {{d.x1 + v.x, d.y1 + v.y}, {d.x2 + v.x, d.y2 + v.y}, {d.x2 - v.x, d.y2 - v.y}, {d.x1 - v.x, d.y1 - v.y}};
|
||||
pp_path_add_points(path, points, 4);
|
||||
return poly;
|
||||
}
|
||||
|
||||
#endif // PPP_IMPLEMENTATION
|
||||
|
||||
#endif // PPP_INCLUDE_H
|
|
@ -40,10 +40,6 @@
|
|||
#define PP_COORD_TYPE float
|
||||
#endif
|
||||
|
||||
#ifndef PP_MAX_NODES_PER_SCANLINE
|
||||
#define PP_MAX_NODES_PER_SCANLINE 16
|
||||
#endif
|
||||
|
||||
#ifndef PP_TILE_BUFFER_SIZE
|
||||
#define PP_TILE_BUFFER_SIZE 64
|
||||
#endif
|
||||
|
@ -131,12 +127,20 @@ extern pp_tile_callback_t _pp_tile_callback;
|
|||
extern pp_antialias_t _pp_antialias;
|
||||
extern pp_mat3_t *_pp_transform;
|
||||
|
||||
// Our parent scope might want to hold a pointer to these
|
||||
// ie: MicroPython to avoid garbage collection
|
||||
extern int32_t *pp_nodes;
|
||||
extern uint32_t *pp_node_counts;
|
||||
|
||||
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h);
|
||||
void pp_tile_callback(pp_tile_callback_t callback);
|
||||
void pp_antialias(pp_antialias_t antialias);
|
||||
pp_mat3_t *pp_transform(pp_mat3_t *transform);
|
||||
void pp_render(pp_poly_t *polygon);
|
||||
|
||||
void pp_init(uint32_t max_nodes_per_scanline);
|
||||
void pp_deinit();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -380,19 +384,33 @@ pp_rect_t pp_poly_bounds(pp_poly_t *p) {
|
|||
return b;
|
||||
}
|
||||
|
||||
uint32_t _pp_max_nodes_per_scanline = 0;
|
||||
|
||||
// buffer that each tile is rendered into before callback
|
||||
// allocate one extra byte to allow a small optimization in the row renderer
|
||||
// This allocates 4k up-front to ensure it's stored in Pico's RAM
|
||||
// Rather than potentially allocating into PSRAM at runtime and trashing perf
|
||||
uint8_t pp_tile_buffer[PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE];
|
||||
|
||||
// polygon node buffer handles at most 16 line intersections per scanline
|
||||
// is this enough for cjk/emoji? (requires a 2kB buffer)
|
||||
int32_t pp_nodes[PP_TILE_BUFFER_SIZE * 4][PP_MAX_NODES_PER_SCANLINE * 2];
|
||||
uint32_t pp_node_counts[PP_TILE_BUFFER_SIZE * 4];
|
||||
int32_t *pp_nodes;
|
||||
uint32_t *pp_node_counts;
|
||||
|
||||
uint8_t _pp_alpha_map_none[2] = {0, 255};
|
||||
uint8_t _pp_alpha_map_x4[5] = {0, 63, 127, 190, 255};
|
||||
uint8_t _pp_alpha_map_x16[17] = {0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255};
|
||||
|
||||
void pp_init(uint32_t max_nodes_per_scanline) {
|
||||
_pp_max_nodes_per_scanline = max_nodes_per_scanline;
|
||||
pp_nodes = (int32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * max_nodes_per_scanline * 2 * sizeof(int32_t));
|
||||
pp_node_counts = (uint32_t *)PP_MALLOC(PP_TILE_BUFFER_SIZE * 4 * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void pp_deinit() {
|
||||
PP_FREE(pp_nodes);
|
||||
PP_FREE(pp_node_counts);
|
||||
}
|
||||
|
||||
void pp_clip(int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
_pp_clip = (pp_rect_t){.x = x, .y = y, .w = w, .h = h};
|
||||
}
|
||||
|
@ -482,7 +500,10 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
|
|||
// }
|
||||
// #else
|
||||
// loop over scanlines
|
||||
|
||||
while(count--) {
|
||||
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
|
||||
|
||||
// consume accumulated error
|
||||
while(e > dy) {e -= dy; x += xinc;}
|
||||
|
||||
|
@ -490,7 +511,7 @@ void add_line_segment_to_nodes(const pp_point_t start, const pp_point_t end, pp_
|
|||
int nx = _pp_max(_pp_min(x, (tb->w << _pp_antialias)), 0);
|
||||
//debug(" + adding node at %d, %d\n", x, y);
|
||||
// add node to node list
|
||||
pp_nodes[y][pp_node_counts[y]++] = nx;
|
||||
pp_scanline_nodes[pp_node_counts[y]++] = nx;
|
||||
|
||||
// step to next scanline and accumulate error
|
||||
y++;
|
||||
|
@ -530,18 +551,19 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
|
|||
debug(" + render tile %d, %d - %d, %d\n", tb->x, tb->y, tb->w, tb->h);
|
||||
|
||||
for(int y = 0; y < ((int)PP_TILE_BUFFER_SIZE << _pp_antialias); y++) {
|
||||
int32_t *pp_scanline_nodes = &pp_nodes[y * _pp_max_nodes_per_scanline * 2];
|
||||
|
||||
// debug(" : row %d node count %d\n", y, pp_node_counts[y]);
|
||||
|
||||
if(pp_node_counts[y] == 0) continue; // no nodes on this raster line
|
||||
|
||||
qsort(&pp_nodes[y][0], pp_node_counts[y], sizeof(int), compare_nodes);
|
||||
qsort(pp_scanline_nodes, pp_node_counts[y], sizeof(int), compare_nodes);
|
||||
|
||||
unsigned char* row_data = &pp_tile_buffer[(y >> _pp_antialias) * PP_TILE_BUFFER_SIZE];
|
||||
|
||||
for(uint32_t i = 0; i < pp_node_counts[y]; i += 2) {
|
||||
int sx = pp_nodes[y][i + 0];
|
||||
int ex = pp_nodes[y][i + 1];
|
||||
int sx = *pp_scanline_nodes++;
|
||||
int ex = *pp_scanline_nodes++;
|
||||
|
||||
if(sx == ex) { // empty span, nothing to do
|
||||
continue;
|
||||
|
@ -570,14 +592,14 @@ pp_rect_t render_nodes(pp_rect_t *tb) {
|
|||
// either 1 (at x4) or 3 (at x16) we change that to a "ceil" instead ensuring
|
||||
// the full tile bounds are returned
|
||||
if(_pp_antialias) {
|
||||
rb.w += (_pp_antialias | 0b1);
|
||||
rb.h += (_pp_antialias | 0b1);
|
||||
}
|
||||
int maxx = rb.x + rb.w + (_pp_antialias | 0b1);
|
||||
int maxy = rb.y + rb.h + (_pp_antialias | 0b1);
|
||||
|
||||
rb.x >>= _pp_antialias;
|
||||
rb.y >>= _pp_antialias;
|
||||
rb.w >>= _pp_antialias;
|
||||
rb.h >>= _pp_antialias;
|
||||
rb.x >>= _pp_antialias;
|
||||
rb.y >>= _pp_antialias;
|
||||
rb.w = (maxx >> _pp_antialias) - rb.x;
|
||||
rb.h = (maxy >> _pp_antialias) - rb.y;
|
||||
}
|
||||
|
||||
uint8_t *p_alpha_map = _pp_alpha_map_none;
|
||||
if(_pp_antialias == 1) p_alpha_map = _pp_alpha_map_x4;
|
||||
|
@ -636,8 +658,8 @@ void pp_render(pp_poly_t *polygon) {
|
|||
if(pp_rect_empty(&tb)) { debug(" : empty when clipped, skipping\n"); continue; }
|
||||
|
||||
// clear existing tile data and nodes
|
||||
memset(pp_node_counts, 0, sizeof(pp_node_counts));
|
||||
memset(pp_tile_buffer, 0, PP_TILE_BUFFER_SIZE * PP_TILE_BUFFER_SIZE);
|
||||
memset(pp_node_counts, 0, PP_TILE_BUFFER_SIZE * 4 * sizeof(uint32_t));
|
||||
memset(pp_tile_buffer, 0, sizeof(pp_tile_buffer));
|
||||
|
||||
// build the nodes for each pp_path_t
|
||||
pp_path_t *path = polygon->paths;
|
||||
|
|
|
@ -164,6 +164,7 @@ static const mp_map_elem_t picographics_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X64), MP_ROM_INT(DISPLAY_INTERSTATE75_128X64) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_192X64), MP_ROM_INT(DISPLAY_INTERSTATE75_192X64) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_256X64), MP_ROM_INT(DISPLAY_INTERSTATE75_256X64) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INTERSTATE75_128X128), MP_ROM_INT(DISPLAY_INTERSTATE75_128X128) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_INKY_FRAME_7), MP_ROM_INT(DISPLAY_INKY_FRAME_7) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_COSMIC_UNICORN), MP_ROM_INT(DISPLAY_COSMIC_UNICORN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_STELLAR_UNICORN), MP_ROM_INT(DISPLAY_STELLAR_UNICORN) },
|
||||
|
@ -172,6 +173,7 @@ static const mp_map_elem_t picographics_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PICO_W_EXPLORER), MP_ROM_INT(DISPLAY_PICO_W_EXPLORER) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_EXPLORER), MP_ROM_INT(DISPLAY_EXPLORER) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PRESTO), MP_ROM_INT(DISPLAY_PRESTO) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DISPLAY_PRESTO_FULL_RES), MP_ROM_INT(DISPLAY_PRESTO_FULL_RES) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_PEN_1BIT), MP_ROM_INT(PEN_1BIT) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PEN_P4), MP_ROM_INT(PEN_P4) },
|
||||
|
|
|
@ -211,6 +211,14 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
|
|||
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
|
||||
if(pen_type == -1) pen_type = PEN_RGB888;
|
||||
break;
|
||||
case DISPLAY_INTERSTATE75_128X128:
|
||||
width = 128;
|
||||
height = 128;
|
||||
bus_type = BUS_PIO;
|
||||
// Portrait to match labelling
|
||||
if(rotate == -1) rotate = (int)Rotation::ROTATE_0;
|
||||
if(pen_type == -1) pen_type = PEN_RGB888;
|
||||
break;
|
||||
case DISPLAY_INKY_FRAME_7:
|
||||
width = 800;
|
||||
height = 480;
|
||||
|
@ -254,7 +262,14 @@ bool get_display_settings(PicoGraphicsDisplay display, int &width, int &height,
|
|||
height = 240;
|
||||
bus_type = BUS_PIO;
|
||||
rotate = (int)Rotation::ROTATE_0;
|
||||
pen_type = PEN_RGB565;
|
||||
if(pen_type == -1) pen_type = PEN_RGB565;
|
||||
break;
|
||||
case DISPLAY_PRESTO_FULL_RES:
|
||||
width = 480;
|
||||
height = 480;
|
||||
bus_type = BUS_PIO;
|
||||
rotate = (int)Rotation::ROTATE_0;
|
||||
if(pen_type == -1) pen_type = PEN_RGB565;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -397,7 +412,8 @@ mp_obj_t ModPicoGraphics_make_new(const mp_obj_type_t *type, size_t n_args, size
|
|||
|| display == DISPLAY_STELLAR_UNICORN
|
||||
|| display == DISPLAY_UNICORN_PACK
|
||||
|| display == DISPLAY_SCROLL_PACK
|
||||
|| display == DISPLAY_PRESTO) {
|
||||
|| display == DISPLAY_PRESTO
|
||||
|| display == DISPLAY_PRESTO_FULL_RES) {
|
||||
// Create a dummy display driver
|
||||
self->display = m_new_class(DisplayDriver, width, height, (Rotation)rotate);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ enum PicoGraphicsDisplay {
|
|||
DISPLAY_INTERSTATE75_128X64,
|
||||
DISPLAY_INTERSTATE75_192X64,
|
||||
DISPLAY_INTERSTATE75_256X64,
|
||||
DISPLAY_INTERSTATE75_128X128,
|
||||
DISPLAY_INKY_FRAME_7,
|
||||
DISPLAY_COSMIC_UNICORN,
|
||||
DISPLAY_STELLAR_UNICORN,
|
||||
|
@ -32,7 +33,8 @@ enum PicoGraphicsDisplay {
|
|||
DISPLAY_SCROLL_PACK,
|
||||
DISPLAY_PICO_W_EXPLORER,
|
||||
DISPLAY_EXPLORER,
|
||||
DISPLAY_PRESTO
|
||||
DISPLAY_PRESTO,
|
||||
DISPLAY_PRESTO_FULL_RES
|
||||
};
|
||||
|
||||
enum PicoGraphicsPenType {
|
||||
|
|
|
@ -19,6 +19,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR(POLYGON_path_obj, 4, POLYGON_path);
|
|||
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_regular_obj, 5, POLYGON_regular);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_circle_obj, 4, POLYGON_circle);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_arc_obj, 6, POLYGON_arc);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_star_obj, 6, POLYGON_star);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(POLYGON_line_obj, 5, POLYGON_line);
|
||||
|
||||
|
||||
static const mp_rom_map_elem_t POLYGON_locals_dict_table[] = {
|
||||
|
@ -39,6 +41,8 @@ static const mp_rom_map_elem_t POLYGON_locals_dict_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_path), MP_ROM_PTR(&POLYGON_path_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&POLYGON_circle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_arc), MP_ROM_PTR(&POLYGON_arc_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_star), MP_ROM_PTR(&POLYGON_star_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&POLYGON_line_obj) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(POLYGON_locals_dict, POLYGON_locals_dict_table);
|
||||
|
|
|
@ -21,7 +21,6 @@ typedef struct _ModPicoGraphics_obj_t {
|
|||
|
||||
typedef struct _VECTOR_obj_t {
|
||||
mp_obj_base_t base;
|
||||
void *mem;
|
||||
PicoVector *vector;
|
||||
} _VECTOR_obj_t;
|
||||
|
||||
|
@ -352,6 +351,72 @@ mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
|||
return self;
|
||||
}
|
||||
|
||||
mp_obj_t POLYGON_star(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_points, ARG_inner_radius, ARG_outer_radius, ARG_stroke };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_points, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_inner_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_outer_radius, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_stroke, MP_ARG_OBJ, { .u_obj = mp_const_none }},
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
|
||||
|
||||
picovector_point_type x = mp_picovector_get_point_type(args[ARG_x].u_obj);
|
||||
picovector_point_type y = mp_picovector_get_point_type(args[ARG_y].u_obj);
|
||||
int p = args[ARG_points].u_int;
|
||||
picovector_point_type r1 = mp_picovector_get_point_type(args[ARG_inner_radius].u_obj);
|
||||
picovector_point_type r2 = mp_picovector_get_point_type(args[ARG_outer_radius].u_obj);
|
||||
picovector_point_type s = args[ARG_stroke].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_stroke].u_obj);
|
||||
|
||||
pp_poly_merge(self->poly, ppp_star({
|
||||
x, y,
|
||||
p,
|
||||
r1,
|
||||
r2,
|
||||
s
|
||||
}));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
mp_obj_t POLYGON_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_self, ARG_x, ARG_y, ARG_x2, ARG_y2, ARG_thickness };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_thickness, MP_ARG_OBJ, { .u_obj = mp_const_none }},
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
_POLY_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _POLY_obj_t);
|
||||
|
||||
picovector_point_type x = mp_picovector_get_point_type(args[ARG_x].u_obj);
|
||||
picovector_point_type y = mp_picovector_get_point_type(args[ARG_y].u_obj);
|
||||
picovector_point_type x2 = mp_picovector_get_point_type(args[ARG_x2].u_obj);
|
||||
picovector_point_type y2 = mp_picovector_get_point_type(args[ARG_y2].u_obj);
|
||||
picovector_point_type t = args[ARG_thickness].u_obj == mp_const_none ? 0 : mp_picovector_get_point_type(args[ARG_thickness].u_obj);
|
||||
|
||||
pp_poly_merge(self->poly, ppp_line({
|
||||
x, y,
|
||||
x2, y2,
|
||||
t
|
||||
}));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
|
||||
mp_obj_t POLYGON_centroid(mp_obj_t self_in) {
|
||||
|
@ -545,12 +610,7 @@ mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
|||
self->base.type = &VECTOR_type;
|
||||
ModPicoGraphics_obj_t *graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj);
|
||||
|
||||
// The PicoVector class calls `pretty_poly::init()` with the memory region
|
||||
// it does not store a pointer to this, so we need to store one ourselves
|
||||
// TODO: C Pretty Poly does not support runtime memory allocation
|
||||
//self->mem = m_new(uint8_t, PicoVector::pretty_poly_buffer_size());
|
||||
|
||||
self->vector = m_new_class(PicoVector, graphics->graphics, self->mem);
|
||||
self->vector = m_new_class(PicoVector, graphics->graphics);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -705,13 +765,15 @@ mp_obj_t VECTOR_set_antialiasing(mp_obj_t self_in, mp_obj_t aa) {
|
|||
}
|
||||
|
||||
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, ARG_angle };
|
||||
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_angle, ARG_max_width, ARG_max_height };
|
||||
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_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} }
|
||||
{ MP_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_max_width, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_max_height, MP_ARG_INT, {.u_int = 0} }
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
@ -729,6 +791,8 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
|||
|
||||
int x = args[ARG_x].u_int;
|
||||
int y = args[ARG_y].u_int;
|
||||
int max_width = args[ARG_max_width].u_int;
|
||||
int max_height = args[ARG_max_height].u_int;
|
||||
|
||||
pp_mat3_t tt = pp_mat3_identity();
|
||||
|
||||
|
@ -738,7 +802,7 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
|||
|
||||
pp_mat3_translate(&tt, (float)x, (float)y);
|
||||
|
||||
self->vector->text(t, &tt);
|
||||
self->vector->text(t, max_width, max_height, &tt);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ extern mp_obj_t POLYGON_regular(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
|||
extern mp_obj_t POLYGON_rectangle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t POLYGON_circle(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t POLYGON_arc(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t POLYGON_star(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
extern mp_obj_t POLYGON_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
|
||||
extern void POLYGON_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
extern mp_obj_t POLYGON_centroid(mp_obj_t self_in);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from pimoroni import RGBLED, Button
|
||||
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_96X48, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64
|
||||
from picographics import PicoGraphics, DISPLAY_INTERSTATE75_32X32, DISPLAY_INTERSTATE75_64X32, DISPLAY_INTERSTATE75_96X32, DISPLAY_INTERSTATE75_96X48, DISPLAY_INTERSTATE75_128X32, DISPLAY_INTERSTATE75_64X64, DISPLAY_INTERSTATE75_128X64, DISPLAY_INTERSTATE75_192X64, DISPLAY_INTERSTATE75_256X64, DISPLAY_INTERSTATE75_128X128
|
||||
from pimoroni_i2c import PimoroniI2C
|
||||
import hub75
|
||||
import sys
|
||||
|
@ -29,6 +29,7 @@ class Interstate75:
|
|||
DISPLAY_INTERSTATE75_128X64 = DISPLAY_INTERSTATE75_128X64
|
||||
DISPLAY_INTERSTATE75_192X64 = DISPLAY_INTERSTATE75_192X64
|
||||
DISPLAY_INTERSTATE75_256X64 = DISPLAY_INTERSTATE75_256X64
|
||||
DISPLAY_INTERSTATE75_128X128 = DISPLAY_INTERSTATE75_128X128
|
||||
|
||||
PANEL_GENERIC = hub75.PANEL_GENERIC
|
||||
PANEL_FM6126A = hub75.PANEL_FM6126A
|
||||
|
@ -46,7 +47,15 @@ class Interstate75:
|
|||
self.interstate75w = "Pico W" in sys.implementation._machine
|
||||
self.display = PicoGraphics(display=display)
|
||||
self.width, self.height = self.display.get_bounds()
|
||||
self.hub75 = hub75.Hub75(self.width, self.height, panel_type=panel_type, stb_invert=stb_invert, color_order=color_order)
|
||||
|
||||
out_width = self.width
|
||||
out_height = self.height
|
||||
|
||||
if display == DISPLAY_INTERSTATE75_128X128:
|
||||
out_width = 256
|
||||
out_height = 64
|
||||
|
||||
self.hub75 = hub75.Hub75(out_width, out_height, panel_type=panel_type, stb_invert=stb_invert, color_order=color_order)
|
||||
self.hub75.start()
|
||||
if self.interstate75w:
|
||||
self._switch_pins = self.SWITCH_PINS_W
|
||||
|
|
Ładowanie…
Reference in New Issue