kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			PicoGraphicS: Hershey support, bugfixes, tidyup.
							rodzic
							
								
									fc1561e54b
								
							
						
					
					
						commit
						49b62515c2
					
				|  | @ -5,4 +5,4 @@ add_library(pico_graphics | |||
| 
 | ||||
| target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR}) | ||||
| 
 | ||||
| target_link_libraries(pico_graphics bitmap_fonts pico_stdlib) | ||||
| target_link_libraries(pico_graphics bitmap_fonts hershey_fonts pico_stdlib) | ||||
|  | @ -4,10 +4,10 @@ namespace pimoroni { | |||
| 
 | ||||
|   void PicoGraphics::set_pen(uint c) {}; | ||||
|   void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {}; | ||||
|   void PicoGraphics::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {}; | ||||
|   void PicoGraphics::reset_pen(uint8_t i) {}; | ||||
|   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(void *frame_buffer, uint x, uint y, uint stride) {}; | ||||
|   void PicoGraphics::set_pixel(const Point &p) {}; | ||||
|   void PicoGraphics::palette_lookup(void *frame_buffer, void *result, uint offset, uint length) {}; | ||||
| 
 | ||||
|   void PicoGraphics::set_dimensions(int width, int height) { | ||||
|  | @ -27,16 +27,27 @@ namespace pimoroni { | |||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_font(const bitmap::font_t *font){ | ||||
|     this->font = font; | ||||
|     this->bitmap_font = font; | ||||
|     this->hershey_font = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_font(std::string font){ | ||||
|     if (font == "bitmap6") { | ||||
|       this->font = &font6; | ||||
|     } else if (font == "bitmap8") { | ||||
|       this->font = &font8; | ||||
|     } else if (font == "bitmap14_outline") { | ||||
|       this->font = &font14_outline; | ||||
|   void PicoGraphics::set_font(const hershey::font_t *font){ | ||||
|     this->bitmap_font = nullptr; | ||||
|     this->hershey_font = font; | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::set_font(std::string name){ | ||||
|     if (name == "bitmap6") { | ||||
|       set_font(&font6); | ||||
|     } else if (name == "bitmap8") { | ||||
|       set_font(&font8); | ||||
|     } else if (name == "bitmap14_outline") { | ||||
|       set_font(&font14_outline); | ||||
|     } else { | ||||
|       // check that font exists and assign it
 | ||||
|       if(hershey::fonts.find(name) != hershey::fonts.end()) { | ||||
|         set_font(hershey::fonts[name]); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -54,7 +65,7 @@ namespace pimoroni { | |||
| 
 | ||||
|   void PicoGraphics::pixel(const Point &p) { | ||||
|     if(!clip.contains(p)) return; | ||||
|     set_pixel(frame_buffer, p.x, p.y, bounds.w); | ||||
|     set_pixel(p); | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::pixel_span(const Point &p, int32_t l) { | ||||
|  | @ -69,7 +80,7 @@ namespace pimoroni { | |||
| 
 | ||||
|     Point dest(clipped.x, clipped.y); | ||||
|     while(l--) { | ||||
|         set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         set_pixel(dest); | ||||
|         dest.x++; | ||||
|     } | ||||
|   } | ||||
|  | @ -117,20 +128,42 @@ namespace pimoroni { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::character(const char c, const Point &p, uint8_t scale) { | ||||
|     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::character(const char c, const Point &p, float s, float a) { | ||||
|     if (bitmap_font) { | ||||
|       bitmap::character(bitmap_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, std::max(1.0f, s)); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (hershey_font) { | ||||
|       hershey::glyph(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { | ||||
|         line(Point(x1, y1), Point(x2, y2)); | ||||
|       }, c, p.x, p.y, s, a); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) { | ||||
|     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); | ||||
|   void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, float s, float a, uint8_t letter_spacing) { | ||||
|     if (bitmap_font) { | ||||
|       bitmap::text(bitmap_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, std::max(1.0f, s), letter_spacing); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (hershey_font) { | ||||
|       hershey::text(hershey_font, [this](int32_t x1, int32_t y1, int32_t x2, int32_t y2) { | ||||
|         line(Point(x1, y1), Point(x2, y2)); | ||||
|       }, t, p.x, p.y, s, a); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) { | ||||
|     return bitmap::measure_text(font, t, scale); | ||||
|   int32_t PicoGraphics::measure_text(const std::string &t, float s, uint8_t letter_spacing) { | ||||
|     if (bitmap_font) return bitmap::measure_text(bitmap_font, t, std::max(1.0f, s), letter_spacing); | ||||
|     if (hershey_font) return hershey::measure_text(hershey_font, t, s); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   int32_t orient2d(Point p1, Point p2, Point p3) { | ||||
|  | @ -186,7 +219,7 @@ namespace pimoroni { | |||
|       Point dest = Point(triangle_bounds.x, triangle_bounds.y + y); | ||||
|       for (int32_t x = 0; x < triangle_bounds.w; x++) { | ||||
|         if ((w0 | w1 | w2) >= 0) { | ||||
|           set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|           set_pixel(dest); | ||||
|         } | ||||
| 
 | ||||
|         dest.x++; | ||||
|  | @ -251,24 +284,29 @@ namespace pimoroni { | |||
|   void PicoGraphics::line(Point p1, Point p2) { | ||||
|     // fast horizontal line
 | ||||
|     if(p1.y == p2.y) { | ||||
|       int32_t start = std::max(clip.x, std::min(p1.x, p2.x)); | ||||
|       int32_t end   = std::min(clip.x + clip.w, std::max(p1.x, p2.x)); | ||||
|       p1 = p1.clamp(clip); | ||||
|       p2 = p2.clamp(clip); | ||||
|       int32_t start = std::min(p1.x, p2.x); | ||||
|       int32_t end   = std::max(p1.x, p2.x); | ||||
|       pixel_span(Point(start, p1.y), end - start); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // fast vertical line
 | ||||
|     if(p1.x == p2.x) { | ||||
|       int32_t start  = std::max(clip.y, std::min(p1.y, p2.y)); | ||||
|       int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start; | ||||
|       p1 = p1.clamp(clip); | ||||
|       p2 = p2.clamp(clip); | ||||
|       int32_t start  = std::min(p1.y, p2.y); | ||||
|       int32_t length = std::max(p1.y, p2.y) - start; | ||||
|       Point dest(p1.x, start); | ||||
|       while(length--) { | ||||
|         set_pixel(frame_buffer, dest.x, dest.y, bounds.w); | ||||
|         set_pixel(dest); | ||||
|         dest.y++; | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // general purpose line
 | ||||
|     // lines are either "shallow" or "steep" based on whether the x delta
 | ||||
|     // is greater than the y delta
 | ||||
|  | @ -283,7 +321,8 @@ namespace pimoroni { | |||
|       int32_t x = p1.x; | ||||
|       int32_t y = p1.y << 16; | ||||
|       while(s--) { | ||||
|         set_pixel(frame_buffer, x, y >> 16, bounds.w); | ||||
|         Point p(x, y >> 16); | ||||
|         if(clip.contains(p)) set_pixel(p); | ||||
|         y += sy; | ||||
|         x += sx; | ||||
|       } | ||||
|  | @ -295,7 +334,8 @@ namespace pimoroni { | |||
|       int32_t y = p1.y; | ||||
|       int32_t x = p1.x << 16; | ||||
|       while(s--) { | ||||
|         set_pixel(frame_buffer, x >> 16, y, bounds.w); | ||||
|         Point p(x >> 16, y); | ||||
|         if(clip.contains(p)) set_pixel(p); | ||||
|         y += sy; | ||||
|         x += sx; | ||||
|       } | ||||
|  |  | |||
|  | @ -4,9 +4,13 @@ | |||
| #include <cstdint> | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
| 
 | ||||
| #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" | ||||
| #include "libraries/bitmap_fonts/font14_outline_data.hpp" | ||||
| 
 | ||||
| #include "common/pimoroni_common.hpp" | ||||
| 
 | ||||
| // A tiny graphics library for our Pico products
 | ||||
|  | @ -72,7 +76,8 @@ namespace pimoroni { | |||
|     Rect bounds; | ||||
|     Rect clip; | ||||
| 
 | ||||
|     const bitmap::font_t *font; | ||||
|     const bitmap::font_t *bitmap_font; | ||||
|     const hershey::font_t *hershey_font; | ||||
| 
 | ||||
|     static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) { | ||||
|       return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6); | ||||
|  | @ -100,13 +105,14 @@ namespace pimoroni { | |||
| 
 | ||||
|     virtual void set_pen(uint c); | ||||
|     virtual void set_pen(uint8_t r, uint8_t g, uint8_t b); | ||||
|     virtual void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b); | ||||
|     virtual void reset_pen(uint8_t i); | ||||
|     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(void *frame_buffer, uint x, uint y, uint stride); | ||||
|     virtual void set_pixel(const Point &p); | ||||
|     virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length); | ||||
| 
 | ||||
|     void set_font(const bitmap::font_t *font); | ||||
|     void set_font(const hershey::font_t *font); | ||||
|     void set_font(std::string font); | ||||
| 
 | ||||
|     void set_dimensions(int width, int height); | ||||
|  | @ -123,9 +129,9 @@ namespace pimoroni { | |||
|     void pixel_span(const Point &p, int32_t l); | ||||
|     void rectangle(const Rect &r); | ||||
|     void circle(const Point &p, int32_t r); | ||||
|     void character(const char c, const Point &p, uint8_t scale = 2); | ||||
|     void text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale = 2); | ||||
|     int32_t measure_text(const std::string &t, uint8_t scale = 2); | ||||
|     void character(const char c, const Point &p, float s = 2.0f, float a = 0.0f); | ||||
|     void text(const std::string &t, const Point &p, int32_t wrap, float s = 2.0f, float a = 0.0f, uint8_t letter_spacing = 1); | ||||
|     int32_t measure_text(const std::string &t, float s = 2.0f, uint8_t letter_spacing = 1); | ||||
|     void polygon(const std::vector<Point> &points); | ||||
|     void triangle(Point p1, Point p2, Point p3); | ||||
|     void line(Point p1, Point p2); | ||||
|  | @ -163,26 +169,28 @@ namespace pimoroni { | |||
|       void set_pen(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // TODO look up closest palette colour, or just NOOP?
 | ||||
|       } | ||||
|       void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { | ||||
|       int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         i &= 0xf; | ||||
|         palette[i].color = rgb_to_rgb565(r, g, b); | ||||
|         palette[i].used = true; | ||||
|         return i; | ||||
|       } | ||||
|       void reset_pen(uint8_t i) override { | ||||
|       int reset_pen(uint8_t i) override { | ||||
|         i &= 0xf; | ||||
|         palette[i].color = default_palette[i]; | ||||
|         return i; | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|       void set_pixel(const Point &p) override { | ||||
|         // pointer to byte in framebuffer that contains this pixel
 | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         uint8_t *p = &buf[(x / 2) + (y * stride / 2)]; | ||||
|         uint8_t *f = &buf[(p.x / 2) + (p.y * bounds.w / 2)]; | ||||
| 
 | ||||
|         uint8_t  o = (~x & 0b1) * 4; // bit offset within byte
 | ||||
|         uint8_t  m = ~(0b1111 << o); // bit mask for byte
 | ||||
|         uint8_t  b = color << o;     // bit value shifted to position
 | ||||
|         uint8_t  o = (~p.x & 0b1) * 4; // bit offset within byte
 | ||||
|         uint8_t  m = ~(0b1111 << o);   // bit mask for byte
 | ||||
|         uint8_t  b = color << o;       // bit value shifted to position
 | ||||
| 
 | ||||
|         *p &= m; // clear bits
 | ||||
|         *p |= b; // set value
 | ||||
|         *f &= m; // clear bits
 | ||||
|         *f |= b; // set value
 | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|  | @ -219,15 +227,17 @@ namespace pimoroni { | |||
|       void set_pen(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // TODO look up closest palette colour, or just NOOP?
 | ||||
|       } | ||||
|       void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { | ||||
|       int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         i &= 0xff; | ||||
|         palette[i].color = rgb_to_rgb565(r, g, b); | ||||
|         palette[i].used = true; | ||||
|         return i; | ||||
|       } | ||||
|       void reset_pen(uint8_t i) override { | ||||
|       int reset_pen(uint8_t i) override { | ||||
|         i &= 0xff; | ||||
|         palette[i].color = 0; | ||||
|         palette[i].used = false; | ||||
|         return i; | ||||
|       } | ||||
|       int create_pen(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         // Create a colour and place it in the palette if there's space
 | ||||
|  | @ -241,9 +251,9 @@ namespace pimoroni { | |||
|         } | ||||
|         return -1; | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|       void set_pixel(const Point &p) override { | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|         buf[p.y * bounds.w + p.x] = color; | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|  | @ -281,9 +291,9 @@ namespace pimoroni { | |||
|       int create_pen(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         return rgb_to_rgb332(r, g, b); | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|       void set_pixel(const Point &p) override { | ||||
|         uint8_t *buf = (uint8_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|         buf[p.y * bounds.w + p.x] = color; | ||||
|       } | ||||
|       void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override { | ||||
|         uint8_t *src = (uint8_t *)frame_buffer; | ||||
|  | @ -316,9 +326,9 @@ namespace pimoroni { | |||
|       int create_pen(uint8_t r, uint8_t g, uint8_t b) override { | ||||
|         return rgb_to_rgb565(r, g, b); | ||||
|       } | ||||
|       void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override { | ||||
|       void set_pixel(const Point &p) override { | ||||
|         uint16_t *buf = (uint16_t *)frame_buffer; | ||||
|         buf[y * stride + x] = color; | ||||
|         buf[p.y * bounds.w + p.x] = color; | ||||
|       } | ||||
|       static size_t buffer_size(uint w, uint h) { | ||||
|         return w * h * sizeof(RGB565); | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ include(pico_unicorn/micropython) | |||
| include(pico_wireless/micropython) | ||||
| include(pico_explorer/micropython) | ||||
| 
 | ||||
| include(hershey_fonts/micropython) | ||||
| include(bitmap_fonts/micropython) | ||||
| 
 | ||||
| include(plasma/micropython) | ||||
|  |  | |||
|  | @ -443,14 +443,16 @@ mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_args, mp_m | |||
| } | ||||
| 
 | ||||
| mp_obj_t ModPicoGraphics_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_wrap, ARG_scale }; | ||||
|     enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_wrap, ARG_scale, ARG_angle, ARG_spacing }; | ||||
|     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_x1, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_wordwrap, MP_ARG_REQUIRED | MP_ARG_INT }, | ||||
|         { MP_QSTR_scale, MP_ARG_INT, {.u_int = 2} }, | ||||
|         { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} }, | ||||
|         { MP_QSTR_angle, MP_ARG_INT, {.u_int = 0} }, | ||||
|         { MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} }, | ||||
|     }; | ||||
| 
 | ||||
|     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; | ||||
|  | @ -469,19 +471,22 @@ mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t | |||
|     int x = args[ARG_x].u_int; | ||||
|     int y = args[ARG_y].u_int; | ||||
|     int wrap = args[ARG_wrap].u_int; | ||||
|     int scale = args[ARG_scale].u_int; | ||||
|     float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj); | ||||
|     int angle = args[ARG_angle].u_int; | ||||
|     int letter_spacing = args[ARG_spacing].u_int; | ||||
| 
 | ||||
|     self->graphics->text(t, Point(x, y), wrap, scale); | ||||
|     self->graphics->text(t, Point(x, y), wrap, scale, angle, letter_spacing); | ||||
| 
 | ||||
|     return mp_const_none; | ||||
| } | ||||
| 
 | ||||
| mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { | ||||
|     enum { ARG_self, ARG_text, ARG_scale }; | ||||
|     enum { ARG_self, ARG_text, ARG_scale, ARG_spacing }; | ||||
|     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_scale, MP_ARG_INT, {.u_int = 2} }, | ||||
|         { MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = mp_const_none} }, | ||||
|         { MP_QSTR_spacing, MP_ARG_INT, {.u_int = 1} }, | ||||
|     }; | ||||
| 
 | ||||
|     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; | ||||
|  | @ -497,9 +502,10 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m | |||
| 
 | ||||
|     std::string t((const char*)str); | ||||
| 
 | ||||
|     int scale = args[ARG_scale].u_int; | ||||
|     float scale = args[ARG_scale].u_obj == mp_const_none ? 2.0f : mp_obj_get_float(args[ARG_scale].u_obj); | ||||
|     int letter_spacing = args[ARG_spacing].u_int; | ||||
| 
 | ||||
|     int width = self->graphics->measure_text(t, scale); | ||||
|     int width = self->graphics->measure_text(t, scale, letter_spacing); | ||||
| 
 | ||||
|     return mp_obj_new_int(width); | ||||
| } | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Phil Howard
						Phil Howard