Skip to content

Commit b1664b5

Browse files
committed
PicoGraphics: Support multiple layers in more types.
1 parent 540f480 commit b1664b5

File tree

9 files changed

+158
-67
lines changed

9 files changed

+158
-67
lines changed

drivers/st7735/st7735.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,21 @@ namespace pimoroni {
165165

166166
// Native 16-bit framebuffer update
167167
void ST7735::update(PicoGraphics *graphics) {
168-
command(reg::RAMWR);
169-
gpio_put(dc, 1); // data mode
170-
gpio_put(cs, 0);
168+
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) {
169+
command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
170+
} else {
171+
command(reg::RAMWR);
172+
gpio_put(dc, 1); // data mode
173+
gpio_put(cs, 0);
171174

172-
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
173-
if (length > 0) {
174-
spi_write_blocking(spi, (const uint8_t*)data, length);
175-
}
176-
});
175+
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
176+
if (length > 0) {
177+
spi_write_blocking(spi, (const uint8_t*)data, length);
178+
}
179+
});
177180

178-
gpio_put(cs, 1);
181+
gpio_put(cs, 1);
182+
}
179183
}
180184

181185
void ST7735::set_backlight(uint8_t brightness) {

drivers/st7789/st7789.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -282,26 +282,30 @@ namespace pimoroni {
282282
void ST7789::update(PicoGraphics *graphics) {
283283
uint8_t cmd = reg::RAMWR;
284284

285-
gpio_put(dc, 0); // command mode
286-
gpio_put(cs, 0);
287-
if(spi) { // SPI Bus
288-
spi_write_blocking(spi, &cmd, 1);
289-
} else { // Parallel Bus
290-
write_blocking_parallel(&cmd, 1);
291-
}
285+
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) { // Display buffer is screen native
286+
command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
287+
} else {
288+
gpio_put(dc, 0); // command mode
289+
gpio_put(cs, 0);
290+
if(spi) { // SPI Bus
291+
spi_write_blocking(spi, &cmd, 1);
292+
} else { // Parallel Bus
293+
write_blocking_parallel(&cmd, 1);
294+
}
292295

293-
gpio_put(dc, 1); // data mode
296+
gpio_put(dc, 1); // data mode
294297

295-
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
296-
if (length > 0) {
297-
write_blocking_dma((const uint8_t*)data, length);
298-
}
299-
else {
300-
dma_channel_wait_for_finish_blocking(st_dma);
301-
}
302-
});
298+
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
299+
if (length > 0) {
300+
write_blocking_dma((const uint8_t*)data, length);
301+
}
302+
else {
303+
dma_channel_wait_for_finish_blocking(st_dma);
304+
}
305+
});
303306

304-
gpio_put(cs, 1);
307+
gpio_put(cs, 1);
308+
}
305309
}
306310

307311
void ST7789::set_backlight(uint8_t brightness) {

libraries/pico_graphics/pico_graphics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ namespace pimoroni {
2121

2222
void PicoGraphics::set_layer(uint l) {
2323
this->layer = l;
24+
this->layer_offset = this->bounds.w * this->bounds.h * l;
2425
};
2526
uint PicoGraphics::get_layer() {
2627
return this->layer;

libraries/pico_graphics/pico_graphics.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ namespace pimoroni {
7979
}
8080
}
8181

82+
constexpr operator bool() {return r || g || b;};
8283
constexpr RGB operator+ (const RGB& c) const {return RGB(r + c.r, g + c.g, b + c.b);}
8384
constexpr RGB& operator+=(const RGB& c) {r += c.r; g += c.g; b += c.b; return *this;}
8485
constexpr RGB& operator-=(const RGB& c) {r -= c.r; g -= c.g; b -= c.b; return *this;}
@@ -228,6 +229,7 @@ namespace pimoroni {
228229

229230
uint layers = 1;
230231
uint layer = 0;
232+
uint layer_offset = 0;
231233

232234
typedef std::function<void(void *data, size_t length)> conversion_callback_func;
233235
typedef std::function<RGB565()> next_pixel_func;

libraries/pico_graphics/pico_graphics_pen_p4.cpp

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ namespace pimoroni {
5959

6060
// pointer to byte in framebuffer that contains this pixel
6161
uint8_t *buf = (uint8_t *)frame_buffer;
62+
buf += this->layer_offset / 2;
6263
uint8_t *f = &buf[i / 2];
6364

6465
uint8_t o = (~i & 0b1) * 4; // bit offset within byte
@@ -74,6 +75,7 @@ namespace pimoroni {
7475

7576
// pointer to byte in framebuffer that contains this pixel
7677
uint8_t *buf = (uint8_t *)frame_buffer;
78+
buf += this->layer_offset / 2;
7779
uint8_t *f = &buf[i / 2];
7880

7981
// doubled up color value, so the color is stored in both nibbles
@@ -144,16 +146,39 @@ namespace pimoroni {
144146
uint8_t *src = (uint8_t *)frame_buffer;
145147
uint8_t o = 4;
146148

147-
frame_convert_rgb565(callback, [&]() {
148-
uint8_t c = *src;
149-
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
150-
151-
// Increment to next 4-bit entry
152-
o ^= 4;
153-
if (o != 0) ++src;
154-
155-
return cache[b];
156-
});
149+
if(this->layers > 1) {
150+
151+
uint offset = this->bounds.w * this->bounds.h / 2;
152+
153+
frame_convert_rgb565(callback, [&]() {
154+
uint8_t b = 0;
155+
156+
// Iterate through layers in reverse order
157+
// Return the first nonzero (not transparent) pixel
158+
for(auto layer = this->layers; layer > 0; layer--) {
159+
uint8_t c = *(src + offset * (layer - 1));
160+
b = (c >> o) & 0xf; // bit value shifted to position
161+
if (b) break;
162+
}
163+
164+
// Increment to next 4-bit entry
165+
o ^= 4;
166+
if (o != 0) src++;
167+
168+
return cache[b];
169+
});
170+
} else {
171+
frame_convert_rgb565(callback, [&]() {
172+
uint8_t c = *src;
173+
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
174+
175+
// Increment to next 4-bit entry
176+
o ^= 4;
177+
if (o != 0) ++src;
178+
179+
return cache[b];
180+
});
181+
}
157182
}
158183
}
159184
}

libraries/pico_graphics/pico_graphics_pen_p8.cpp

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ namespace pimoroni {
5151
}
5252
void PicoGraphics_PenP8::set_pixel(const Point &p) {
5353
uint8_t *buf = (uint8_t *)frame_buffer;
54+
buf += this->layer_offset;
5455
buf[p.y * bounds.w + p.x] = color;
5556
}
5657

5758
void PicoGraphics_PenP8::set_pixel_span(const Point &p, uint l) {
5859
// pointer to byte in framebuffer that contains this pixel
5960
uint8_t *buf = (uint8_t *)frame_buffer;
61+
buf += this->layer_offset;
6062
buf = &buf[p.y * bounds.w + p.x];
6163

6264
while(l--) {
@@ -103,26 +105,70 @@ namespace pimoroni {
103105
}
104106

105107
void PicoGraphics_PenP8::frame_convert(PenType type, conversion_callback_func callback) {
106-
if(type == PEN_RGB565) {
107-
// Cache the RGB888 palette as RGB565
108-
RGB565 cache[palette_size];
109-
for(auto i = 0u; i < palette_size; i++) {
110-
cache[i] = palette[i].to_rgb565();
111-
}
108+
// Treat our void* frame_buffer as uint8_t
109+
uint8_t *src = (uint8_t *)frame_buffer;
110+
111+
if(layers > 1) {
112+
// The size of a single layer
113+
uint offset = this->bounds.w * this->bounds.h;
114+
115+
if(type == PEN_RGB565) {
116+
// Cache the RGB888 palette as RGB565
117+
RGB565 cache[palette_size];
118+
for(auto i = 0u; i < palette_size; i++) {
119+
cache[i] = palette[i].to_rgb565();
120+
}
121+
122+
frame_convert_rgb565(callback, [&]() {
123+
// Check the *palette* index, rather than the colour
124+
// Thus palette entry 0 is *always* transparent
125+
uint8_t c = 0;
126+
127+
// Iterate through layers in reverse order
128+
// Return the first nonzero (not transparent) pixel
129+
for(auto layer = this->layers; layer > 0; layer--) {
130+
c = *(src + offset * (layer - 1));
131+
if (c) break;
132+
}
112133

113-
// Treat our void* frame_buffer as uint8_t
114-
uint8_t *src = (uint8_t *)frame_buffer;
134+
src++;
115135

116-
frame_convert_rgb565(callback, [&]() {
117-
return cache[*src++];
118-
});
119-
} else if (type == PEN_RGB888) {
120-
// Treat our void* frame_buffer as uint8_t
121-
uint8_t *src = (uint8_t *)frame_buffer;
136+
return cache[c];
137+
});
138+
} else if (type == PEN_RGB888) {
139+
frame_convert_rgb888(callback, [&]() {
140+
// Check the *palette* index, rather than the colour
141+
// Thus palette entry 0 is *always* transparent
142+
uint8_t c = 0;
122143

123-
frame_convert_rgb888(callback, [&]() {
124-
return palette[*src++].to_rgb888();
125-
});
144+
// Iterate through layers in reverse order
145+
// Return the first nonzero (not transparent) pixel
146+
for(auto layer = this->layers; layer > 0; layer--) {
147+
c = *(src + offset * (layer - 1));
148+
if (c) break;
149+
}
150+
151+
src++;
152+
153+
return palette[c].to_rgb888();
154+
});
155+
}
156+
} else {
157+
if(type == PEN_RGB565) {
158+
// Cache the RGB888 palette as RGB565
159+
RGB565 cache[palette_size];
160+
for(auto i = 0u; i < palette_size; i++) {
161+
cache[i] = palette[i].to_rgb565();
162+
}
163+
164+
frame_convert_rgb565(callback, [&]() {
165+
return cache[*src++];
166+
});
167+
} else if (type == PEN_RGB888) {
168+
frame_convert_rgb888(callback, [&]() {
169+
return palette[*src++].to_rgb888();
170+
});
171+
}
126172
}
127173
}
128174
}

libraries/pico_graphics/pico_graphics_pen_rgb332.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ namespace pimoroni {
2323
}
2424
void PicoGraphics_PenRGB332::set_pixel(const Point &p) {
2525
uint8_t *buf = (uint8_t *)frame_buffer;
26-
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
26+
buf += this->layer_offset;
2727
buf[p.y * bounds.w + p.x] = color;
2828
}
2929
void PicoGraphics_PenRGB332::set_pixel_span(const Point &p, uint l) {
3030
// pointer to byte in framebuffer that contains this pixel
3131
uint8_t *buf = (uint8_t *)frame_buffer;
32-
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
32+
buf += this->layer_offset;
3333
buf += p.y * bounds.w + p.x;
3434

3535
while(l--) {
@@ -40,7 +40,7 @@ namespace pimoroni {
4040
if(!bounds.contains(p)) return;
4141

4242
uint8_t *buf = (uint8_t *)frame_buffer;
43-
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
43+
buf += this->layer_offset;
4444

4545
RGB332 blended = RGB(buf[p.y * bounds.w + p.x]).blend(RGB(color), a).to_rgb332();
4646

@@ -99,14 +99,23 @@ namespace pimoroni {
9999
// Treat our void* frame_buffer as uint8_t
100100
uint8_t *src = (uint8_t *)frame_buffer;
101101

102-
if(this->layers > 1) {
103-
// Assume only two layers for now
104-
uint8_t *src_layer2 = src + buffer_size(this->bounds.w, this->bounds.h);
102+
if(this->layers > 1) {
103+
// The size of a single layer
104+
uint offset = this->bounds.w * this->bounds.h;
105105

106106
frame_convert_rgb565(callback, [&]() {
107-
RGB565 c1 = rgb332_to_rgb565_lut[*src++];
108-
RGB565 c2 = rgb332_to_rgb565_lut[*src_layer2++];
109-
return c2 ? c2 : c1;
107+
uint8_t c = 0;
108+
109+
// Iterate through layers in reverse order
110+
// Return the first nonzero (not transparent) pixel
111+
for(auto layer = this->layers; layer > 0; layer--) {
112+
c = *(src + offset * (layer - 1));
113+
if (c) break;
114+
}
115+
116+
src++;
117+
118+
return rgb332_to_rgb565_lut[c];
110119
});
111120
} else {
112121
frame_convert_rgb565(callback, [&]() {

libraries/pico_graphics/pico_graphics_pen_rgb565.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ namespace pimoroni {
2424
void PicoGraphics_PenRGB565::set_pixel(const Point &p) {
2525
uint16_t *buf = (uint16_t *)frame_buffer;
2626
// We can't use buffer_size because our pointer is uint16_t
27-
buf += this->bounds.w * this->bounds.h * layer;
27+
buf += this->layer_offset;
2828
buf[p.y * bounds.w + p.x] = color;
2929
}
3030
void PicoGraphics_PenRGB565::set_pixel_span(const Point &p, uint l) {
3131
// pointer to byte in framebuffer that contains this pixel
3232
uint16_t *buf = (uint16_t *)frame_buffer;
3333
// We can't use buffer_size because our pointer is uint16_t
34-
buf += this->bounds.w * this->bounds.h * layer;
34+
buf += this->layer_offset;
3535
buf = &buf[p.y * bounds.w + p.x];
3636

3737
while(l--) {
@@ -45,10 +45,8 @@ namespace pimoroni {
4545

4646
if(layers > 1) {
4747
// Assume only two layers for now
48-
uint16_t *src_layer2 = src;
49-
5048
// We can't use buffer_size because our pointer is uint16_t
51-
src_layer2 += this->bounds.w * this->bounds.h * layer;
49+
uint16_t *src_layer2 = src + this->bounds.w * this->bounds.h;
5250

5351
frame_convert_rgb565(callback, [&]() {
5452
RGB565 c1 = *src++;

libraries/pico_graphics/pico_graphics_pen_rgb888.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ namespace pimoroni {
2323
}
2424
void PicoGraphics_PenRGB888::set_pixel(const Point &p) {
2525
uint32_t *buf = (uint32_t *)frame_buffer;
26+
buf += this->layer_offset;
2627
buf[p.y * bounds.w + p.x] = color;
2728
}
2829
void PicoGraphics_PenRGB888::set_pixel_span(const Point &p, uint l) {
2930
// pointer to byte in framebuffer that contains this pixel
3031
uint32_t *buf = (uint32_t *)frame_buffer;
32+
buf += this->layer_offset;
3133
buf = &buf[p.y * bounds.w + p.x];
3234

3335
while(l--) {

0 commit comments

Comments
 (0)