diff --git a/libraries/pico_graphics/pico_graphics.cpp b/libraries/pico_graphics/pico_graphics.cpp index 8bdd2eb3..4d1e82bc 100644 --- a/libraries/pico_graphics/pico_graphics.cpp +++ b/libraries/pico_graphics/pico_graphics.cpp @@ -2,12 +2,9 @@ namespace pimoroni { - void PicoGraphics::set_pen(uint c) {}; - void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {}; int PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {return -1;}; int PicoGraphics::reset_pen(uint8_t i) {return -1;}; int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {return -1;}; - void PicoGraphics::set_pixel(const Point &p) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; @@ -74,10 +71,7 @@ namespace pimoroni { if(clipped.x + l >= clip.x + clip.w) {l = clip.x + clip.w - clipped.x;} Point dest(clipped.x, clipped.y); - while(l--) { - set_pixel(dest); - dest.x++; - } + set_pixel_span(dest, l); } void PicoGraphics::rectangle(const Rect &r) { @@ -89,7 +83,7 @@ namespace pimoroni { Point dest(clipped.x, clipped.y); while(clipped.h--) { // draw span of pixels for this row - pixel_span(dest, clipped.w); + set_pixel_span(dest, clipped.w); // move to next scanline dest.y++; } diff --git a/libraries/pico_graphics/pico_graphics.hpp b/libraries/pico_graphics/pico_graphics.hpp index 926db4eb..0fb43837 100644 --- a/libraries/pico_graphics/pico_graphics.hpp +++ b/libraries/pico_graphics/pico_graphics.hpp @@ -437,12 +437,14 @@ namespace pimoroni { set_font(&font6); }; - virtual void set_pen(uint c); - virtual void set_pen(uint8_t r, uint8_t g, uint8_t b); + virtual void set_pen(uint c) = 0; + virtual void set_pen(uint8_t r, uint8_t g, uint8_t b) = 0; + virtual void set_pixel(const Point &p) = 0; + virtual void set_pixel_span(const Point &p, uint l) = 0; + + virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); virtual int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); virtual int reset_pen(uint8_t i); - virtual int create_pen(uint8_t r, uint8_t g, uint8_t b); - virtual void set_pixel(const Point &p); virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void scanline_convert(PenType type, conversion_callback_func callback); @@ -483,6 +485,7 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; static size_t buffer_size(uint w, uint h) { return w * h / 8; @@ -511,6 +514,7 @@ namespace pimoroni { int reset_pen(uint8_t i) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; @@ -541,6 +545,7 @@ namespace pimoroni { int reset_pen(uint8_t i) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates); void set_pixel_dither(const Point &p, const RGB &c) override; @@ -559,6 +564,7 @@ namespace pimoroni { int create_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + 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; @@ -579,6 +585,7 @@ namespace pimoroni { void set_pen(uint8_t r, uint8_t g, uint8_t b) override; int create_pen(uint8_t r, uint8_t g, uint8_t b) override; void set_pixel(const Point &p) override; + void set_pixel_span(const Point &p, uint l) override; static size_t buffer_size(uint w, uint h) { return w * h * sizeof(RGB565); } diff --git a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp index af052d4b..ef0f2d0b 100644 --- a/libraries/pico_graphics/pico_graphics_pen_1bit.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_1bit.cpp @@ -32,4 +32,29 @@ namespace pimoroni { *f |= (color << bo); } + void PicoGraphics_Pen1Bit::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 8) + (p.y * bounds.w / 8)]; + + uint bo = 7 - (p.x & 0b111); + + // TODO: this could trivially be sped up by processing single bits only at + // the start and the end of the span and writing full bytes (8 pixels at + // a time) in the middle portion of the span. would only be more efficient + // for longer spans (probably around 20 pixels or more) + while(l--) { + // forceably clear the bit and then set to the correct value + *f &= ~(1U << bo); + *f |= (color << bo); + + if(bo == 0) { // last bit of this byte? + // move to next byte in framebuffer and reset the bit offset + f++; bo = 8; + } + + bo--; + } + } + } \ No newline at end of file diff --git a/libraries/pico_graphics/pico_graphics_pen_p4.cpp b/libraries/pico_graphics/pico_graphics_pen_p4.cpp index 17bf6b6c..11fbeb99 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p4.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p4.cpp @@ -1,6 +1,7 @@ #include "pico_graphics.hpp" namespace pimoroni { + PicoGraphics_PenP4::PicoGraphics_PenP4(uint16_t width, uint16_t height, void *frame_buffer) : PicoGraphics(width, height, frame_buffer) { this->pen_type = PEN_P4; @@ -19,7 +20,7 @@ namespace pimoroni { } void PicoGraphics_PenP4::set_pen(uint c) { color = c & 0xf; - } + } void PicoGraphics_PenP4::set_pen(uint8_t r, uint8_t g, uint8_t b) { int pen = RGB(r, g, b).closest(palette, palette_size); if(pen != -1) color = pen; @@ -61,7 +62,25 @@ namespace pimoroni { *f &= m; // clear bits *f |= b; // set value } - + + void PicoGraphics_PenP4::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; + + // doubled up color value, so the color is stored in both nibbles + uint8_t cc = color | (color << 4); + + // handle the first pixel if not byte aligned + if(p.x & 0b1) {*f &= 0b11110000; *f |= (cc & 0b00001111); f++; l--;} + + // write any double nibble pixels + while(l > 1) {*f++ = cc; l -= 2;} + + // handle the last pixel if not byte aligned + if(l) {*f &= 0b00001111; *f |= (cc & 0b11110000);} + } + void PicoGraphics_PenP4::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { RGB error; for(size_t i = 0; i < candidates.size(); i++) { diff --git a/libraries/pico_graphics/pico_graphics_pen_p8.cpp b/libraries/pico_graphics/pico_graphics_pen_p8.cpp index 7f1f60c7..a2f3aad1 100644 --- a/libraries/pico_graphics/pico_graphics_pen_p8.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_p8.cpp @@ -50,6 +50,16 @@ namespace pimoroni { buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenP8::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } + void PicoGraphics_PenP8::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array &candidates) { RGB error; for(size_t i = 0; i < candidates.size(); i++) { diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp index 9fb7bb1c..d99970f0 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb332.cpp @@ -22,6 +22,15 @@ namespace pimoroni { uint8_t *buf = (uint8_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenRGB332::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint8_t *buf = (uint8_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } void PicoGraphics_PenRGB332::set_pixel_dither(const Point &p, const RGB &c) { if(!bounds.contains(p)) return; static uint8_t _odm[16] = { diff --git a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp index cdfa0b32..37520703 100644 --- a/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp +++ b/libraries/pico_graphics/pico_graphics_pen_rgb565.cpp @@ -22,4 +22,13 @@ namespace pimoroni { uint16_t *buf = (uint16_t *)frame_buffer; buf[p.y * bounds.w + p.x] = color; } + void PicoGraphics_PenRGB565::set_pixel_span(const Point &p, uint l) { + // pointer to byte in framebuffer that contains this pixel + uint16_t *buf = (uint16_t *)frame_buffer; + buf = &buf[p.y * bounds.w + p.x]; + + while(l--) { + *buf++ = color; + } + } } \ No newline at end of file