PicoGraphics: Support multiple layers in more types.

pull/1011/head
Phil Howard 2024-10-07 15:51:02 +01:00
rodzic 5e0682bc22
commit be24eb5d4e
9 zmienionych plików z 160 dodań i 69 usunięć

Wyświetl plik

@ -165,17 +165,21 @@ namespace pimoroni {
// Native 16-bit framebuffer update
void ST7735::update(PicoGraphics *graphics) {
command(reg::RAMWR);
gpio_put(dc, 1); // data mode
gpio_put(cs, 0);
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) {
command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
command(reg::RAMWR);
gpio_put(dc, 1); // data mode
gpio_put(cs, 0);
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)data, length);
}
});
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)data, length);
}
});
gpio_put(cs, 1);
gpio_put(cs, 1);
}
}
void ST7735::set_backlight(uint8_t brightness) {

Wyświetl plik

@ -282,26 +282,30 @@ namespace pimoroni {
void ST7789::update(PicoGraphics *graphics) {
uint8_t cmd = reg::RAMWR;
gpio_put(dc, 0); // command mode
gpio_put(cs, 0);
if(spi) { // SPI Bus
spi_write_blocking(spi, &cmd, 1);
} else { // Parallel Bus
write_blocking_parallel(&cmd, 1);
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) { // Display buffer is screen native
command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
gpio_put(dc, 0); // command mode
gpio_put(cs, 0);
if(spi) { // SPI Bus
spi_write_blocking(spi, &cmd, 1);
} else { // Parallel Bus
write_blocking_parallel(&cmd, 1);
}
gpio_put(dc, 1); // data mode
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
write_blocking_dma((const uint8_t*)data, length);
}
else {
dma_channel_wait_for_finish_blocking(st_dma);
}
});
gpio_put(cs, 1);
}
gpio_put(dc, 1); // data mode
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
write_blocking_dma((const uint8_t*)data, length);
}
else {
dma_channel_wait_for_finish_blocking(st_dma);
}
});
gpio_put(cs, 1);
}
void ST7789::set_backlight(uint8_t brightness) {

Wyświetl plik

@ -21,6 +21,7 @@ namespace pimoroni {
void PicoGraphics::set_layer(uint l) {
this->layer = l;
this->layer_offset = this->bounds.w * this->bounds.h * l;
};
uint PicoGraphics::get_layer() {
return this->layer;

Wyświetl plik

@ -79,6 +79,7 @@ namespace pimoroni {
}
}
constexpr operator bool() {return r || g || b;};
constexpr RGB operator+ (const RGB& c) const {return RGB(r + c.r, g + c.g, b + c.b);}
constexpr RGB& operator+=(const RGB& c) {r += c.r; g += c.g; b += c.b; return *this;}
constexpr RGB& operator-=(const RGB& c) {r -= c.r; g -= c.g; b -= c.b; return *this;}
@ -228,6 +229,7 @@ namespace pimoroni {
uint layers = 1;
uint layer = 0;
uint layer_offset = 0;
typedef std::function<void(void *data, size_t length)> conversion_callback_func;
typedef std::function<RGB565()> next_pixel_func;

Wyświetl plik

@ -59,6 +59,7 @@ namespace pimoroni {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset / 2;
uint8_t *f = &buf[i / 2];
uint8_t o = (~i & 0b1) * 4; // bit offset within byte
@ -74,6 +75,7 @@ namespace pimoroni {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset / 2;
uint8_t *f = &buf[i / 2];
// doubled up color value, so the color is stored in both nibbles
@ -144,16 +146,39 @@ namespace pimoroni {
uint8_t *src = (uint8_t *)frame_buffer;
uint8_t o = 4;
frame_convert_rgb565(callback, [&]() {
uint8_t c = *src;
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
// Increment to next 4-bit entry
o ^= 4;
if (o != 0) ++src;
if(this->layers > 1) {
return cache[b];
});
uint offset = this->bounds.w * this->bounds.h / 2;
frame_convert_rgb565(callback, [&]() {
uint8_t b = 0;
// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
uint8_t c = *(src + offset * (layer - 1));
b = (c >> o) & 0xf; // bit value shifted to position
if (b) break;
}
// Increment to next 4-bit entry
o ^= 4;
if (o != 0) src++;
return cache[b];
});
} else {
frame_convert_rgb565(callback, [&]() {
uint8_t c = *src;
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
// Increment to next 4-bit entry
o ^= 4;
if (o != 0) ++src;
return cache[b];
});
}
}
}
}

Wyświetl plik

@ -51,12 +51,14 @@ namespace pimoroni {
}
void PicoGraphics_PenP8::set_pixel(const Point &p) {
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenP8::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];
while(l--) {
@ -103,26 +105,70 @@ namespace pimoroni {
}
void PicoGraphics_PenP8::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
if(layers > 1) {
// The size of a single layer
uint offset = this->bounds.w * this->bounds.h;
if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
}
frame_convert_rgb565(callback, [&]() {
// Check the *palette* index, rather than the colour
// Thus palette entry 0 is *always* transparent
uint8_t c = 0;
// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}
src++;
return cache[c];
});
} else if (type == PEN_RGB888) {
frame_convert_rgb888(callback, [&]() {
// Check the *palette* index, rather than the colour
// Thus palette entry 0 is *always* transparent
uint8_t c = 0;
// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}
src++;
return palette[c].to_rgb888();
});
}
} else {
if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
}
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
frame_convert_rgb565(callback, [&]() {
return cache[*src++];
});
} else if (type == PEN_RGB888) {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
frame_convert_rgb888(callback, [&]() {
return palette[*src++].to_rgb888();
});
frame_convert_rgb565(callback, [&]() {
return cache[*src++];
});
} else if (type == PEN_RGB888) {
frame_convert_rgb888(callback, [&]() {
return palette[*src++].to_rgb888();
});
}
}
}
}

Wyświetl plik

@ -23,13 +23,13 @@ namespace pimoroni {
}
void PicoGraphics_PenRGB332::set_pixel(const Point &p) {
uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB332::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;
buf += p.y * bounds.w + p.x;
while(l--) {
@ -40,7 +40,7 @@ namespace pimoroni {
if(!bounds.contains(p)) return;
uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;
RGB332 blended = RGB(buf[p.y * bounds.w + p.x]).blend(RGB(color), a).to_rgb332();
@ -99,14 +99,23 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
if(this->layers > 1) {
// Assume only two layers for now
uint8_t *src_layer2 = src + buffer_size(this->bounds.w, this->bounds.h);
if(this->layers > 1) {
// The size of a single layer
uint offset = this->bounds.w * this->bounds.h;
frame_convert_rgb565(callback, [&]() {
RGB565 c1 = rgb332_to_rgb565_lut[*src++];
RGB565 c2 = rgb332_to_rgb565_lut[*src_layer2++];
return c2 ? c2 : c1;
uint8_t c = 0;
// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}
src++;
return rgb332_to_rgb565_lut[c];
});
} else {
frame_convert_rgb565(callback, [&]() {

Wyświetl plik

@ -24,14 +24,14 @@ namespace pimoroni {
void PicoGraphics_PenRGB565::set_pixel(const Point &p) {
uint16_t *buf = (uint16_t *)frame_buffer;
// We can't use buffer_size because our pointer is uint16_t
buf += this->bounds.w * this->bounds.h * layer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB565::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint16_t *buf = (uint16_t *)frame_buffer;
// We can't use buffer_size because our pointer is uint16_t
buf += this->bounds.w * this->bounds.h * layer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];
while(l--) {
@ -45,10 +45,8 @@ namespace pimoroni {
if(layers > 1) {
// Assume only two layers for now
uint16_t *src_layer2 = src;
// We can't use buffer_size because our pointer is uint16_t
src_layer2 += this->bounds.w * this->bounds.h * layer;
uint16_t *src_layer2 = src + this->bounds.w * this->bounds.h;
frame_convert_rgb565(callback, [&]() {
RGB565 c1 = *src++;

Wyświetl plik

@ -23,11 +23,13 @@ namespace pimoroni {
}
void PicoGraphics_PenRGB888::set_pixel(const Point &p) {
uint32_t *buf = (uint32_t *)frame_buffer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB888::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint32_t *buf = (uint32_t *)frame_buffer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];
while(l--) {