PicoVector: Vector anti-aliasing support.

This commit is contained in:
Phil Howard 2023-08-15 14:25:55 +01:00
parent 95ab839ba5
commit 4671607b3a
4 changed files with 55 additions and 9 deletions

View File

@ -8,6 +8,7 @@ namespace pimoroni {
int PicoGraphics::reset_pen(uint8_t i) {return -1;};
int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;};
int PicoGraphics::create_pen_hsv(float h, float s, float v){return -1;};
void PicoGraphics::set_pixel_alpha(const Point &p, const uint8_t a) {};
void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {};
void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {};
void PicoGraphics::set_pixel_dither(const Point &p, const uint8_t &c) {};
@ -16,6 +17,7 @@ namespace pimoroni {
int PicoGraphics::get_palette_size() {return 0;}
RGB* PicoGraphics::get_palette() {return nullptr;}
bool PicoGraphics::supports_alpha_blend() {return false;}
void PicoGraphics::set_dimensions(int width, int height) {
bounds = clip = {0, 0, width, height};

View File

@ -47,7 +47,19 @@ namespace pimoroni {
g((c >> 8) & 0xff),
b(c & 0xff) {}
constexpr RGB(int16_t r, int16_t g, int16_t b) : r(r), g(g), b(b) {}
constexpr uint8_t blend(uint8_t s, uint8_t d, uint8_t a) {
return d + ((a * (s - d) + 127) >> 8);
}
constexpr RGB blend(RGB with, const uint8_t alpha) {
return RGB(
blend(with.r, r, alpha),
blend(with.g, g, alpha),
blend(with.b, b, alpha)
);
}
static RGB from_hsv(float h, float s, float v) {
float i = floor(h * 6.0f);
float f = h * 6.0f - i;
@ -268,6 +280,7 @@ namespace pimoroni {
virtual int get_palette_size();
virtual RGB* get_palette();
virtual bool supports_alpha_blend();
virtual int create_pen(uint8_t r, uint8_t g, uint8_t b);
virtual int create_pen_hsv(float h, float s, float v);
@ -276,6 +289,7 @@ namespace pimoroni {
virtual void set_pixel_dither(const Point &p, const RGB &c);
virtual void set_pixel_dither(const Point &p, const RGB565 &c);
virtual void set_pixel_dither(const Point &p, const uint8_t &c);
virtual void set_pixel_alpha(const Point &p, const uint8_t a);
virtual void frame_convert(PenType type, conversion_callback_func callback);
virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent);
@ -471,6 +485,9 @@ namespace pimoroni {
void set_pixel_span(const Point &p, uint l) override;
void set_pixel_dither(const Point &p, const RGB &c) override;
void set_pixel_dither(const Point &p, const RGB565 &c) override;
void set_pixel_alpha(const Point &p, const uint8_t a) override;
bool supports_alpha_blend() override {return true;}
void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override;

View File

@ -34,6 +34,15 @@ namespace pimoroni {
*buf++ = color;
}
}
void PicoGraphics_PenRGB332::set_pixel_alpha(const Point &p, const uint8_t a) {
if(!bounds.contains(p)) return;
uint8_t *buf = (uint8_t *)frame_buffer;
RGB332 blended = RGB(buf[p.y * bounds.w + p.x]).blend(RGB(color), a).to_rgb332();
buf[p.y * bounds.w + p.x] = blended;
};
void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB &c) {
if(!bounds.contains(p)) return;
uint8_t _dmv = dither16_pattern[(p.x & 0b11) | ((p.y & 0b11) << 2)];

View File

@ -7,21 +7,39 @@ namespace pimoroni {
private:
PicoGraphics *graphics;
alright_fonts::text_metrics_t text_metrics;
const uint8_t alpha_map[4] {0, 128, 192, 255};
public:
PicoVector(PicoGraphics *graphics, void *mem = nullptr) : graphics(graphics) {
pretty_poly::init(mem);
set_options([this](const pretty_poly::tile_t &tile) -> void {
for(auto y = 0; y < tile.bounds.h; y++) {
for(auto x = 0; x < tile.bounds.w; x++) {
uint8_t alpha = tile.get_value(x, y);
if (alpha > 0) {
this->graphics->pixel({x + tile.bounds.x, y + tile.bounds.y});
if(graphics->supports_alpha_blend()) {
set_options([this](const pretty_poly::tile_t &tile) -> void {
for(auto y = 0; y < tile.bounds.h; y++) {
for(auto x = 0; x < tile.bounds.w; x++) {
uint8_t alpha = tile.get_value(x, y);
if (alpha >= 4) {
this->graphics->pixel({x + tile.bounds.x, y + tile.bounds.y});
} else if (alpha > 0) {
alpha = alpha_map[alpha];
this->graphics->set_pixel_alpha({x + tile.bounds.x, y + tile.bounds.y}, alpha);
}
}
}
}
}, pretty_poly::X4, {0, 0, graphics->bounds.w, graphics->bounds.h});
}, pretty_poly::X4, {0, 0, graphics->bounds.w, graphics->bounds.h});
} else {
set_options([this](const pretty_poly::tile_t &tile) -> void {
for(auto y = 0; y < tile.bounds.h; y++) {
for(auto x = 0; x < tile.bounds.w; x++) {
uint8_t alpha = tile.get_value(x, y);
if (alpha > 0) {
this->graphics->pixel({x + tile.bounds.x, y + tile.bounds.y});
}
}
}
}, pretty_poly::NONE, {0, 0, graphics->bounds.w, graphics->bounds.h});
}
};
bool set_font(std::string_view font_path, unsigned int font_size) {