CHGame 0.3.0
Libraries for the CHGame handheld
Loading...
Searching...
No Matches
CHGfx_AdafruitGFX.h
Go to the documentation of this file.
1/**
2 * @file CHGfx_AdafruitGFX.h
3 * @brief Drop CHGfx in underneath Adafruit_GFX: existing sketches keep
4 * their drawing code and get the framebuffer and DMA transport.
5 *
6 * **Why you might want this.** Adafruit_GFX itself is not the slow part.
7 * The slow part is Adafruit_ST7735 underneath it, pushing every pixel
8 * down a polled SPI link with a fresh address window each time.
9 * Adafruit_GFX's own feature set - print(), setTextSize(), the custom
10 * GFXfont system, drawBitmap(), triangles, rounded rectangles - is
11 * perfectly good.
12 *
13 * So: subclass Adafruit_GFX, point drawPixel() at the 4 bpp
14 * framebuffer, override the span primitives with CHGfx's fast paths,
15 * and present with display(). Existing sketches keep working and get
16 * the full DMA transport underneath.
17 *
18 * @code
19 * #include <Adafruit_GFX.h> // see the note below - required
20 * #include <CHGfx.h>
21 * #include <CHGfx_AdafruitGFX.h>
22 * CHGfx_GFX tft;
23 *
24 * void setup() {
25 * tft.begin(); // same as Gfx.begin()
26 * tft.setPalette(myPalette, 16);
27 * tft.setTextColor(WHITE_IDX);
28 * tft.setCursor(4, 4);
29 * tft.print("hello");
30 * tft.display(); // one DMA burst
31 * }
32 * @endcode
33 *
34 * **The one thing that changes.** Adafruit_GFX passes colours as
35 * uint16_t. Here a colour is a PALETTE INDEX, 0..15 - there is no
36 * 16-colour framebuffer that can hold an arbitrary RGB565. Passing
37 * ST77XX_RED (0xF800) would be read as index 0, i.e. black, so map your
38 * colours once at setup:
39 *
40 * @code
41 * const uint8_t RED = Gfx.nearest(0xF800);
42 * @endcode
43 *
44 * Set `CHGFX_GFX_AUTOMAP` if you would rather have colours mapped for you
45 * at every call. It makes old code work verbatim but costs a 16-entry
46 * search per drawing call, so it is off by default.
47 *
48 * **Fonts.** Adafruit_GFX's own setFont() keeps working here, and CHGfx's
49 * bundled fonts are GFXfonts, so they go straight in:
50 *
51 * @code
52 * #include <fonts/CHGfx_Sans12.h>
53 * tft.setFont(&CHGfx_Sans12);
54 * @endcode
55 *
56 * Note that tft.setFont() and Gfx.setFont() are SEPARATE state. The
57 * bridge routes drawing through Adafruit_GFX, which does its own glyph
58 * walking, so a font set on `Gfx` does not affect `tft` and vice versa.
59 * Pick one text path per sketch.
60 *
61 * **Requires** the Adafruit GFX Library to be installed. This header is
62 * not included by CHGfx.h - include it yourself only if you want the
63 * bridge.
64 *
65 * You must also write `#include <Adafruit_GFX.h>` in your .ino, above
66 * this include. That looks redundant, but the Arduino builder works out
67 * which library include paths to add by scanning the SKETCH file only.
68 * A library reached solely through another library's header never gets
69 * its path added, and the include below would fail to resolve.
70 */
71#pragma once
72
73#include "CHGfx.h"
74
75#if !__has_include(<Adafruit_GFX.h>)
76 #error "Adafruit_GFX.h not found. Install the Adafruit GFX Library, AND add \
77'#include <Adafruit_GFX.h>' to your .ino ABOVE this include - the Arduino \
78builder only resolves libraries that the sketch itself names."
79#endif
80
81#include <Adafruit_GFX.h>
82
83/**
84 * @defgroup chgfx_adafruit Adafruit_GFX bridge
85 * @ingroup lib_chgfx
86 * @brief CHGfx_GFX: an Adafruit_GFX whose drawing lands in CHGfx's
87 * framebuffer, from `CHGfx_AdafruitGFX.h` (needs the Adafruit GFX
88 * Library).
89 *
90 * See CHGfx_AdafruitGFX.h for the two things that change: colours are
91 * palette indices, and the sketch must include `<Adafruit_GFX.h>` itself.
92 * @{
93 */
94
95/**
96 * @brief An Adafruit_GFX display that draws into CHGfx's 4 bpp
97 * framebuffer and presents it by DMA.
98 *
99 * Adafruit_GFX's print(), fonts, bitmaps, triangles and the rest work as
100 * usual; the pixel and span primitives go to CHGfx's fast paths. Every
101 * `color` is a palette index, 0..15 (only the low 4 bits are used),
102 * unless `CHGFX_GFX_AUTOMAP` is defined, in which case it is an RGB565
103 * colour matched to the nearest palette entry at every call. Nothing
104 * reaches the panel until display() or displayAsync().
105 */
106class CHGfx_GFX : public Adafruit_GFX {
107public:
108 /** @brief Makes a GFX_W x GFX_H display. Call begin() in `setup()`. */
109 CHGfx_GFX() : Adafruit_GFX(GFX_W, GFX_H) { }
110
111 /**
112 * @brief Starts the panel, as gfx_begin().
113 * @param spiDiv SPI clock divider (default GFX_DIV2, 24 MHz).
114 * @param colorMode GFX_16BPP (the default), GFX_12BPP or GFX_18BPP.
115 */
116 void begin(uint8_t spiDiv = GFX_DIV2, uint8_t colorMode = GFX_16BPP) {
117 gfx_begin(spiDiv, colorMode);
118 }
119
120 /* ---- the one method Adafruit_GFX actually requires ---- */
121 /**
122 * @brief Sets one pixel in the framebuffer (gfx_pixel()).
123 * @param x Column.
124 * @param y Row.
125 * @param color Palette index.
126 */
127 void drawPixel(int16_t x, int16_t y, uint16_t color) override {
128 gfx_pixel(x, y, idx(color));
129 }
130
131 /* ---- overrides that matter for speed --------------------------
132 * Adafruit_GFX's defaults build every one of these out of
133 * drawPixel(). Routing them at the framebuffer instead is where the
134 * CPU-side win comes from: a filled span is word stores, 8 pixels
135 * at a time, rather than a call and a clip test per pixel. */
136 /**
137 * @brief Draws a horizontal line (gfx_hline()).
138 * @param x Left end.
139 * @param y Row.
140 * @param w Length in pixels.
141 * @param color Palette index.
142 */
143 void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override {
144 gfx_hline(x, y, w, idx(color));
145 }
146 /**
147 * @brief Draws a vertical line (gfx_vline()).
148 * @param x Column.
149 * @param y Top end.
150 * @param h Length in pixels.
151 * @param color Palette index.
152 */
153 void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override {
154 gfx_vline(x, y, h, idx(color));
155 }
156 /**
157 * @brief Fills a rectangle (gfx_fillRect()).
158 * @param x Left edge.
159 * @param y Top edge.
160 * @param w Width.
161 * @param h Height.
162 * @param color Palette index.
163 */
164 void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override {
165 gfx_fillRect(x, y, w, h, idx(color));
166 }
167 /**
168 * @brief Fills the screen (the clip rectangle) with one colour (gfx_clear()).
169 * @param color Palette index.
170 */
171 void fillScreen(uint16_t color) override {
172 gfx_clear(idx(color));
173 }
174 /**
175 * @brief Sets one pixel (gfx_pixel()); the same as drawPixel().
176 * @param x Column.
177 * @param y Row.
178 * @param color Palette index.
179 */
180 void writePixel(int16_t x, int16_t y, uint16_t color) override {
181 gfx_pixel(x, y, idx(color));
182 }
183 /**
184 * @brief Fills a rectangle (gfx_fillRect()); the same as fillRect().
185 * @param x Left edge.
186 * @param y Top edge.
187 * @param w Width.
188 * @param h Height.
189 * @param color Palette index.
190 */
191 void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override {
192 gfx_fillRect(x, y, w, h, idx(color));
193 }
194 /**
195 * @brief Draws a horizontal line (gfx_hline()); the same as drawFastHLine().
196 * @param x Left end.
197 * @param y Row.
198 * @param w Length in pixels.
199 * @param color Palette index.
200 */
201 void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override {
202 gfx_hline(x, y, w, idx(color));
203 }
204 /**
205 * @brief Draws a vertical line (gfx_vline()); the same as drawFastVLine().
206 * @param x Column.
207 * @param y Top end.
208 * @param h Length in pixels.
209 * @param color Palette index.
210 */
211 void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override {
212 gfx_vline(x, y, h, idx(color));
213 }
214 /* Nothing to batch - we are writing to RAM, not to the panel. */
215 /** @brief Does nothing: drawing goes to RAM, so there is nothing to batch. */
216 void startWrite(void) override { }
217 /** @brief Does nothing: drawing goes to RAM, so there is nothing to batch. */
218 void endWrite(void) override { }
219
220 /* ---- presenting ----
221 * Adafruit_ST7735 has no display() because it writes straight to the
222 * glass. Here nothing reaches the panel until you ask. */
223 /** @brief Sends the whole framebuffer to the panel and waits for it (gfx_flush()). */
224 void display() { gfx_flush(); }
225 /** @brief Starts sending the whole framebuffer by DMA and returns at once (gfx_flushAsync()). */
227 /**
228 * @brief Sends one rectangle of the framebuffer and waits for it (gfx_flushRect()).
229 * @param x Left edge.
230 * @param y Top edge.
231 * @param w Width.
232 * @param h Height.
233 */
234 void displayRect(int x, int y, int w, int h) { gfx_flushRect(x, y, w, h); }
235 /**
236 * @brief Starts sending one rectangle of the framebuffer and returns at once
237 * (gfx_flushRectAsync()).
238 * @param x Left edge.
239 * @param y Top edge.
240 * @param w Width.
241 * @param h Height.
242 */
243 void displayRectAsync(int x, int y, int w, int h) { gfx_flushRectAsync(x, y, w, h); }
244 /** @brief Whether an async flush is in flight (gfx_busy()). @return true while sending. */
245 bool busy() const { return gfx_busy(); }
246 /** @brief Waits for the flush in flight to finish (gfx_wait()); draw after it. */
247 void wait() { gfx_wait(); }
248
249 /* ---- palette passthrough ---- */
250 /**
251 * @brief Sets the first `n` palette entries (gfx_setPalette()).
252 * @param p RGB565 colours.
253 * @param n How many, at most 16.
254 */
255 void setPalette(const uint16_t *p, uint8_t n) { gfx_setPalette(p, n); }
256 /**
257 * @brief Sets one palette entry (gfx_setPaletteEntry()).
258 * @param i Palette index, 0..15.
259 * @param c RGB565 colour.
260 */
261 void setPaletteEntry(uint8_t i, uint16_t c) { gfx_setPaletteEntry(i, c); }
262 /**
263 * @brief Nearest palette index for an RGB565 colour (gfx_nearest()):
264 * map Adafruit colour constants once at setup.
265 * @param rgb565 The colour.
266 * @return Palette index, 0..15.
267 */
268 uint8_t nearest(uint16_t rgb565) const { return gfx_nearest(rgb565); }
269 /**
270 * @brief Switches the colour output mode (gfx_setColorMode()).
271 * @param m GFX_16BPP, GFX_12BPP or GFX_18BPP.
272 */
273 void setColorMode(uint8_t m) { gfx_setColorMode(m); }
274
275private:
276 static inline uint8_t idx(uint16_t color) {
277#ifdef CHGFX_GFX_AUTOMAP
278 /* Convenience mode: treat the argument as a real RGB565 and find
279 * the closest palette slot. Correct for legacy code, but it is a
280 * 16-entry search on every drawing call. */
281 return gfx_nearest(color);
282#else
283 return (uint8_t)(color & 0x0F);
284#endif
285 }
286};
287
288/** @} */
CHGfx: a maximum-throughput ST7735 driver for the CHGame board (CH32X035G8U6 @ 48 MHz,...
An Adafruit_GFX display that draws into CHGfx's 4 bpp framebuffer and presents it by DMA.
Definition CHGfx_AdafruitGFX.h:106
uint8_t nearest(uint16_t rgb565) const
Nearest palette index for an RGB565 colour (gfx_nearest()): map Adafruit colour constants once at set...
Definition CHGfx_AdafruitGFX.h:268
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override
Fills a rectangle (gfx_fillRect()); the same as fillRect().
Definition CHGfx_AdafruitGFX.h:191
void writePixel(int16_t x, int16_t y, uint16_t color) override
Sets one pixel (gfx_pixel()); the same as drawPixel().
Definition CHGfx_AdafruitGFX.h:180
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override
Draws a horizontal line (gfx_hline()); the same as drawFastHLine().
Definition CHGfx_AdafruitGFX.h:201
void endWrite(void) override
Does nothing: drawing goes to RAM, so there is nothing to batch.
Definition CHGfx_AdafruitGFX.h:218
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override
Draws a vertical line (gfx_vline()); the same as drawFastVLine().
Definition CHGfx_AdafruitGFX.h:211
void setPalette(const uint16_t *p, uint8_t n)
Sets the first n palette entries (gfx_setPalette()).
Definition CHGfx_AdafruitGFX.h:255
void startWrite(void) override
Does nothing: drawing goes to RAM, so there is nothing to batch.
Definition CHGfx_AdafruitGFX.h:216
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override
Draws a horizontal line (gfx_hline()).
Definition CHGfx_AdafruitGFX.h:143
bool busy() const
Whether an async flush is in flight (gfx_busy()).
Definition CHGfx_AdafruitGFX.h:245
void setPaletteEntry(uint8_t i, uint16_t c)
Sets one palette entry (gfx_setPaletteEntry()).
Definition CHGfx_AdafruitGFX.h:261
void fillScreen(uint16_t color) override
Fills the screen (the clip rectangle) with one colour (gfx_clear()).
Definition CHGfx_AdafruitGFX.h:171
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override
Fills a rectangle (gfx_fillRect()).
Definition CHGfx_AdafruitGFX.h:164
CHGfx_GFX()
Makes a GFX_W x GFX_H display.
Definition CHGfx_AdafruitGFX.h:109
void displayRectAsync(int x, int y, int w, int h)
Starts sending one rectangle of the framebuffer and returns at once (gfx_flushRectAsync()).
Definition CHGfx_AdafruitGFX.h:243
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override
Draws a vertical line (gfx_vline()).
Definition CHGfx_AdafruitGFX.h:153
void begin(uint8_t spiDiv=GFX_DIV2, uint8_t colorMode=GFX_16BPP)
Starts the panel, as gfx_begin().
Definition CHGfx_AdafruitGFX.h:116
void display()
Sends the whole framebuffer to the panel and waits for it (gfx_flush()).
Definition CHGfx_AdafruitGFX.h:224
void drawPixel(int16_t x, int16_t y, uint16_t color) override
Sets one pixel in the framebuffer (gfx_pixel()).
Definition CHGfx_AdafruitGFX.h:127
void setColorMode(uint8_t m)
Switches the colour output mode (gfx_setColorMode()).
Definition CHGfx_AdafruitGFX.h:273
void wait()
Waits for the flush in flight to finish (gfx_wait()); draw after it.
Definition CHGfx_AdafruitGFX.h:247
void displayRect(int x, int y, int w, int h)
Sends one rectangle of the framebuffer and waits for it (gfx_flushRect()).
Definition CHGfx_AdafruitGFX.h:234
void displayAsync()
Starts sending the whole framebuffer by DMA and returns at once (gfx_flushAsync()).
Definition CHGfx_AdafruitGFX.h:226
#define GFX_H
Screen height in pixels (default 128).
Definition CHGfx.h:109
#define GFX_W
Screen width in pixels (default 128).
Definition CHGfx.h:105
@ GFX_DIV2
HCLK/2 = 24 MHz: the fastest the chip can clock SPI, and the default.
Definition CHGfx.h:232
@ GFX_16BPP
ST7735 COLMOD 0x05, RGB565, 2 bytes/px -> 90 fps.
Definition CHGfx.h:219
void gfx_hline(int x, int y, int w, uint8_t c)
Draws a horizontal line from (x, y), w pixels to the right.
void gfx_clear(uint8_t c)
Fills the clip rectangle (normally the whole screen) with one colour.
void gfx_pixel(int x, int y, uint8_t c)
Sets one pixel.
void gfx_fillRect(int x, int y, int w, int h, uint8_t c)
Fills a rectangle.
void gfx_vline(int x, int y, int h, uint8_t c)
Draws a vertical line from (x, y), h pixels down.
void gfx_setPaletteEntry(uint8_t index, uint16_t rgb565)
Sets one palette entry.
void gfx_setPalette(const uint16_t *rgb565, uint8_t count)
Sets the first count palette entries.
uint8_t gfx_nearest(uint16_t rgb565)
Nearest palette index for a full RGB565 colour.
void gfx_flushRectAsync(int x, int y, int w, int h)
Starts sending one rectangle of the framebuffer and returns at once, as gfx_flushAsync() does for the...
void gfx_flushAsync(void)
Starts sending the whole framebuffer and returns at once; the DMA interrupt does the rest.
void gfx_wait(void)
Waits until the flush in flight, if any, has finished.
bool gfx_busy(void)
Whether an async flush is still in flight.
void gfx_flushRect(int x, int y, int w, int h)
Sends one rectangle of the framebuffer to the panel and returns when it has gone out.
void gfx_flush(void)
Sends the whole framebuffer to the panel and returns when it has gone out.
static void gfx_begin(uint8_t spiDiv=GFX_DIV2, uint8_t colorMode=GFX_16BPP)
Starts the panel: pins, SPI1, DMA, a hardware reset and the ST7735 initialisation,...
Definition CHGfx.h:308
void gfx_setColorMode(uint8_t mode)
Switches the panel's colour output mode.