kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			ST7789/PicoGraphics: Templated framebuffer formats.
							rodzic
							
								
									dbed4a463f
								
							
						
					
					
						commit
						7e4725d1cd
					
				| 
						 | 
					@ -9,4 +9,4 @@ target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
 | 
				
			||||||
target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR})
 | 
					target_include_directories(st7789 INTERFACE ${CMAKE_CURRENT_LIST_DIR})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Pull in pico libraries that we need
 | 
					# Pull in pico libraries that we need
 | 
				
			||||||
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma)
 | 
					target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib pimoroni_bus hardware_spi hardware_pwm hardware_dma pico_graphics)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -201,6 +201,101 @@ namespace pimoroni {
 | 
				
			||||||
    gpio_put(cs, 1);
 | 
					    gpio_put(cs, 1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  void ST7789::update(PicoGraphics<PenRGB565> *graphics) {
 | 
				
			||||||
 | 
					    command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->get_data());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void ST7789::update(PicoGraphics<PenRGB332> *graphics) {
 | 
				
			||||||
 | 
					    uint8_t command = reg::RAMWR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(dc, 0); // command mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(spi) {
 | 
				
			||||||
 | 
					      spi_write_blocking(spi, &command, 1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      write_blocking_parallel(&command, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(dc, 1); // data mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t row_buf[width];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(auto y = 0u; y < height; y++) {
 | 
				
			||||||
 | 
					      graphics->get_data(y, &row_buf);
 | 
				
			||||||
 | 
					      // TODO: Add DMA->SPI / PIO while we prep the next row
 | 
				
			||||||
 | 
					      if(spi) {
 | 
				
			||||||
 | 
					        spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void ST7789::update(PicoGraphics<PenP8> *graphics) {
 | 
				
			||||||
 | 
					    uint8_t command = reg::RAMWR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(dc, 0); // command mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(spi) {
 | 
				
			||||||
 | 
					      spi_write_blocking(spi, &command, 1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      write_blocking_parallel(&command, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    gpio_put(dc, 1); // data mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t row_buf[width];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(auto y = 0u; y < height; y++) {
 | 
				
			||||||
 | 
					      graphics->get_data(y, &row_buf);
 | 
				
			||||||
 | 
					      // TODO: Add DMA->SPI / PIO while we prep the next row
 | 
				
			||||||
 | 
					      if(spi) {
 | 
				
			||||||
 | 
					        spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void ST7789::update(PicoGraphics<PenP4> *graphics) {
 | 
				
			||||||
 | 
					    uint8_t command = reg::RAMWR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(dc, 0); // command mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(spi) {
 | 
				
			||||||
 | 
					      spi_write_blocking(spi, &command, 1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      write_blocking_parallel(&command, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(dc, 1); // data mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t row_buf[width];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(auto y = 0u; y < height; y++) {
 | 
				
			||||||
 | 
					      graphics->get_data(y, &row_buf);
 | 
				
			||||||
 | 
					      // TODO: Add DMA->SPI / PIO while we prep the next row
 | 
				
			||||||
 | 
					      if(spi) {
 | 
				
			||||||
 | 
					        spi_write_blocking(spi, (const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        write_blocking_parallel((const uint8_t*)row_buf, width * sizeof(uint16_t));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gpio_put(cs, 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
  // Native 16-bit framebuffer update
 | 
					  // Native 16-bit framebuffer update
 | 
				
			||||||
  void ST7789::update() {
 | 
					  void ST7789::update() {
 | 
				
			||||||
    command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer);
 | 
					    command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)frame_buffer);
 | 
				
			||||||
| 
						 | 
					@ -238,6 +333,7 @@ namespace pimoroni {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gpio_put(cs, 1);
 | 
					    gpio_put(cs, 1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void ST7789::set_backlight(uint8_t brightness) {
 | 
					  void ST7789::set_backlight(uint8_t brightness) {
 | 
				
			||||||
    // gamma correct the provided 0-255 brightness value onto a
 | 
					    // gamma correct the provided 0-255 brightness value onto a
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@
 | 
				
			||||||
#include "hardware/pwm.h"
 | 
					#include "hardware/pwm.h"
 | 
				
			||||||
#include "common/pimoroni_common.hpp"
 | 
					#include "common/pimoroni_common.hpp"
 | 
				
			||||||
#include "common/pimoroni_bus.hpp"
 | 
					#include "common/pimoroni_bus.hpp"
 | 
				
			||||||
 | 
					#include "libraries/pico_graphics/pico_graphics.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,15 +42,11 @@ namespace pimoroni {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
    // frame buffer where pixel data is stored
 | 
					 | 
				
			||||||
    void *frame_buffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Parallel init
 | 
					    // Parallel init
 | 
				
			||||||
    ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) :
 | 
					    ST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins pins) :
 | 
				
			||||||
      spi(nullptr),
 | 
					      spi(nullptr),
 | 
				
			||||||
      width(width), height(height), rotation(rotation), round(false),
 | 
					      width(width), height(height), rotation(rotation), round(false),
 | 
				
			||||||
      cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl), frame_buffer(frame_buffer) {
 | 
					      cs(pins.cs), dc(pins.dc), wr_sck(pins.wr_sck), rd_sck(pins.rd_sck), d0(pins.d0), bl(pins.bl) {
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
      gpio_set_function(wr_sck, GPIO_FUNC_SIO);
 | 
					      gpio_set_function(wr_sck, GPIO_FUNC_SIO);
 | 
				
			||||||
      gpio_set_dir(wr_sck, GPIO_OUT);
 | 
					      gpio_set_dir(wr_sck, GPIO_OUT);
 | 
				
			||||||
| 
						 | 
					@ -71,7 +68,7 @@ namespace pimoroni {
 | 
				
			||||||
    ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) :
 | 
					    ST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins pins) :
 | 
				
			||||||
      spi(pins.spi),
 | 
					      spi(pins.spi),
 | 
				
			||||||
      width(width), height(height), rotation(rotation), round(round),
 | 
					      width(width), height(height), rotation(rotation), round(round),
 | 
				
			||||||
      cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl), frame_buffer(frame_buffer) {
 | 
					      cs(pins.cs), dc(pins.dc), wr_sck(pins.sck), d0(pins.mosi), bl(pins.bl) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // configure spi interface and pins
 | 
					      // configure spi interface and pins
 | 
				
			||||||
      spi_init(spi, SPI_BAUD);
 | 
					      spi_init(spi, SPI_BAUD);
 | 
				
			||||||
| 
						 | 
					@ -86,17 +83,15 @@ namespace pimoroni {
 | 
				
			||||||
    void command(uint8_t command, size_t len = 0, const char *data = NULL);
 | 
					    void command(uint8_t command, size_t len = 0, const char *data = NULL);
 | 
				
			||||||
    void set_backlight(uint8_t brightness);
 | 
					    void set_backlight(uint8_t brightness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void update();
 | 
					    void update(PicoGraphics<PenRGB565> *graphics);
 | 
				
			||||||
    void update(uint16_t *palette);
 | 
					    void update(PicoGraphics<PenRGB332> *graphics);
 | 
				
			||||||
 | 
					    void update(PicoGraphics<PenP8> *graphics);
 | 
				
			||||||
 | 
					    void update(PicoGraphics<PenP4> *graphics);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    void configure_display(Rotation rotate);
 | 
					    void configure_display(Rotation rotate);
 | 
				
			||||||
    void write_blocking_parallel(const uint8_t *src, size_t len);
 | 
					    void write_blocking_parallel(const uint8_t *src, size_t len);
 | 
				
			||||||
    void common_init() {
 | 
					    void common_init() {
 | 
				
			||||||
        if(!this->frame_buffer) {
 | 
					 | 
				
			||||||
          this->frame_buffer = new uint8_t[width * height];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        gpio_set_function(dc, GPIO_FUNC_SIO);
 | 
					        gpio_set_function(dc, GPIO_FUNC_SIO);
 | 
				
			||||||
        gpio_set_dir(dc, GPIO_OUT);
 | 
					        gpio_set_dir(dc, GPIO_OUT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,135 +1,40 @@
 | 
				
			||||||
#include "pico_graphics.hpp"
 | 
					#include "pico_graphics.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace pimoroni {
 | 
					namespace pimoroni {
 | 
				
			||||||
  PicoGraphics::PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer)
 | 
					 | 
				
			||||||
  : frame_buffer((Pen *)frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) {
 | 
					 | 
				
			||||||
    set_font(&font6);
 | 
					 | 
				
			||||||
    set_palette_mode(PaletteModeRGB332);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::set_font(const bitmap::font_t *font){
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::set_font(const bitmap::font_t *font){
 | 
				
			||||||
    this->font = font;
 | 
					    this->font = font;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::set_pen(Pen p) {
 | 
					  template<class T>
 | 
				
			||||||
    pen = p;
 | 
					  void PicoGraphics<T>::set_pen(uint16_t p) {
 | 
				
			||||||
 | 
					    pen.set_color(p);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::set_palette_mode(PaletteMode mode) {
 | 
					  template<class T>
 | 
				
			||||||
    palette_mode = mode;
 | 
					  void PicoGraphics<T>::set_clip(const Rect &r) {
 | 
				
			||||||
    if(mode == PaletteModeRGB332) {
 | 
					 | 
				
			||||||
      rgb332_palette();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      empty_palette();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int PicoGraphics::create_pen(uint8_t r, uint8_t g, uint8_t b) {
 | 
					 | 
				
			||||||
    if (palette_mode == PaletteModeRGB332) {
 | 
					 | 
				
			||||||
      return rgb_to_rgb332_index(r, g, b); // Fast pack RGB into palette index
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      RGB565 c = create_pen_rgb565(r, g, b);
 | 
					 | 
				
			||||||
      int result = search_palette(c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (result == -1) {
 | 
					 | 
				
			||||||
        result = put_palette(create_pen_rgb565(r, g, b));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::set_pen(uint8_t r, uint8_t g, uint8_t b) {
 | 
					 | 
				
			||||||
    int result = create_pen(r, g, b);
 | 
					 | 
				
			||||||
    (void)result;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int PicoGraphics::search_palette(RGB565 c) {
 | 
					 | 
				
			||||||
    for(auto i = 0u; i < 256; i++) {
 | 
					 | 
				
			||||||
      if((palette_status[i] & PaletteStatusUsed) && palette[i] == c) return i;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int PicoGraphics::put_palette(RGB565 c) {
 | 
					 | 
				
			||||||
    if(palette_mode != PaletteModeUSER) return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for(auto i = 0u; i < 256; i++) {
 | 
					 | 
				
			||||||
      if(!(palette_status[i] & (PaletteStatusUsed | PaletteStatusReserved))) {
 | 
					 | 
				
			||||||
        palette[i] = c;
 | 
					 | 
				
			||||||
        palette_status[i] = PaletteStatusUsed;
 | 
					 | 
				
			||||||
        return i;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::set_palette(uint8_t i, RGB565 c) {
 | 
					 | 
				
			||||||
    if(palette_mode != PaletteModeUSER) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    palette[i] = c;
 | 
					 | 
				
			||||||
    palette_status[i] |= PaletteStatusUsed;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int PicoGraphics::reserve_palette() {
 | 
					 | 
				
			||||||
    if(palette_mode != PaletteModeUSER) return - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (auto i = 0u; i < 256; i++) {
 | 
					 | 
				
			||||||
      if (!palette_status[i]) {
 | 
					 | 
				
			||||||
        palette_status[i] = PaletteStatusReserved;
 | 
					 | 
				
			||||||
        return i;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::empty_palette() {
 | 
					 | 
				
			||||||
    for (auto i = 0u; i < 256; i++) {
 | 
					 | 
				
			||||||
      palette[i] = 0;
 | 
					 | 
				
			||||||
      palette_status[i] = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::rgb332_palette() {
 | 
					 | 
				
			||||||
    for (auto i = 0u; i < 256; i++) {
 | 
					 | 
				
			||||||
      // Convert the implicit RGB332 (i) into RGB565
 | 
					 | 
				
			||||||
      // 0b11100 000 0b00011100 0b00000011
 | 
					 | 
				
			||||||
      palette[i] = ((i & 0b11100000) << 8) | ((i & 0b00011100) << 6) | ((i & 0b00000011) << 3);
 | 
					 | 
				
			||||||
      palette[i] = __builtin_bswap16(palette[i]);
 | 
					 | 
				
			||||||
      palette_status[i] = PaletteStatusUsed;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::set_clip(const Rect &r) {
 | 
					 | 
				
			||||||
    clip = bounds.intersection(r);
 | 
					    clip = bounds.intersection(r);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::remove_clip() {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::remove_clip() {
 | 
				
			||||||
    clip = bounds;
 | 
					    clip = bounds;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Pen* PicoGraphics::ptr(const Rect &r) {
 | 
					  template<class T>
 | 
				
			||||||
    return frame_buffer + r.x + r.y * bounds.w;
 | 
					  void PicoGraphics<T>::clear() {
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Pen* PicoGraphics::ptr(const Point &p) {
 | 
					 | 
				
			||||||
    return frame_buffer + p.x + p.y * bounds.w;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Pen* PicoGraphics::ptr(int32_t x, int32_t y) {
 | 
					 | 
				
			||||||
    return frame_buffer + x + y * bounds.w;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void PicoGraphics::clear() {
 | 
					 | 
				
			||||||
    rectangle(clip);
 | 
					    rectangle(clip);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::pixel(const Point &p) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::pixel(const Point &p) {
 | 
				
			||||||
    if(!clip.contains(p)) return;
 | 
					    if(!clip.contains(p)) return;
 | 
				
			||||||
    *ptr(p) = pen;
 | 
					    pen.set_pixel(frame_buffer, p.x, p.y, bounds.w);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::pixel_span(const Point &p, int32_t l) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::pixel_span(const Point &p, int32_t l) {
 | 
				
			||||||
    // check if span in bounds
 | 
					    // check if span in bounds
 | 
				
			||||||
    if( p.x + l < clip.x || p.x >= clip.x + clip.w ||
 | 
					    if( p.x + l < clip.x || p.x >= clip.x + clip.w ||
 | 
				
			||||||
        p.y     < clip.y || p.y >= clip.y + clip.h) return;
 | 
					        p.y     < clip.y || p.y >= clip.y + clip.h) return;
 | 
				
			||||||
| 
						 | 
					@ -139,31 +44,36 @@ namespace pimoroni {
 | 
				
			||||||
    if(clipped.x     <  clip.x)           {l += clipped.x - clip.x; clipped.x = clip.x;}
 | 
					    if(clipped.x     <  clip.x)           {l += clipped.x - clip.x; clipped.x = clip.x;}
 | 
				
			||||||
    if(clipped.x + l >= clip.x + clip.w)  {l  = clip.x + clip.w - clipped.x;}
 | 
					    if(clipped.x + l >= clip.x + clip.w)  {l  = clip.x + clip.w - clipped.x;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Pen *dest = ptr(clipped);
 | 
					    Point dest(clipped.x, clipped.y);
 | 
				
			||||||
    while(l--) {
 | 
					    while(l--) {
 | 
				
			||||||
      *dest++ = pen;
 | 
					        pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
 | 
				
			||||||
 | 
					        dest.x++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::rectangle(const Rect &r) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::rectangle(const Rect &r) {
 | 
				
			||||||
    // clip and/or discard depending on rectangle visibility
 | 
					    // clip and/or discard depending on rectangle visibility
 | 
				
			||||||
    Rect clipped = r.intersection(clip);
 | 
					    Rect clipped = r.intersection(clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(clipped.empty()) return;
 | 
					    if(clipped.empty()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Pen *dest = ptr(clipped);
 | 
					    Point dest(clipped.x, clipped.y);
 | 
				
			||||||
    while(clipped.h--) {
 | 
					    while(clipped.h--) {
 | 
				
			||||||
      // draw span of pixels for this row
 | 
					      // draw span of pixels for this row
 | 
				
			||||||
      for(int32_t i = 0; i < clipped.w; i++) {
 | 
					      pixel_span(dest, clipped.w);
 | 
				
			||||||
        *dest++ = pen;
 | 
					      /*for(int32_t i = 0; i < clipped.w; i++) {
 | 
				
			||||||
      }
 | 
					        pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
 | 
				
			||||||
 | 
					        dest.x++;
 | 
				
			||||||
 | 
					      }*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // move to next scanline
 | 
					      // move to next scanline
 | 
				
			||||||
      dest += bounds.w - clipped.w;
 | 
					      dest.y++;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::circle(const Point &p, int32_t radius) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::circle(const Point &p, int32_t radius) {
 | 
				
			||||||
    // circle in screen bounds?
 | 
					    // circle in screen bounds?
 | 
				
			||||||
    Rect bounds = Rect(p.x - radius, p.y - radius, radius * 2, radius * 2);
 | 
					    Rect bounds = Rect(p.x - radius, p.y - radius, radius * 2, radius * 2);
 | 
				
			||||||
    if(!bounds.intersects(clip)) return;
 | 
					    if(!bounds.intersects(clip)) return;
 | 
				
			||||||
| 
						 | 
					@ -191,19 +101,22 @@ namespace pimoroni {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::character(const char c, const Point &p, uint8_t scale) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::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){
 | 
					    bitmap::character(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){
 | 
				
			||||||
      rectangle(Rect(x, y, w, h));
 | 
					      rectangle(Rect(x, y, w, h));
 | 
				
			||||||
    }, c, p.x, p.y, scale);
 | 
					    }, c, p.x, p.y, scale);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::text(const std::string &t, const Point &p, int32_t wrap, uint8_t scale) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::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){
 | 
					    bitmap::text(font, [this](int32_t x, int32_t y, int32_t w, int32_t h){
 | 
				
			||||||
      rectangle(Rect(x, y, w, h));
 | 
					      rectangle(Rect(x, y, w, h));
 | 
				
			||||||
    }, t, p.x, p.y, wrap, scale);
 | 
					    }, t, p.x, p.y, wrap, scale);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int32_t PicoGraphics::measure_text(const std::string &t, uint8_t scale) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  int32_t PicoGraphics<T>::measure_text(const std::string &t, uint8_t scale) {
 | 
				
			||||||
    return bitmap::measure_text(font, t, scale);
 | 
					    return bitmap::measure_text(font, t, scale);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -215,7 +128,8 @@ namespace pimoroni {
 | 
				
			||||||
    return (p1.y == p2.y && p1.x > p2.x) || (p1.y < p2.y);
 | 
					    return (p1.y == p2.y && p1.x > p2.x) || (p1.y < p2.y);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::triangle(Point p1, Point p2, Point p3) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::triangle(Point p1, Point p2, Point p3) {
 | 
				
			||||||
    Rect triangle_bounds(
 | 
					    Rect triangle_bounds(
 | 
				
			||||||
      Point(std::min(p1.x, std::min(p2.x, p3.x)), std::min(p1.y, std::min(p2.y, p3.y))),
 | 
					      Point(std::min(p1.x, std::min(p2.x, p3.x)), std::min(p1.y, std::min(p2.y, p3.y))),
 | 
				
			||||||
      Point(std::max(p1.x, std::max(p2.x, p3.x)), std::max(p1.y, std::max(p2.y, p3.y))));
 | 
					      Point(std::max(p1.x, std::max(p2.x, p3.x)), std::max(p1.y, std::max(p2.y, p3.y))));
 | 
				
			||||||
| 
						 | 
					@ -257,13 +171,13 @@ namespace pimoroni {
 | 
				
			||||||
      int32_t w1 = w1row;
 | 
					      int32_t w1 = w1row;
 | 
				
			||||||
      int32_t w2 = w2row;
 | 
					      int32_t w2 = w2row;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Pen *dest = ptr(triangle_bounds.x, triangle_bounds.y + y);
 | 
					      Point dest = Point(triangle_bounds.x, triangle_bounds.y + y);
 | 
				
			||||||
      for (int32_t x = 0; x < triangle_bounds.w; x++) {
 | 
					      for (int32_t x = 0; x < triangle_bounds.w; x++) {
 | 
				
			||||||
        if ((w0 | w1 | w2) >= 0) {
 | 
					        if ((w0 | w1 | w2) >= 0) {
 | 
				
			||||||
          *dest = pen;
 | 
					          pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dest++;
 | 
					        dest.x++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        w0 += a12;
 | 
					        w0 += a12;
 | 
				
			||||||
        w1 += a20;
 | 
					        w1 += a20;
 | 
				
			||||||
| 
						 | 
					@ -276,7 +190,8 @@ namespace pimoroni {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::polygon(const std::vector<Point> &points) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::polygon(const std::vector<Point> &points) {
 | 
				
			||||||
    static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering
 | 
					    static int32_t nodes[64]; // maximum allowed number of nodes per scanline for polygon rendering
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int32_t miny = points[0].y, maxy = points[0].y;
 | 
					    int32_t miny = points[0].y, maxy = points[0].y;
 | 
				
			||||||
| 
						 | 
					@ -322,7 +237,8 @@ namespace pimoroni {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphics::line(Point p1, Point p2) {
 | 
					  template<class T>
 | 
				
			||||||
 | 
					  void PicoGraphics<T>::line(Point p1, Point p2) {
 | 
				
			||||||
    // fast horizontal line
 | 
					    // fast horizontal line
 | 
				
			||||||
    if(p1.y == p2.y) {
 | 
					    if(p1.y == p2.y) {
 | 
				
			||||||
      int32_t start = std::max(clip.x, std::min(p1.x, p2.x));
 | 
					      int32_t start = std::max(clip.x, std::min(p1.x, p2.x));
 | 
				
			||||||
| 
						 | 
					@ -335,10 +251,10 @@ namespace pimoroni {
 | 
				
			||||||
    if(p1.x == p2.x) {
 | 
					    if(p1.x == p2.x) {
 | 
				
			||||||
      int32_t start  = std::max(clip.y, std::min(p1.y, p2.y));
 | 
					      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;
 | 
					      int32_t length = std::min(clip.y + clip.h, std::max(p1.y, p2.y)) - start;
 | 
				
			||||||
      Pen *dest = ptr(p1.x, start);
 | 
					      Point dest(p1.x, start);
 | 
				
			||||||
      while(length--) {
 | 
					      while(length--) {
 | 
				
			||||||
        *dest = pen;
 | 
					        pen.set_pixel(frame_buffer, dest.x, dest.y, bounds.w);
 | 
				
			||||||
        dest += bounds.w;
 | 
					        dest.y++;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -357,7 +273,7 @@ namespace pimoroni {
 | 
				
			||||||
      int32_t x = p1.x;
 | 
					      int32_t x = p1.x;
 | 
				
			||||||
      int32_t y = p1.y << 16;
 | 
					      int32_t y = p1.y << 16;
 | 
				
			||||||
      while(s--) {
 | 
					      while(s--) {
 | 
				
			||||||
        pixel(Point(x, y >> 16));
 | 
					        pen.set_pixel(frame_buffer, x, y >> 16, bounds.w);
 | 
				
			||||||
        y += sy;
 | 
					        y += sy;
 | 
				
			||||||
        x += sx;
 | 
					        x += sx;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -369,7 +285,7 @@ namespace pimoroni {
 | 
				
			||||||
      int32_t y = p1.y;
 | 
					      int32_t y = p1.y;
 | 
				
			||||||
      int32_t x = p1.x << 16;
 | 
					      int32_t x = p1.x << 16;
 | 
				
			||||||
      while(s--) {
 | 
					      while(s--) {
 | 
				
			||||||
        pixel(Point(x >> 16, y));
 | 
					        pen.set_pixel(frame_buffer, x >> 16, y, bounds.w);
 | 
				
			||||||
        y += sy;
 | 
					        y += sy;
 | 
				
			||||||
        x += sx;
 | 
					        x += sx;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,9 @@
 | 
				
			||||||
// a tiny little graphics library for our Pico products
 | 
					// a tiny little graphics library for our Pico products
 | 
				
			||||||
// supports only 16-bit (565) RGB framebuffers
 | 
					// supports only 16-bit (565) RGB framebuffers
 | 
				
			||||||
namespace pimoroni {
 | 
					namespace pimoroni {
 | 
				
			||||||
 | 
					  typedef uint8_t RGB332;
 | 
				
			||||||
  typedef uint8_t Pen;
 | 
					 | 
				
			||||||
  typedef uint16_t RGB565;
 | 
					  typedef uint16_t RGB565;
 | 
				
			||||||
 | 
					  typedef int Pen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct Rect;
 | 
					  struct Rect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,46 +44,26 @@ namespace pimoroni {
 | 
				
			||||||
    void deflate(int32_t v);
 | 
					    void deflate(int32_t v);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class PicoGraphics {
 | 
					  class PicoGraphicsPenType {
 | 
				
			||||||
      public:
 | 
					      public:
 | 
				
			||||||
    Pen *frame_buffer;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Rect      bounds;
 | 
					        struct PaletteEntry {
 | 
				
			||||||
    Rect      clip;
 | 
					          RGB565 color;
 | 
				
			||||||
 | 
					          bool used;
 | 
				
			||||||
    Pen       pen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const bitmap::font_t *font;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    RGB565 palette[256];
 | 
					 | 
				
			||||||
    uint8_t palette_status[256];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    enum PaletteMode {
 | 
					 | 
				
			||||||
      PaletteModeRGB332 = 0,
 | 
					 | 
				
			||||||
      PaletteModeUSER = 1
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    enum PaletteStatus : uint8_t {
 | 
					        static constexpr RGB332 rgb_to_rgb332(uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
      PaletteStatusReserved = 1,
 | 
					 | 
				
			||||||
      PaletteStatusUsed = 2
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PaletteMode palette_mode = PaletteModeRGB332;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public:
 | 
					 | 
				
			||||||
    PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer);
 | 
					 | 
				
			||||||
    void set_font(const bitmap::font_t *font);
 | 
					 | 
				
			||||||
    void set_pen(Pen p);
 | 
					 | 
				
			||||||
    void set_palette_mode(PaletteMode mode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    [[deprecated("Use uint8_t create_pen(uint8_t, uint8_t, uint8_t).")]]
 | 
					 | 
				
			||||||
    void set_pen(uint8_t r, uint8_t g, uint8_t b);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static constexpr Pen rgb_to_rgb332_index(uint8_t r, uint8_t g, uint8_t b) {
 | 
					 | 
				
			||||||
          return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6);
 | 
					          return (r & 0b11100000) | ((g & 0b11100000) >> 3) | ((b & 0b11000000) >> 6);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static constexpr RGB565 create_pen_rgb565(uint8_t r, uint8_t g, uint8_t b) {
 | 
					        static constexpr RGB565 rgb332_to_rgb565(RGB332 c) {
 | 
				
			||||||
 | 
					          uint16_t p = ((c & 0b11100000) << 8) |
 | 
				
			||||||
 | 
					                       ((c & 0b00011100) << 6) |
 | 
				
			||||||
 | 
					                       ((c & 0b00000011) << 3);
 | 
				
			||||||
 | 
					          return __builtin_bswap16(p);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static constexpr RGB565 rgb_to_rgb565(uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
          uint16_t p = ((r & 0b11111000) << 8) |
 | 
					          uint16_t p = ((r & 0b11111000) << 8) |
 | 
				
			||||||
                       ((g & 0b11111100) << 3) |
 | 
					                       ((g & 0b11111100) << 3) |
 | 
				
			||||||
                       ((b & 0b11111000) >> 3);
 | 
					                       ((b & 0b11111000) >> 3);
 | 
				
			||||||
| 
						 | 
					@ -91,12 +71,228 @@ namespace pimoroni {
 | 
				
			||||||
          return __builtin_bswap16(p);
 | 
					          return __builtin_bswap16(p);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static constexpr RGB565 create_pen_rgb332(uint8_t r, uint8_t g, uint8_t b) {
 | 
					        virtual void set_pixel(void *frame_buffer, uint x, uint y, uint stride);
 | 
				
			||||||
      uint16_t p = ((r & 0b11100000) << 8) |
 | 
					        virtual int create(uint8_t r, uint8_t g, uint8_t b);
 | 
				
			||||||
                   ((g & 0b11100000) << 3) |
 | 
					        virtual void set_color(uint c);
 | 
				
			||||||
                   ((b & 0b11000000) >> 3);
 | 
					        virtual void set_color(uint8_t r, uint8_t g, uint8_t b);
 | 
				
			||||||
 | 
					        virtual void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return __builtin_bswap16(p);
 | 
					        virtual void palette_lookup(void *frame_buffer, void *result, uint offset, uint length);
 | 
				
			||||||
 | 
					        static size_t buffer_size(uint w, uint h); // Must be static, since user must know required size to alloc framebuffer
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class PenP4 : public PicoGraphicsPenType {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      uint8_t color;
 | 
				
			||||||
 | 
					      PaletteEntry palette[8];
 | 
				
			||||||
 | 
					      PenP4() {
 | 
				
			||||||
 | 
					        palette[0].color = rgb_to_rgb565(57, 48, 57);     // Black
 | 
				
			||||||
 | 
					        palette[1].color = rgb_to_rgb565(255, 255, 255);  // White
 | 
				
			||||||
 | 
					        palette[2].color = rgb_to_rgb565(58, 91, 70);     // Green
 | 
				
			||||||
 | 
					        palette[3].color = rgb_to_rgb565(61, 59, 94);     // Blue
 | 
				
			||||||
 | 
					        palette[4].color = rgb_to_rgb565(156, 72, 75);    // Red
 | 
				
			||||||
 | 
					        palette[5].color = rgb_to_rgb565(208, 190, 71);   // Yellow
 | 
				
			||||||
 | 
					        palette[6].color = rgb_to_rgb565(177, 106, 73);   // Orange
 | 
				
			||||||
 | 
					        palette[7].color = rgb_to_rgb565(255, 255, 255);  // Clear
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint c) {
 | 
				
			||||||
 | 
					        color = c & 0xf;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        // TODO look up closest palette colour, or just NOOP?
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {}
 | 
				
			||||||
 | 
					      void reset_color(uint8_t i) {}
 | 
				
			||||||
 | 
					      int create(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        return -1; // Can never create new colours, fixed palette!
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_pixel(void *frame_buffer, uint x, uint y, uint stride) 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  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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        *p &= m; // clear bits
 | 
				
			||||||
 | 
					        *p |= b; // set value
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
 | 
				
			||||||
 | 
					        uint8_t *src = (uint8_t *)frame_buffer;
 | 
				
			||||||
 | 
					        uint16_t *dst = (uint16_t *)result;
 | 
				
			||||||
 | 
					        for(auto x = 0u; x < length; x++) {
 | 
				
			||||||
 | 
					          uint8_t c = src[(offset / 2) + (x / 2)];
 | 
				
			||||||
 | 
					          uint8_t  o = (~x & 0b1) * 4; // bit offset within byte
 | 
				
			||||||
 | 
					          uint8_t  b = (c >> o) & 0xf; // bit value shifted to position
 | 
				
			||||||
 | 
					          dst[x] = palette[b].color;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      static size_t buffer_size(uint w, uint h) {
 | 
				
			||||||
 | 
					        return w * h / 2;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class PenP8 : public PicoGraphicsPenType {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      uint8_t color;
 | 
				
			||||||
 | 
					      PaletteEntry palette[256];
 | 
				
			||||||
 | 
					      PenP8() {
 | 
				
			||||||
 | 
					        for(auto i = 0u; i < 256; i++) {
 | 
				
			||||||
 | 
					          reset_color(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint c) override {
 | 
				
			||||||
 | 
					        color = c;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        // TODO look up closest palette colour, or just NOOP?
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					        palette[i].color = rgb_to_rgb565(r, g, b);
 | 
				
			||||||
 | 
					        palette[i].used = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void reset_color(uint8_t i) {
 | 
				
			||||||
 | 
					        palette[i].color = 0;
 | 
				
			||||||
 | 
					        palette[i].used = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      int create(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        // Create a colour and place it in the palette if there's space
 | 
				
			||||||
 | 
					        RGB565 c = rgb_to_rgb565(r, g, b);
 | 
				
			||||||
 | 
					        for(auto i = 0u; i < 256u; i++) {
 | 
				
			||||||
 | 
					          if(!palette[i].used) {
 | 
				
			||||||
 | 
					            palette[i].color = c;
 | 
				
			||||||
 | 
					            palette[i].used = true;
 | 
				
			||||||
 | 
					            return i;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_pixel(void *frame_buffer, uint x, uint y, uint stride) override {
 | 
				
			||||||
 | 
					        uint8_t *buf = (uint8_t *)frame_buffer;
 | 
				
			||||||
 | 
					        buf[y * stride + x] = color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
 | 
				
			||||||
 | 
					        uint8_t *src = (uint8_t *)frame_buffer;
 | 
				
			||||||
 | 
					        uint16_t *dst = (uint16_t *)result;
 | 
				
			||||||
 | 
					        for(auto x = 0u; x < length; x++) {
 | 
				
			||||||
 | 
					          dst[x] = palette[src[offset + x]].color;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      static size_t buffer_size(uint w, uint h) {
 | 
				
			||||||
 | 
					        return w * h;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class PenRGB332 : public PicoGraphicsPenType {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      RGB332 color;
 | 
				
			||||||
 | 
					      PaletteEntry palette[256];
 | 
				
			||||||
 | 
					      PenRGB332() {
 | 
				
			||||||
 | 
					        for(auto i = 0u; i < 256; i++) {
 | 
				
			||||||
 | 
					          reset_color(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint c) {
 | 
				
			||||||
 | 
					        color = c;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        color = rgb_to_rgb332(r, g, b);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					        palette[i].color = rgb_to_rgb565(r, g, b);
 | 
				
			||||||
 | 
					        palette[i].used = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void reset_color(uint8_t i) {
 | 
				
			||||||
 | 
					        palette[i].color = rgb332_to_rgb565(i);
 | 
				
			||||||
 | 
					        palette[i].used = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      int create(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 {
 | 
				
			||||||
 | 
					        uint8_t *buf = (uint8_t *)frame_buffer;
 | 
				
			||||||
 | 
					        buf[y * stride + x] = color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
 | 
				
			||||||
 | 
					        uint8_t *src = (uint8_t *)frame_buffer;
 | 
				
			||||||
 | 
					        uint16_t *dst = (uint16_t *)result;
 | 
				
			||||||
 | 
					        for(auto x = 0u; x < length; x++) {
 | 
				
			||||||
 | 
					          dst[x] = palette[src[offset + x]].color;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      static size_t buffer_size(uint w, uint h) {
 | 
				
			||||||
 | 
					        return w * h;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class PenRGB565 : public PicoGraphicsPenType {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      uint16_t color;
 | 
				
			||||||
 | 
					      void set_color(uint c) override {
 | 
				
			||||||
 | 
					        color = c;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void update_color(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					        // Palette only. Does nothing.
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void reset_color(uint8_t i) {
 | 
				
			||||||
 | 
					        // Palette only. Does nothing.
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void set_color(uint8_t r, uint8_t g, uint8_t b) override {
 | 
				
			||||||
 | 
					        color = rgb_to_rgb565(r, g, b);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      int create(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 {
 | 
				
			||||||
 | 
					        uint16_t *buf = (uint16_t *)frame_buffer;
 | 
				
			||||||
 | 
					        buf[y * stride + x] = color;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      void palette_lookup(void *frame_buffer, void *result, uint offset, uint length) override {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      static size_t buffer_size(uint w, uint h) {
 | 
				
			||||||
 | 
					        return w * h * sizeof(RGB565);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <class T=PicoGraphicsPenType>
 | 
				
			||||||
 | 
					  class PicoGraphics {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    void *frame_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Rect      bounds;
 | 
				
			||||||
 | 
					    Rect      clip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const bitmap::font_t *font;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    T pen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    PicoGraphics(uint16_t width, uint16_t height, void *frame_buffer)
 | 
				
			||||||
 | 
					    : frame_buffer(frame_buffer), bounds(0, 0, width, height), clip(0, 0, width, height) {
 | 
				
			||||||
 | 
					      set_font(&font6);
 | 
				
			||||||
 | 
					      if(frame_buffer == nullptr) {
 | 
				
			||||||
 | 
					        frame_buffer = (void *)(new uint8_t[pen.buffer_size(width, height)]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void set_font(const bitmap::font_t *font);
 | 
				
			||||||
 | 
					    void set_pen(uint16_t p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int create_pen(uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					      return pen.create(r, g, b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void set_pen(uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					      pen.set_color(r, g, b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {
 | 
				
			||||||
 | 
					      pen.update_color(i, r, g, b);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void reset_pen(uint8_t i) {
 | 
				
			||||||
 | 
					      pen.reset_color(i);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void set_dimensions(int width, int height) {
 | 
					    void set_dimensions(int width, int height) {
 | 
				
			||||||
| 
						 | 
					@ -106,23 +302,16 @@ namespace pimoroni {
 | 
				
			||||||
      clip.h = height;
 | 
					      clip.h = height;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int create_pen(uint8_t r, uint8_t g, uint8_t b);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int reserve_palette();
 | 
					 | 
				
			||||||
    void empty_palette();
 | 
					 | 
				
			||||||
    void rgb332_palette();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int search_palette(RGB565 c);
 | 
					 | 
				
			||||||
    int get_palette(uint8_t i);
 | 
					 | 
				
			||||||
    void set_palette(uint8_t i, RGB565 c);
 | 
					 | 
				
			||||||
    int put_palette(RGB565 c);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void set_clip(const Rect &r);
 | 
					    void set_clip(const Rect &r);
 | 
				
			||||||
    void remove_clip();
 | 
					    void remove_clip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Pen* ptr(const Point &p);
 | 
					    void* get_data() {
 | 
				
			||||||
    Pen* ptr(const Rect &r);
 | 
					      return frame_buffer;
 | 
				
			||||||
    Pen* ptr(int32_t x, int32_t y);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void get_data(uint y, void *row_buf) {
 | 
				
			||||||
 | 
					      pen.palette_lookup(frame_buffer, row_buf, y * bounds.w, bounds.w);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void clear();
 | 
					    void clear();
 | 
				
			||||||
    void pixel(const Point &p);
 | 
					    void pixel(const Point &p);
 | 
				
			||||||
| 
						 | 
					@ -137,4 +326,9 @@ namespace pimoroni {
 | 
				
			||||||
    void line(Point p1, Point p2);
 | 
					    void line(Point p1, Point p2);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template class PicoGraphics<PenP4>;
 | 
				
			||||||
 | 
					  template class PicoGraphics<PenP8>;
 | 
				
			||||||
 | 
					  template class PicoGraphics<PenRGB332>;
 | 
				
			||||||
 | 
					  template class PicoGraphics<PenRGB565>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,11 +5,5 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace pimoroni {
 | 
					namespace pimoroni {
 | 
				
			||||||
  void PicoGraphicsST7789::update() {
 | 
					 | 
				
			||||||
    st7789.update(palette);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void PicoGraphicsST7789::set_backlight(uint8_t brightness) {
 | 
					 | 
				
			||||||
    st7789.set_backlight(brightness);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,42 +6,46 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace pimoroni {
 | 
					namespace pimoroni {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class PicoGraphicsST7789 : public PicoGraphics {
 | 
					  template <class T=PicoGraphicsPenType>
 | 
				
			||||||
 | 
					  class PicoGraphicsST7789 : public PicoGraphics<T> {
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
    ST7789 st7789;
 | 
					    ST7789 st7789;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) :
 | 
					    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round=false, void *frame_buffer=nullptr) :
 | 
				
			||||||
      PicoGraphics(width, height, frame_buffer),
 | 
					      PicoGraphics<T>(width, height, frame_buffer),
 | 
				
			||||||
      st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) {
 | 
					      st7789(width, height, rotation, round, frame_buffer, get_spi_pins(BG_SPI_FRONT)) {
 | 
				
			||||||
              common_init();
 | 
					              common_init();
 | 
				
			||||||
           };
 | 
					           };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) :
 | 
					    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, bool round, void *frame_buffer, SPIPins bus_pins) :
 | 
				
			||||||
      PicoGraphics(width, height, frame_buffer),
 | 
					      PicoGraphics<T>(width, height, frame_buffer),
 | 
				
			||||||
      st7789(width, height, rotation, round, frame_buffer, bus_pins) {
 | 
					      st7789(width, height, rotation, round, frame_buffer, bus_pins) {
 | 
				
			||||||
              common_init();
 | 
					              common_init();
 | 
				
			||||||
           };
 | 
					           };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) :
 | 
					    PicoGraphicsST7789(uint16_t width, uint16_t height, Rotation rotation, void *frame_buffer, ParallelPins bus_pins) :
 | 
				
			||||||
      PicoGraphics(width, height, frame_buffer),
 | 
					      PicoGraphics<T>(width, height, frame_buffer),
 | 
				
			||||||
      st7789(width, height, rotation, frame_buffer, bus_pins) {
 | 
					      st7789(width, height, rotation, frame_buffer, bus_pins) {
 | 
				
			||||||
              common_init();
 | 
					              common_init();
 | 
				
			||||||
           };
 | 
					           };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void common_init() {
 | 
					    void common_init() {
 | 
				
			||||||
      this->frame_buffer = (Pen *)st7789.frame_buffer;
 | 
					      st7789.init();
 | 
				
			||||||
      this->st7789.init();
 | 
					      this->set_dimensions(st7789.width, st7789.height);
 | 
				
			||||||
      this->set_dimensions(this->st7789.width, this->st7789.height);
 | 
					      st7789.update(this);
 | 
				
			||||||
      this->st7789.update(palette);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void update() {
 | 
				
			||||||
 | 
					      st7789.update(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void set_backlight(uint8_t brightness) {
 | 
				
			||||||
 | 
					      st7789.set_backlight(brightness);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void update();
 | 
					 | 
				
			||||||
    void set_backlight(uint8_t brightness);
 | 
					 | 
				
			||||||
    void configure_display(bool rotate180);
 | 
					 | 
				
			||||||
    void set_framebuffer(void* frame_buffer) {
 | 
					    void set_framebuffer(void* frame_buffer) {
 | 
				
			||||||
      this->frame_buffer = (Pen *)frame_buffer;
 | 
					      this->frame_buffer = frame_buffer;
 | 
				
			||||||
      st7789.frame_buffer = frame_buffer;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,9 +10,8 @@ MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_backlight_obj, GenericST7789_set_bac
 | 
				
			||||||
MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer);
 | 
					MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_framebuffer_obj, GenericST7789_set_framebuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Palette management
 | 
					// Palette management
 | 
				
			||||||
MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_palette_mode_obj, GenericST7789_set_palette_mode);
 | 
					MP_DEFINE_CONST_FUN_OBJ_KW(GenericST7789_update_pen_obj, 4, GenericST7789_update_pen);
 | 
				
			||||||
MP_DEFINE_CONST_FUN_OBJ_3(GenericST7789_set_palette_obj, GenericST7789_set_palette);
 | 
					MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_reset_pen_obj, GenericST7789_reset_pen);
 | 
				
			||||||
MP_DEFINE_CONST_FUN_OBJ_1(GenericST7789_reserve_palette_obj, GenericST7789_reserve_palette);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pen
 | 
					// Pen
 | 
				
			||||||
MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen);
 | 
					MP_DEFINE_CONST_FUN_OBJ_2(GenericST7789_set_pen_obj, GenericST7789_set_pen);
 | 
				
			||||||
| 
						 | 
					@ -41,9 +40,8 @@ STATIC const mp_rom_map_elem_t GenericST7789_locals_dict_table[] = {
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_set_pen), MP_ROM_PTR(&GenericST7789_set_pen_obj) },
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&GenericST7789_update_obj) },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_set_palette_mode), MP_ROM_PTR(&GenericST7789_set_palette_mode_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_update_pen), MP_ROM_PTR(&GenericST7789_update_pen_obj) },
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&GenericST7789_set_palette_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_reset_pen), MP_ROM_PTR(&GenericST7789_reset_pen_obj) },
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_reserve_palette), MP_ROM_PTR(&GenericST7789_reserve_palette_obj) },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&GenericST7789_set_backlight_obj) },
 | 
				
			||||||
    { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) },
 | 
					    { MP_ROM_QSTR(MP_QSTR_create_pen), MP_ROM_PTR(&GenericST7789_create_pen_obj) },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "micropython/modules/util.hpp"
 | 
					#include "micropython/modules/util.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef PICO_GRAPHICS_PEN_TYPE
 | 
				
			||||||
 | 
					#define PICO_GRAPHICS_PEN_TYPE PenP4
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace pimoroni;
 | 
					using namespace pimoroni;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +16,7 @@ extern "C" {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _GenericST7789_obj_t {
 | 
					typedef struct _GenericST7789_obj_t {
 | 
				
			||||||
    mp_obj_base_t base;
 | 
					    mp_obj_base_t base;
 | 
				
			||||||
    PicoGraphicsST7789 *st7789;
 | 
					    PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE> *st7789;
 | 
				
			||||||
    void *buffer;
 | 
					    void *buffer;
 | 
				
			||||||
} GenericST7789_obj_t;
 | 
					} GenericST7789_obj_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,32 +68,34 @@ mp_obj_t GenericST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t required_size = PICO_GRAPHICS_PEN_TYPE::buffer_size(width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (args[ARG_buffer].u_obj != mp_const_none) {
 | 
					    if (args[ARG_buffer].u_obj != mp_const_none) {
 | 
				
			||||||
        mp_buffer_info_t bufinfo;
 | 
					        mp_buffer_info_t bufinfo;
 | 
				
			||||||
        mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
 | 
					        mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_RW);
 | 
				
			||||||
        self->buffer = bufinfo.buf;
 | 
					        self->buffer = bufinfo.buf;
 | 
				
			||||||
        if(bufinfo.len < (size_t)(width * height * sizeof(Pen))) {
 | 
					        if(bufinfo.len < (size_t)(required_size)) {
 | 
				
			||||||
            mp_raise_ValueError("Supplied buffer is too small!");
 | 
					            mp_raise_ValueError("Supplied buffer is too small!");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        self->buffer = m_new(uint8_t, width * height * sizeof(Pen));
 | 
					        self->buffer = m_new(uint8_t, required_size);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (display == DISPLAY_TUFTY_2040) {
 | 
					    if (display == DISPLAY_TUFTY_2040) {
 | 
				
			||||||
        if (args[ARG_bus].u_obj == mp_const_none) {
 | 
					        if (args[ARG_bus].u_obj == mp_const_none) {
 | 
				
			||||||
            self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2});
 | 
					            self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, self->buffer, {10, 11, 12, 13, 14, 2});
 | 
				
			||||||
        } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) {
 | 
					        } else if (mp_obj_is_type(args[ARG_bus].u_obj, &ParallelPins_type)) {
 | 
				
			||||||
            _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
 | 
					            _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
 | 
				
			||||||
            self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins));
 | 
					            self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, self->buffer, *(ParallelPins *)(bus->pins));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            mp_raise_ValueError("ParallelBus expected!");
 | 
					            mp_raise_ValueError("ParallelBus expected!");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        if (args[ARG_bus].u_obj == mp_const_none) {
 | 
					        if (args[ARG_bus].u_obj == mp_const_none) {
 | 
				
			||||||
            self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT));
 | 
					            self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, round, self->buffer, get_spi_pins(BG_SPI_FRONT));
 | 
				
			||||||
        } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) {
 | 
					        } else if (mp_obj_is_type(args[ARG_bus].u_obj, &SPIPins_type)) {
 | 
				
			||||||
            _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
 | 
					            _PimoroniBus_obj_t *bus = (_PimoroniBus_obj_t *)MP_OBJ_TO_PTR(args[ARG_bus].u_obj);
 | 
				
			||||||
            self->st7789 = m_new_class(PicoGraphicsST7789, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins));
 | 
					            self->st7789 = m_new_class(PicoGraphicsST7789<PICO_GRAPHICS_PEN_TYPE>, width, height, rotate, round, self->buffer, *(SPIPins *)(bus->pins));
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            mp_raise_ValueError("SPIBus expected!");
 | 
					            mp_raise_ValueError("SPIBus expected!");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -146,7 +150,7 @@ mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
					mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
				
			||||||
    return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb332(
 | 
					    return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb332(
 | 
				
			||||||
        mp_obj_get_int(r),
 | 
					        mp_obj_get_int(r),
 | 
				
			||||||
        mp_obj_get_int(g),
 | 
					        mp_obj_get_int(g),
 | 
				
			||||||
        mp_obj_get_int(b)
 | 
					        mp_obj_get_int(b)
 | 
				
			||||||
| 
						 | 
					@ -154,7 +158,7 @@ mp_obj_t GenericST7789_module_RGB332(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
					mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
				
			||||||
    return mp_obj_new_int(PicoGraphicsST7789::create_pen_rgb565(
 | 
					    return mp_obj_new_int(PicoGraphicsPenType::rgb_to_rgb565(
 | 
				
			||||||
        mp_obj_get_int(r),
 | 
					        mp_obj_get_int(r),
 | 
				
			||||||
        mp_obj_get_int(g),
 | 
					        mp_obj_get_int(g),
 | 
				
			||||||
        mp_obj_get_int(b)
 | 
					        mp_obj_get_int(b)
 | 
				
			||||||
| 
						 | 
					@ -164,40 +168,44 @@ mp_obj_t GenericST7789_module_RGB565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
 | 
				
			||||||
mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) {
 | 
					mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen) {
 | 
				
			||||||
    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
					    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->st7789->set_pen(mp_obj_get_int(pen) & 0xff);
 | 
					    self->st7789->set_pen(mp_obj_get_int(pen));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return mp_const_none;
 | 
					    return mp_const_none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode) {
 | 
					mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen) {
 | 
				
			||||||
    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
					    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->st7789->set_palette_mode((PicoGraphicsST7789::PaletteMode)mp_obj_get_int(mode));
 | 
					    self->st7789->reset_pen(mp_obj_get_int(pen));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return mp_const_none;
 | 
					    return mp_const_none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour) {
 | 
					mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 | 
				
			||||||
    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
					    enum { ARG_self, ARG_i, ARG_r, ARG_g, ARG_b };
 | 
				
			||||||
 | 
					    static const mp_arg_t allowed_args[] = {
 | 
				
			||||||
 | 
					        { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
 | 
				
			||||||
 | 
					        { MP_QSTR_i, MP_ARG_REQUIRED | MP_ARG_INT },
 | 
				
			||||||
 | 
					        { MP_QSTR_r, MP_ARG_REQUIRED | MP_ARG_INT },
 | 
				
			||||||
 | 
					        { MP_QSTR_g, MP_ARG_REQUIRED | MP_ARG_INT },
 | 
				
			||||||
 | 
					        { MP_QSTR_b, MP_ARG_REQUIRED | MP_ARG_INT }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self->st7789->set_palette(
 | 
					    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
 | 
				
			||||||
        mp_obj_get_int(index) & 0xff,
 | 
					    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 | 
				
			||||||
        mp_obj_get_int(colour) & 0xffff
 | 
					
 | 
				
			||||||
 | 
					    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, GenericST7789_obj_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    self->st7789->update_pen(
 | 
				
			||||||
 | 
					        args[ARG_i].u_int & 0xff,
 | 
				
			||||||
 | 
					        args[ARG_r].u_int & 0xff,
 | 
				
			||||||
 | 
					        args[ARG_g].u_int & 0xff,
 | 
				
			||||||
 | 
					        args[ARG_b].u_int & 0xff
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return mp_const_none;
 | 
					    return mp_const_none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in) {
 | 
					 | 
				
			||||||
    GenericST7789_obj_t *self = MP_OBJ_TO_PTR2(self_in, GenericST7789_obj_t);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    int result = self->st7789->reserve_palette();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (result == -1) mp_raise_ValueError("reserve_palette failed. No space in palette!");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return mp_obj_new_int(result);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 | 
					mp_obj_t GenericST7789_create_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 | 
				
			||||||
    enum { ARG_self, ARG_r, ARG_g, ARG_b };
 | 
					    enum { ARG_self, ARG_r, ARG_g, ARG_b };
 | 
				
			||||||
    static const mp_arg_t allowed_args[] = {
 | 
					    static const mp_arg_t allowed_args[] = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,8 @@ extern mp_obj_t GenericST7789_update(mp_obj_t self_in);
 | 
				
			||||||
extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness);
 | 
					extern mp_obj_t GenericST7789_set_backlight(mp_obj_t self_in, mp_obj_t brightness);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Palette management
 | 
					// Palette management
 | 
				
			||||||
extern mp_obj_t GenericST7789_set_palette_mode(mp_obj_t self_in, mp_obj_t mode);
 | 
					extern mp_obj_t GenericST7789_update_pen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
 | 
				
			||||||
extern mp_obj_t GenericST7789_set_palette(mp_obj_t self_in, mp_obj_t index, mp_obj_t colour);
 | 
					extern mp_obj_t GenericST7789_reset_pen(mp_obj_t self_in, mp_obj_t pen);
 | 
				
			||||||
extern mp_obj_t GenericST7789_reserve_palette(mp_obj_t self_in);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pen
 | 
					// Pen
 | 
				
			||||||
extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen);
 | 
					extern mp_obj_t GenericST7789_set_pen(mp_obj_t self_in, mp_obj_t pen);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Ładowanie…
	
		Reference in New Issue