CHGame 0.3.0
Libraries for the CHGame handheld
Loading...
Searching...
No Matches
CHGfx.h
Go to the documentation of this file.
1/**
2 * @file CHGfx.h
3 * @brief CHGfx: a maximum-throughput ST7735 driver for the CHGame board
4 * (CH32X035G8U6 @ 48 MHz, QingKe V4C, 20 KB SRAM, 62 KB flash).
5 *
6 * **Why this exists.** Adafruit_GFX + Adafruit_ST7735 on this part is
7 * slow for three separate reasons, and they compound:
8 *
9 * 1. Every drawPixel() sends CASET + RASET + RAMWR (11 bytes of command
10 * traffic) to paint 2 bytes of pixel. ~85% of the bus is overhead.
11 * 2. The Arduino SPI class transfers one byte at a time in a polled loop
12 * (cores/.../libraries/SPI/src/utility/spi_com.c spins on TXE for
13 * every single byte). The CPU is the bottleneck, not the wire.
14 * 3. There is no framebuffer, so overdraw goes straight out over SPI.
15 *
16 * **What this does instead.**
17 *
18 * - Register-level SPI1 at HCLK/2 = 24 MHz. That is the CH32X035 hard
19 * ceiling: "Maximum clock frequency supports up to half of FHCLK"
20 * (Reference Manual ch.16.1), and HCLK cannot exceed 48 MHz because
21 * this part has no PLL, only the 48 MHz HSI RC (RM ch.3.3).
22 * - DMA1 channel 3 - the SPI1_TX request line (RM 9.2.3) - pushes whole
23 * chunks with zero CPU involvement.
24 * - 16-bit SPI data frames (DFF=1) so DMA does half as many bus cycles.
25 * - A 4 bpp (16-colour) framebuffer. 128*128 RGB565 is 32 KB and this
26 * chip has 20 KB, so a full-colour framebuffer is physically
27 * impossible. 4 bpp is 8 KB and leaves room to live.
28 * - A 256-entry uint32 lookup table expands one framebuffer byte
29 * (= 2 pixels) into one 32-bit store. Conversion costs ~3 cycles per
30 * pixel against a 32-cycle-per-pixel SPI budget, so the wire stays
31 * saturated. Free for the WIRE, not for the CPU: an async flush
32 * still spends its conversion time inside the DMA interrupt - see
33 * "What a flush costs the CPU" in @ref chgfx_present.
34 * - Optional 12 bpp (RGB444) output - ST7735 COLMOD 0x03. Three bytes
35 * per two pixels instead of four: 25% less traffic, and with a
36 * 16-colour palette you lose nothing you were actually using.
37 * - Ping-pong chunk buffers driven by the DMA transfer-complete ISR, so
38 * gfx_flushAsync() returns immediately and game logic overlaps the
39 * ~11 ms it takes to shift a frame out.
40 * - The conversion inner loops are linked into .data so they execute
41 * from SRAM. Flash on this part runs at 3 wait states above 24 MHz
42 * (RM 20.3.1, FLASH_ACTLR LATENCY = 10b); SRAM runs at zero.
43 *
44 * **Ceiling.** 24 MHz SPI = 3.0 MB/s.
45 *
46 * | Output | Bytes a frame | Frame time | Frame rate |
47 * |---|---:|---:|---:|
48 * | 16 bpp, 128*128*2 | 32768 | 10.9 ms | 91 fps |
49 * | 12 bpp, 128*128*1.5 | 24576 | 8.2 ms | 122 fps |
50 *
51 * Nothing on this chip beats that: there is no parallel LCD interface,
52 * no second SPI on these pins, and no PLL to go past 48 MHz HCLK.
53 *
54 * Everything is a plain C function (`gfx_*`); the CHGfx class and its one
55 * instance, Gfx, are inline forwarders for the `Gfx.clear(0)` spelling.
56 * The topics are listed under @ref lib_chgfx.
57 */
58#pragma once
59
60#include <Arduino.h>
61#include <stdint.h>
62#include "CHGfx_gfxfont.h"
63
64#if !defined(CH32X035)
65 #error "CHGfx targets the CH32X035. It drives SPI1 and DMA1 channel 3 directly and is not portable as-is. Select a CH32X035 board."
66#endif
67
68/**
69 * @defgroup chgfx_config Configuration
70 * @ingroup lib_chgfx
71 * @brief Screen geometry, the panel's wiring, colour modes and SPI
72 * dividers: the build options and the constants they define.
73 *
74 * The macros here can be overridden with `-D` build flags. They are
75 * compiled into the library's own files, so they have to be build flags
76 * (`--build-property build.extra_flags=-DGFX_CHUNK_ROWS=4` with
77 * `arduino-cli`), not `#define`s in the sketch. Two more switches are
78 * read only by the library's `.cpp` files:
79 *
80 * - `CHGFX_NO_SD_PARK`: do not drive the shared SD card's chip select
81 * (CHGFX_SDCS_PORT / CHGFX_SDCS_PIN) high at gfx_begin(). Define it if
82 * nothing else shares SPI1.
83 * - `CHGFX_ISR_IN_SRAM`: run the DMA interrupt handler from SRAM. An
84 * async flush costs 4-9% less CPU (0.1-0.25 ms a full frame), for about
85 * 330 bytes of SRAM.
86 * @{
87 */
88
89/* ------------------------------------------------------------------ */
90/* Geometry */
91/* ------------------------------------------------------------------ */
92/* Override before including, or with a -D build flag. Tested at
93 * 128x128; the framebuffer is W*H/2 bytes, so keep an eye on the 20 KB
94 * SRAM budget if you raise these (160x128 = 10 KB, still fits). W must
95 * be even and W*H/2 must be a multiple of 32. */
96#ifndef GFX_W
97/**
98 * @brief Screen width in pixels (default 128).
99 *
100 * Override with a `-D` build flag. Must be a multiple of 8 (the row
101 * operations work in 32-bit words), and W*H/2 a multiple of 32. The
102 * framebuffer is W*H/2 bytes, so keep an eye on the 20 KB SRAM budget if
103 * you raise it (160x128 = 10 KB, still fits).
104 */
105#define GFX_W 128
106#endif
107#ifndef GFX_H
108/** @brief Screen height in pixels (default 128). Override with a `-D` build flag. */
109#define GFX_H 128
110#endif
111/** @brief Bytes per framebuffer row: two pixels a byte, 64 at 128 wide. */
112#define GFX_FB_STRIDE (GFX_W / 2)
113/** @brief Size of the framebuffer, gfx_fb, in bytes: 8192 at 128x128. */
114#define GFX_FB_BYTES (GFX_FB_STRIDE * GFX_H)
115
116/* Rows converted per DMA chunk. Two chunk buffers are allocated, so
117 * this directly costs GFX_W * GFX_CHUNK_ROWS * 4 bytes of SRAM. */
118#ifndef GFX_CHUNK_ROWS
119/**
120 * @brief Framebuffer rows converted per DMA chunk (default 2).
121 *
122 * Two chunk buffers are allocated, so this directly costs
123 * `GFX_W * GFX_CHUNK_ROWS * 4` bytes of SRAM. Override with
124 * `-DGFX_CHUNK_ROWS=n`; it does not buy much CPU back either (an async
125 * frame measured 2.49 / 2.33 / 2.29 ms of CPU at 2 / 4 / 8 rows, with
126 * `CHGFX_ISR_IN_SRAM`).
127 *
128 * 2 rows = 512 B per buffer, 1 KB total. Measured against the obvious
129 * 4 rows on real hardware: gfx_flush() went 11051 -> 11143 us, about
130 * 0.8%, which is the same order as run-to-run variation. That buys back
131 * a kilobyte, and on a part with 20 KB total a kilobyte is 5% of all
132 * the memory there is - the right way round for this chip. Raise it if
133 * you have RAM to spare and want the last percent.
134 */
135#define GFX_CHUNK_ROWS 2
136#endif
137/**
138 * @brief Size of one DMA chunk buffer in bytes (worst case, 16 bpp).
139 *
140 * There are two; together they are the 1 KB gfx_chunkScratch().
141 */
142#define GFX_CHUNK_BYTES (GFX_W * GFX_CHUNK_ROWS * 2)
143
144/* ------------------------------------------------------------------ */
145/* Wiring */
146/* ------------------------------------------------------------------ */
147/*
148 * SCK and MOSI are fixed: they are SPI1's pins on this package (PA5 and
149 * PA7), and SPI1 is the only peripheral with a DMA path to these lines.
150 * The three control pins are yours to move - redefine any of these
151 * before including CHGfx.h, or with -D build flags.
152 *
153 * Defaults are the CHGame board (see variant_CHGame_Rev0.h):
154 * PA4 = LCD_CS, PB0 = LCD_DC, PB12 = LCD_RST, PB11 = SD_CS
155 * SD_CS is driven high at begin() because the microSD slot shares SPI1.
156 */
157#ifndef CHGFX_CS_PORT
158/**
159 * @brief GPIO port of the panel's chip select (default `GPIOA`, the
160 * CHGame board's LCD_CS on PA4).
161 *
162 * The three control pins (CS, DC, RST) can be moved with `-D` build
163 * flags; define the port and the pin together. SCK and MOSI are fixed:
164 * they are SPI1's pins on this package (PA5 and PA7), and SPI1 is the
165 * only peripheral with a DMA path to these lines.
166 */
167#define CHGFX_CS_PORT GPIOA
168/** @brief Pin number of the panel's chip select on CHGFX_CS_PORT (default 4). */
169#define CHGFX_CS_PIN 4
170#endif
171#ifndef CHGFX_DC_PORT
172/** @brief GPIO port of the panel's data/command line (default `GPIOB`, LCD_DC on PB0). */
173#define CHGFX_DC_PORT GPIOB
174/** @brief Pin number of the panel's data/command line on CHGFX_DC_PORT (default 0). */
175#define CHGFX_DC_PIN 0
176#endif
177#ifndef CHGFX_RST_PORT
178/** @brief GPIO port of the panel's reset line (default `GPIOB`, LCD_RST on PB12). */
179#define CHGFX_RST_PORT GPIOB
180/** @brief Pin number of the panel's reset line on CHGFX_RST_PORT (default 12). */
181#define CHGFX_RST_PIN 12
182#endif
183/* Define CHGFX_NO_SD_PARK to skip driving a shared SD chip select high. */
184#ifndef CHGFX_SDCS_PORT
185/**
186 * @brief GPIO port of the SD card's chip select, which shares SPI1
187 * (default `GPIOB`, SD_CS on PB11).
188 *
189 * gfx_begin() drives it high so the card does not answer the traffic
190 * meant for the panel. Define `CHGFX_NO_SD_PARK` to skip that.
191 */
192#define CHGFX_SDCS_PORT GPIOB
193/** @brief Pin number of the SD card's chip select on CHGFX_SDCS_PORT (default 11). */
194#define CHGFX_SDCS_PIN 11
195#endif
196
197/* ------------------------------------------------------------------ */
198/* Colour output modes */
199/* ------------------------------------------------------------------ */
200/**
201 * @brief The panel's colour output modes, for gfx_begin() and
202 * gfx_setColorMode().
203 *
204 * The framebuffer is always 4 bpp; this is what its palette colours are
205 * expanded to on the wire, so the frame rate is just the byte count.
206 * 12 bpp costs nothing visible behind a 16-colour palette and is a free
207 * 25%, so the CHGame games use it.
208 *
209 * A note on 18 bpp. Each pixel is three bytes and each byte carries its
210 * 6-bit component in bits 7:2, bits 1:0 don't-care (ST7735S DS 9.8.4).
211 * 128*128*3 = 49152 B, so a frame costs 16.4 ms instead of 10.9 - you
212 * are buying one extra bit of red and one of blue for a third of your
213 * frame rate. Worth it for smooth gradients, pointless for sprite work.
214 * Unlike 12 bpp it does not pass through the RGBSET conversion table:
215 * the datasheet only defines 4k->262k and 65k->262k tables, so 18-bit
216 * data reaches the frame memory directly.
217 */
218enum : uint8_t {
219 GFX_16BPP = 0, /**< ST7735 COLMOD 0x05, RGB565, 2 bytes/px -> 90 fps */
220 GFX_12BPP = 1, /**< ST7735 COLMOD 0x03, RGB444, 1.5 bytes/px -> 119 fps */
221 GFX_18BPP = 2 /**< ST7735 COLMOD 0x06, RGB666, 3 bytes/px -> 61 fps */
223
224/**
225 * @brief SPI baud dividers (HCLK / n) for gfx_begin() and gfx_setSpiDiv().
226 *
227 * @note The ST7735S datasheet specifies tSCYCW(min) = 66 ns, i.e. 15 MHz.
228 * 24 MHz is out of spec and only works on short flex. The Benchmark
229 * example's SPI sweep exists to find out whether YOUR panel tolerates it;
230 * GFX_DIV4 is comfortably in spec.
231 */
232enum : uint8_t { GFX_DIV2 = 2, GFX_DIV4 = 4, GFX_DIV8 = 8, GFX_DIV16 = 16 };
233/** @var GFX_DIV2
234 * @brief HCLK/2 = 24 MHz: the fastest the chip can clock SPI, and the default. */
235/** @var GFX_DIV4
236 * @brief HCLK/4 = 12 MHz: within the ST7735S datasheet's limit. */
237/** @var GFX_DIV8
238 * @brief HCLK/8 = 6 MHz. */
239/** @var GFX_DIV16
240 * @brief HCLK/16 = 3 MHz. */
241
242/** @} */
243
244/* ------------------------------------------------------------------ */
245/* Framebuffer + palette */
246/* ------------------------------------------------------------------ */
247/**
248 * @brief The framebuffer: GFX_FB_BYTES of 4 bpp pixels, two per byte.
249 * @ingroup chgfx_draw
250 *
251 * Row y starts at `gfx_fb + y * GFX_FB_STRIDE`. Even x is in the LOW
252 * nibble, odd x in the HIGH nibble - that ordering makes the expansion
253 * LUT a single uint32 store with no shuffling on a little-endian core.
254 * Each nibble is a palette index. Write it directly only for primitives
255 * of your own, and only when no flush is reading it (after gfx_wait()).
256 */
257extern uint8_t gfx_fb[GFX_FB_BYTES];
258/**
259 * @brief The 16 palette colours as set, in RGB565.
260 * @ingroup chgfx_palette
261 *
262 * Read it freely; change it with gfx_setPalette() or
263 * gfx_setPaletteEntry(), which stage the change for the next flush.
264 * The fade (gfx_setFade()) is not applied here: gfx_paletteOut() gives
265 * the colour the panel actually receives.
266 */
267extern uint16_t gfx_pal[16];
268
269/* ------------------------------------------------------------------ */
270/* Lifecycle */
271/* ------------------------------------------------------------------ */
272/**
273 * @defgroup chgfx_setup Setup
274 * @ingroup lib_chgfx
275 * @brief Starting the panel and changing its SPI clock, colour mode,
276 * orientation and scan rate.
277 * @{
278 */
279
280/* The two starts gfx_begin() picks between (see its documentation). */
281void gfx__begin(uint8_t spiDiv, uint8_t colorMode);
282void gfx__begin12(uint8_t spiDiv);
283/**
284 * @brief Starts the panel: pins, SPI1, DMA, a hardware reset and the
285 * ST7735 initialisation, then a default 16-colour palette.
286 *
287 * Call it once in `setup()`. It takes about 0.7 s (the panel's reset
288 * and wake-up delays). It parks the SD card's chip select high (unless
289 * `CHGFX_NO_SD_PARK`), selects the colour mode and, in 12 bpp, programs
290 * the panel's colour LUT (gfx_writeColorLut()). The framebuffer is not
291 * touched and nothing is sent to the glass until the first flush.
292 *
293 * gfx_begin() picks one of two starts. A sketch that names GFX_12BPP and
294 * never calls gfx_setColorMode() gets the 12 bpp-only start, and the 16
295 * and 18 bpp converters and tables stay out of its image (0.2-0.4 KB of
296 * flash, 176 B of it SRAM code). Any other mode, or one only known when
297 * it runs, gets the general start, which keeps all three.
298 *
299 * @param spiDiv SPI clock divider: GFX_DIV2 (24 MHz, the default),
300 * GFX_DIV4, GFX_DIV8 or GFX_DIV16.
301 * @param colorMode GFX_16BPP (the default), GFX_12BPP or GFX_18BPP.
302 *
303 * @code
304 * gfx_begin(GFX_DIV2, GFX_12BPP); // what the CHGame games use
305 * @endcode
306 * @see CHGfx::begin()
307 */
308static inline void gfx_begin(uint8_t spiDiv = GFX_DIV2, uint8_t colorMode = GFX_16BPP) {
309 if (colorMode == GFX_12BPP) gfx__begin12(spiDiv);
310 else gfx__begin(spiDiv, colorMode);
311}
312/**
313 * @brief Changes the SPI clock divider, and sets SPI1 up afresh for the panel.
314 *
315 * Waits for any flush in flight first, then programs all of SPI1 as
316 * gfx_begin() does (its clock on, master, mode 0, MSB first, this divider).
317 * That makes it the way to hand SPI1 back to CHGfx after anything else used
318 * it, such as the Arduino @ref core_spi "SPI" class:
319 * @code
320 * gfx_wait();
321 * SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));
322 * // ... talk to your own device ...
323 * SPI.endTransaction();
324 * gfx_setSpiDiv(gfx_spiDiv()); // the panel's set-up back before the next flush
325 * gfx_flushAsync();
326 * @endcode
327 * @param div GFX_DIV2, GFX_DIV4, GFX_DIV8 or GFX_DIV16 (32 also works);
328 * any other value runs at HCLK/2.
329 */
330void gfx_setSpiDiv(uint8_t div);
331/**
332 * @brief Switches the panel's colour output mode.
333 *
334 * Waits for any flush in flight, sends the panel its new COLMOD (and the
335 * colour LUT when entering 12 bpp), and rebuilds the palette table for
336 * the next flush. Does nothing if the mode is already set.
337 * @param mode GFX_16BPP, GFX_12BPP or GFX_18BPP.
338 * @note Calling it anywhere in a sketch links the 16 and 18 bpp
339 * converters, even if gfx_begin() was given GFX_12BPP.
340 */
341void gfx_setColorMode(uint8_t mode);
342/**
343 * @brief The current colour output mode.
344 * @return GFX_16BPP, GFX_12BPP or GFX_18BPP.
345 */
346uint8_t gfx_colorMode(void);
347/**
348 * @brief The current SPI clock divider.
349 * @return The divider last given to gfx_begin() or gfx_setSpiDiv().
350 */
351uint8_t gfx_spiDiv(void);
352/**
353 * @brief The current SPI clock.
354 * @return The SPI clock in Hz: F_CPU divided by gfx_spiDiv(), 24000000 at
355 * GFX_DIV2.
356 */
357uint32_t gfx_spiHz(void);
358
359/**
360 * @brief Sets the panel's orientation (MADCTL) and the offsets of the
361 * visible window in its memory.
362 *
363 * MADCTL / window offsets differ between 1.44" panel batches. Defaults
364 * match Adafruit's INITR_144GREENTAB (madctl 0xC8, colstart 2, rowstart
365 * 3), which is what an Adafruit_ST7735 setup is already using. Change
366 * them if the image is offset or mirrored. Sends MADCTL at once, so call
367 * it after gfx_wait().
368 * @param madctl ST7735 MADCTL (36h) value: rotation, mirroring, RGB/BGR.
369 * @param colStart First visible column of the panel's memory.
370 * @param rowStart First visible row of the panel's memory.
371 */
372void gfx_setPanelOffsets(uint8_t madctl, uint8_t colStart, uint8_t rowStart);
373/**
374 * @brief Turns the panel's colour inversion (INVON / INVOFF) on or off.
375 *
376 * Sends the command at once, so call it after gfx_wait().
377 * @param on true to invert every colour, false for normal.
378 */
379void gfx_setInverted(bool on);
380
381/**
382 * @brief Sets the panel's own refresh rate (ST7735 FRMCTR1, 0xB1).
383 *
384 * Lower values scan the glass faster, which cuts the latency between a
385 * GRAM write and the pixel actually changing. The panel's rate is
386 * 850 kHz / ((RTNA*2 + 40) * (lines + FPA + BPA)). Defaults to the fast
387 * setting 0x05, 0x3A, 0x3A (Adafruit's is a lazy ~60 Hz 0x01, 0x2C,
388 * 0x2D). Waits for any flush in flight first.
389 * @param rtna RTNA, the line period.
390 * @param fpa Front porch, in lines.
391 * @param bpa Back porch, in lines.
392 */
393void gfx_setPanelFrameRate(uint8_t rtna, uint8_t fpa, uint8_t bpa);
394
395/** @} */
396
397/**
398 * @defgroup chgfx_palette Palette
399 * @ingroup lib_chgfx
400 * @brief The 16 colours the framebuffer's indices stand for, and a fade
401 * applied on top of them.
402 *
403 * Palette changes are STAGED: they take effect when the next flush
404 * starts, never part-way through one in flight, so these are safe to
405 * call at any time - including between gfx_flushAsync() and gfx_wait().
406 * Every frame is re-sent through the palette, so animating it (cycling a
407 * slot, pulsing a highlight, a fade) costs a 256-entry table rebuild per
408 * frame and no drawing at all.
409 * @{
410 */
411
412/**
413 * @brief Sets the first `count` palette entries.
414 * @param rgb565 The colours, in RGB565 (see gfx_rgb()). Passing gfx_pal
415 * itself just re-stages the palette.
416 * @param count How many entries to set, from index 0; at most 16 are used.
417 */
418void gfx_setPalette(const uint16_t *rgb565, uint8_t count);
419/**
420 * @brief Sets one palette entry.
421 * @param index Palette index, 0..15 (only the low 4 bits are used).
422 * @param rgb565 The colour, in RGB565.
423 */
424void gfx_setPaletteEntry(uint8_t index, uint16_t rgb565);
425
426/**
427 * @brief Fades every colour toward one colour (black by default).
428 *
429 * Applied while the expansion table is built, so gfx_pal[] keeps the
430 * true colours and gfx_nearest() still matches against them. Staged like
431 * the palette.
432 * @param amount 0 = the palette as set, 255 = solid `rgb565`.
433 * @param rgb565 The colour faded toward, in RGB565 (default black).
434 */
435void gfx_setFade(uint8_t amount, uint16_t rgb565 = 0x0000);
436/**
437 * @brief The current fade amount.
438 * @return 0 (no fade) to 255 (every colour is the fade colour).
439 */
440uint8_t gfx_fade(void);
441
442/**
443 * @brief The colour a palette index actually reaches the panel as, fade
444 * included.
445 * @param index Palette index, 0..15.
446 * @return The colour in RGB565.
447 */
448uint16_t gfx_paletteOut(uint8_t index);
449/**
450 * @brief Packs an 8-bit-per-channel colour into RGB565.
451 * @param r Red, 0..255 (the top 5 bits are kept).
452 * @param g Green, 0..255 (the top 6 bits are kept).
453 * @param b Blue, 0..255 (the top 5 bits are kept).
454 * @return The colour in RGB565, for gfx_setPalette() and the like.
455 */
456static inline uint16_t gfx_rgb(uint8_t r, uint8_t g, uint8_t b) {
457 return (uint16_t)(((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
458}
459
460/** @} */
461
462/* ------------------------------------------------------------------ */
463/* Presenting the framebuffer */
464/* ------------------------------------------------------------------ */
465/**
466 * @defgroup chgfx_present Presenting the framebuffer
467 * @ingroup lib_chgfx
468 * @brief Sending the framebuffer to the panel: whole or a rectangle,
469 * blocking or by DMA in the background, and waiting for it.
470 *
471 * A flush converts the 4 bpp framebuffer through the palette into the
472 * panel's format a chunk at a time and DMAs it out. The framebuffer is
473 * free to draw into again after gfx_wait() (or, row by row, after
474 * gfx_waitRow()). Every flush first waits for the one before it.
475 *
476 * **What a flush costs the CPU.** The wire time is fixed (11.1 ms a full
477 * frame at 16 bpp, 8.4 ms at 12 bpp) and an async flush hands it to the
478 * DMA. The pixel conversion still runs on the CPU, in the DMA interrupt,
479 * one chunk at a time, and the DMA shares the bus: measured on the board,
480 * an async full frame costs the main loop 2.5-3.2 ms of CPU (by -O2/-Os
481 * and 12/16 bpp). At 60 fps that is a sixth of the CPU, taken from
482 * whatever the main loop is doing - an AI search, for example. A partial
483 * flush costs in proportion to its area. (Before 1.3, at the board's
484 * default -Os, the converters were silently compiled into flash and the
485 * same flush cost 5.1 ms.) `-DCHGFX_ISR_IN_SRAM` trims it by 4-9% for
486 * ~330 bytes of SRAM.
487 *
488 * The cheapest frame is the one you do not draw: if nothing on screen
489 * changed, flush the buffer you already have. A palette animation still
490 * moves (the palette is applied during the flush), and the frame costs a
491 * flush and no drawing.
492 *
493 * **Flush progress - "racing the beam".** The flush converts the
494 * framebuffer top to bottom, and a row it has converted is never read
495 * again, so it is free to draw into while the rest of the frame is still
496 * going out. gfx_flushRow() is the first row the flush in flight may
497 * still read; gfx_waitRow() waits for a band to be free. Useful when the
498 * next frame is drawn top to bottom: wait for the top band, draw it, wait
499 * for the next. A clip rectangle keeps the drawing honest:
500 *
501 * @code
502 * gfx_waitRow(64); gfx_setClip(0, 0, 128, 64); drawTopHalf();
503 * gfx_wait(); gfx_setClip(0, 64, 128, 64); drawBottomHalf();
504 * gfx_resetClip(); gfx_flushAsync();
505 * @endcode
506 *
507 * **Partial updates.** The wire is the bottleneck, so sending a quarter
508 * of the screen costs a quarter of the time - gfx_flushRect() is the
509 * single biggest lever left once DMA is in place.
510 * @{
511 */
512
513/**
514 * @brief Sends the whole framebuffer to the panel and returns when it
515 * has gone out.
516 *
517 * About 11.1 ms at 16 bpp, 8.4 ms at 12 bpp, at 24 MHz.
518 * @see gfx_flushAsync(), gfx_flushRect()
519 */
520void gfx_flush(void); /* convert + DMA the whole frame, blocking */
521/**
522 * @brief Starts sending the whole framebuffer and returns at once; the
523 * DMA interrupt does the rest.
524 *
525 * Do not draw into the framebuffer until gfx_wait() (or gfx_waitRow())
526 * says the rows are free. The conversion costs the main loop 2.5-3.2 ms
527 * of CPU a full frame (see above).
528 */
529void gfx_flushAsync(void); /* same, but returns after the first chunk */
530/**
531 * @brief Whether an async flush is still in flight.
532 * @return true until the last byte of the flush has gone out.
533 */
534bool gfx_busy(void);
535/**
536 * @brief Waits until the flush in flight, if any, has finished.
537 *
538 * After it the framebuffer and gfx_chunkScratch() are free. Returns at
539 * once when nothing is being sent.
540 */
541void gfx_wait(void);
542
543/**
544 * @brief The first framebuffer row the flush in flight may still read.
545 * @return A row number; rows above it are free to draw into. GFX_H when
546 * no flush is in flight or the last chunk has been converted.
547 */
548int gfx_flushRow(void);
549/**
550 * @brief Waits until rows 0..y-1 are free to draw into.
551 * @param y One past the last row needed. gfx_waitRow(GFX_H) is gfx_wait()
552 * as far as drawing goes.
553 */
554void gfx_waitRow(int y);
555
556/** @} */
557
558/* ------------------------------------------------------------------ */
559/* Direct streaming - bypass the framebuffer entirely */
560/* ------------------------------------------------------------------ */
561/**
562 * @defgroup chgfx_stream Direct streaming
563 * @ingroup lib_chgfx
564 * @brief Full-colour procedural frames computed straight into the DMA's
565 * buffers, with no framebuffer and no palette.
566 *
567 * The 4 bpp framebuffer exists because 128*128 RGB565 will not fit in
568 * 20 KB. But a procedural effect - plasma, tunnel, rotozoomer, fire -
569 * does not need a framebuffer at all: it can compute pixels straight
570 * into the buffer the DMA is about to send. That gets you the panel's
571 * FULL colour depth, 65536 or 262144 colours, with no framebuffer and
572 * no palette.
573 *
574 * The callback (a gfx_streamFn) is called once per chunk while the
575 * previous chunk is still on the wire, so the transfer never stalls as
576 * long as you stay inside budget.
577 *
578 * **The budget, and it is the whole game:** 32 CPU cycles per pixel at
579 * 16 bpp, 48 at 18 bpp. Stay under it and you render at full wire speed.
580 * Go over and the frame rate degrades in proportion - nothing breaks, it
581 * just slows. Put your inner loop in SRAM; flash costs 3 wait states here
582 * and measured 2.2x slower on exactly this kind of loop.
583 *
584 * @code
585 * void plasma(uint8_t *dst, int y0, int rows, void *user) {
586 * for (int r = 0; r < rows; r++)
587 * for (int x = 0; x < GFX_W; x++)
588 * dst = gfx_px565(dst, someColour(x, y0 + r));
589 * }
590 * gfx_stream(plasma, nullptr);
591 * @endcode
592 * @{
593 */
594
595/**
596 * @brief A direct-streaming callback: fills `rows` rows starting at row
597 * `y0` into `dst`, in the panel's native format.
598 *
599 * `dst` takes `rows * GFX_W * gfx_bytesPerPixel()` bytes: GFX_16BPP is
600 * 2 bytes/px, RGB565 little-endian (write uint16_t, or gfx_px565());
601 * GFX_18BPP is 3 bytes/px, each component in bits 7:2 (gfx_px666()).
602 * `user` is the pointer given to gfx_stream().
603 */
604typedef void (*gfx_streamFn)(uint8_t *dst, int y0, int rows, void *user);
605/**
606 * @brief Draws one full-screen frame by calling `fn` for every chunk of
607 * rows and sending the result straight to the panel.
608 *
609 * Blocking: waits for any flush in flight, then returns when the frame
610 * has gone out. Requires GFX_16BPP or GFX_18BPP. In 12 bpp the packing
611 * is 1.5 bytes per pixel with pixels straddling bytes, which is no use to
612 * a per-pixel generator, so gfx_stream() switches to 16 bpp for you (and
613 * the mode stays 16 bpp afterwards).
614 * @param fn The callback that fills each chunk.
615 * @param user Passed to every call of `fn` (may be nullptr).
616 */
617void gfx_stream(gfx_streamFn fn, void *user);
618
619/**
620 * @brief Bytes per pixel a stream callback writes in the current mode.
621 * @return 2, or 3 for GFX_18BPP.
622 */
623uint8_t gfx_bytesPerPixel(void);
624
625/* Pack helpers for stream callbacks. */
626/**
627 * @brief Writes one 16 bpp pixel for a stream callback.
628 * @param p Where to write it.
629 * @param rgb565 The colour, in RGB565.
630 * @return `p` advanced past the pixel (2 bytes).
631 */
632static inline uint8_t *gfx_px565(uint8_t *p, uint16_t rgb565) {
633 *(uint16_t *)p = rgb565;
634 return p + 2;
635}
636/**
637 * @brief Writes one 18 bpp pixel for a stream callback.
638 * @param p Where to write it.
639 * @param r6 Red, 0..63.
640 * @param g6 Green, 0..63.
641 * @param b6 Blue, 0..63.
642 * @return `p` advanced past the pixel (3 bytes).
643 */
644static inline uint8_t *gfx_px666(uint8_t *p, uint8_t r6, uint8_t g6, uint8_t b6) {
645 p[0] = (uint8_t)(r6 << 2);
646 p[1] = (uint8_t)(g6 << 2);
647 p[2] = (uint8_t)(b6 << 2);
648 return p + 3;
649}
650
651/** @} */
652
653/** @addtogroup chgfx_present
654 * @{
655 */
656
657/* Partial update. The wire is the bottleneck, so sending a quarter of
658 * the screen costs a quarter of the time - this is the single biggest
659 * lever left once DMA is in place. Declare what your frame actually
660 * changed and a mostly-static scene runs several times faster. */
661/**
662 * @brief Sends one rectangle of the framebuffer to the panel and returns
663 * when it has gone out.
664 *
665 * Declare what your frame actually changed and a mostly-static scene
666 * runs several times faster: 64x64 goes out in 2.8 ms, 32x32 in 0.75 ms.
667 * The rectangle is clipped to the screen (an empty one sends nothing).
668 * x/w are rounded OUTWARD to a multiple of 2 (16 bpp) or 8 (12 bpp),
669 * because the 4 bpp source has to start and end on a byte. Rounding out
670 * is always safe - you just send a few more pixels than strictly needed.
671 * @param x Left edge, in pixels.
672 * @param y Top edge, in pixels.
673 * @param w Width, in pixels.
674 * @param h Height, in pixels.
675 * @see gfx_flushRectAsync()
676 */
677void gfx_flushRect(int x, int y, int w, int h);
678/**
679 * @brief Starts sending one rectangle of the framebuffer and returns at
680 * once, as gfx_flushAsync() does for the whole frame.
681 *
682 * Clipped and rounded as gfx_flushRect(). gfx_wait() before drawing
683 * again.
684 * @param x Left edge, in pixels.
685 * @param y Top edge, in pixels.
686 * @param w Width, in pixels.
687 * @param h Height, in pixels.
688 */
689void gfx_flushRectAsync(int x, int y, int w, int h);
690
691/** @} */
692
693/* ------------------------------------------------------------------ */
694/* Framebuffer drawing (all clipped, all operate on the 4 bpp buffer) */
695/* ------------------------------------------------------------------ */
696/**
697 * @defgroup chgfx_draw Drawing
698 * @ingroup lib_chgfx
699 * @brief The clip rectangle, pixels, lines, rectangles, circles and
700 * sprite blits, drawn into the 4 bpp framebuffer.
701 *
702 * Every colour is a palette index, 0..15 (only the low 4 bits are
703 * used). Every call is clipped to the clip rectangle, and nothing reaches
704 * the panel until a flush. Draw only after gfx_wait() (or gfx_waitRow()
705 * for the rows you touch).
706 *
707 * **The clip rectangle.** Every call that paints pixels - fills, lines,
708 * shapes, text, sprites, gfx_clear() - stays inside it. It is
709 * intersected with the screen; an empty one (w or h <= 0) stops all
710 * drawing. Defaults to the whole screen. gfx_getPixel(), gfx_scroll() and
711 * the flush ignore it. Changing it costs nothing, so set it around a
712 * panel or a HUD and put it back:
713 *
714 * @code
715 * gfx_setClip(0, 10, 128, 118); drawBoard(); gfx_resetClip();
716 * @endcode
717 * @{
718 */
719
720/**
721 * @brief Sets the clip rectangle every drawing call stays inside.
722 * @param x Left edge, in pixels.
723 * @param y Top edge, in pixels.
724 * @param w Width; 0 or less stops all drawing.
725 * @param h Height; 0 or less stops all drawing.
726 */
727void gfx_setClip(int x, int y, int w, int h);
728/** @brief Puts the clip rectangle back to the whole screen. */
729void gfx_resetClip(void);
730/**
731 * @brief Reads the clip rectangle, as intersected with the screen.
732 * @param[out] x Left edge (may be nullptr).
733 * @param[out] y Top edge (may be nullptr).
734 * @param[out] w Width (may be nullptr).
735 * @param[out] h Height (may be nullptr).
736 */
737void gfx_getClip(int *x, int *y, int *w, int *h);
738
739/**
740 * @brief Fills the clip rectangle (normally the whole screen) with one
741 * colour.
742 *
743 * The whole screen is one word store per 8 pixels, from SRAM.
744 * @param c Palette index.
745 */
746void gfx_clear(uint8_t c);
747/**
748 * @brief Sets one pixel.
749 * @param x Column.
750 * @param y Row.
751 * @param c Palette index.
752 */
753void gfx_pixel(int x, int y, uint8_t c);
754/**
755 * @brief Reads one pixel of the framebuffer (the clip is ignored).
756 * @param x Column.
757 * @param y Row.
758 * @return The palette index there, or 0 off the screen.
759 */
760uint8_t gfx_getPixel(int x, int y);
761/**
762 * @brief Draws a horizontal line from (x, y), `w` pixels to the right.
763 * @param x Left end.
764 * @param y Row.
765 * @param w Length in pixels; 0 or less draws nothing.
766 * @param c Palette index.
767 */
768void gfx_hline(int x, int y, int w, uint8_t c);
769/**
770 * @brief Draws a vertical line from (x, y), `h` pixels down.
771 * @param x Column.
772 * @param y Top end.
773 * @param h Length in pixels; 0 or less draws nothing.
774 * @param c Palette index.
775 */
776void gfx_vline(int x, int y, int h, uint8_t c);
777/**
778 * @brief Fills a rectangle.
779 * @param x Left edge.
780 * @param y Top edge.
781 * @param w Width; 0 or less draws nothing.
782 * @param h Height; 0 or less draws nothing.
783 * @param c Palette index.
784 */
785void gfx_fillRect(int x, int y, int w, int h, uint8_t c);
786/**
787 * @brief Draws a rectangle's 1-pixel outline.
788 * @param x Left edge.
789 * @param y Top edge.
790 * @param w Width; 0 or less draws nothing.
791 * @param h Height; 0 or less draws nothing.
792 * @param c Palette index.
793 */
794void gfx_rect(int x, int y, int w, int h, uint8_t c);
795/**
796 * @brief Draws a line between two points, both ends included.
797 * @param x0 Start column.
798 * @param y0 Start row.
799 * @param x1 End column.
800 * @param y1 End row.
801 * @param c Palette index.
802 */
803void gfx_line(int x0, int y0, int x1, int y1, uint8_t c);
804/**
805 * @brief Draws a circle's 1-pixel outline, 2*r+1 pixels across.
806 * @param cx Centre column.
807 * @param cy Centre row.
808 * @param r Radius in pixels.
809 * @param c Palette index.
810 */
811void gfx_circle(int cx, int cy, int r, uint8_t c);
812/**
813 * @brief Draws a filled circle, 2*r+1 pixels across.
814 * @param cx Centre column.
815 * @param cy Centre row.
816 * @param r Radius in pixels.
817 * @param c Palette index.
818 */
819void gfx_fillCircle(int cx, int cy, int r, uint8_t c);
820
821/**
822 * @brief Copies a 4 bpp bitmap into the framebuffer, optionally with one
823 * colour transparent.
824 *
825 * Source rows are packed the same way as the framebuffer (2 px/byte,
826 * even x low nibble), each row padded to a whole byte. The opaque even-x
827 * case runs at memcpy speed. For art with many runs of one colour, the
828 * compact @ref chgfx_sprites "span sprites" are smaller.
829 * @param spr The bitmap, `(w + 1) / 2` bytes a row.
830 * @param x Left edge on screen.
831 * @param y Top edge on screen.
832 * @param w Width in pixels.
833 * @param h Height in pixels.
834 * @param transparent Colour index skipped, or -1 for an opaque copy.
835 */
836void gfx_blit(const uint8_t *spr, int x, int y, int w, int h, int transparent);
837
838/** @} */
839
840/* ------------------------------------------------------------------ */
841/* Shapes */
842/* ------------------------------------------------------------------ */
843/**
844 * @defgroup chgfx_shapes Shapes
845 * @ingroup lib_chgfx
846 * @brief Rounded rectangles, ellipses, dithered fills and in-place
847 * recolouring.
848 *
849 * Clipped like everything in @ref chgfx_draw. Nothing here costs a
850 * sketch that does not call it: the linker drops what is unused.
851 * @{
852 */
853
854/**
855 * @brief Draws a rounded rectangle's 1-pixel outline.
856 *
857 * Corners are pixel-art arcs, not chamfers; r is clamped to half the
858 * shorter side, and r = 0 is a plain rectangle.
859 * @param x Left edge.
860 * @param y Top edge.
861 * @param w Width; 0 or less draws nothing.
862 * @param h Height; 0 or less draws nothing.
863 * @param r Corner radius in pixels.
864 * @param c Palette index.
865 */
866void gfx_roundRect(int x, int y, int w, int h, int r, uint8_t c);
867/**
868 * @brief Fills a rounded rectangle (corners as gfx_roundRect()).
869 * @param x Left edge.
870 * @param y Top edge.
871 * @param w Width; 0 or less draws nothing.
872 * @param h Height; 0 or less draws nothing.
873 * @param r Corner radius in pixels.
874 * @param c Palette index.
875 */
876void gfx_fillRoundRect(int x, int y, int w, int h, int r, uint8_t c);
877
878/**
879 * @brief Draws an axis-aligned ellipse's 1-pixel outline, 2*rx+1 by
880 * 2*ry+1 pixels, centred on (cx, cy).
881 *
882 * Integer only, no square roots.
883 * @param cx Centre column.
884 * @param cy Centre row.
885 * @param rx Horizontal radius in pixels.
886 * @param ry Vertical radius in pixels.
887 * @param c Palette index.
888 */
889void gfx_ellipse(int cx, int cy, int rx, int ry, uint8_t c);
890/**
891 * @brief Draws a filled axis-aligned ellipse, 2*rx+1 by 2*ry+1 pixels,
892 * centred on (cx, cy).
893 * @param cx Centre column.
894 * @param cy Centre row.
895 * @param rx Horizontal radius in pixels.
896 * @param ry Vertical radius in pixels.
897 * @param c Palette index.
898 */
899void gfx_fillEllipse(int cx, int cy, int rx, int ry, uint8_t c);
900
901/**
902 * @brief Paints a 50% checkerboard of one colour over a rectangle,
903 * leaving the pixels in between alone.
904 *
905 * Darkened backdrops behind menus, felt, shadows.
906 * @param x Left edge.
907 * @param y Top edge.
908 * @param w Width.
909 * @param h Height.
910 * @param c Palette index.
911 * @param phase 0 paints pixels where x + y is even, 1 where it is odd.
912 */
913void gfx_dither(int x, int y, int w, int h, uint8_t c, uint8_t phase);
914
915/**
916 * @brief Recolours a rectangle in place through a 16-entry table:
917 * pixel = remap[pixel].
918 *
919 * Dimming, tinting, a hit flash on what is already drawn. A rectangle of
920 * 512 pixels or more builds a 256-entry table first and then costs one
921 * lookup per two pixels.
922 * @param x Left edge.
923 * @param y Top edge.
924 * @param w Width.
925 * @param h Height.
926 * @param remap 16 palette indices: the new colour for each old one.
927 */
928void gfx_remapRect(int x, int y, int w, int h, const uint8_t *remap);
929
930/** @} */
931
932/* ------------------------------------------------------------------ */
933/* Span sprites (sprite4) */
934/* ------------------------------------------------------------------ */
935/**
936 * @defgroup chgfx_sprites Span sprites
937 * @ingroup lib_chgfx
938 * @brief The compact run-length sprite format (sprite4): plain, scaled,
939 * recoloured and rotated.
940 *
941 * The compact sprite format two CHGame titles arrived at independently.
942 * Each row is a list of runs of one colour, so the art is small and a
943 * run is a fill, not a pixel loop:
944 *
945 * w, h, then per row: n, then n bytes of (len - 1) << 4 | colour
946 *
947 * Runs are 1..16 px. Colour 15 is transparent (a skip), and trailing
948 * transparency is left out. `extras/sprite4.py` packs a PNG.
949 *
950 * Every pixel is drawn through remap[colour] (nullptr = as is), so ONE
951 * image serves many looks: a team colour, a red damage flash, a white
952 * hit flash, a solid silhouette for an outline. With 16 colours,
953 * palette swapping is the natural way to get variety.
954 *
955 * @code
956 * #include "slime.h" // python extras/sprite4.py slime.png SLIME > slime.h
957 * gfx_sprite4(SLIME, 40, 60); // as drawn
958 * gfx_sprite4(SLIME, 40, 60, redFlash); // through a 16-entry remap
959 * gfx_sprite4(SLIME, 40, 60, nullptr, 512); // double size
960 * @endcode
961 * @{
962 */
963
964/**
965 * @brief Draws a span sprite, optionally recoloured and scaled.
966 *
967 * Scaling is nearest neighbour, about the top-left corner. 1:1 has its
968 * own fast path, so leave it at 256 unless you mean it.
969 * @param spr The sprite data (w, h, then the rows of runs).
970 * @param x Left edge on screen.
971 * @param y Top edge on screen.
972 * @param remap 16 palette indices to draw each colour as, or nullptr
973 * (the default) for the colours as they are.
974 * @param scale Q8 scale: 256 = 1:1 (the default), 512 = double, 128 =
975 * half. 0 or less draws nothing.
976 */
977void gfx_sprite4(const uint8_t *spr, int x, int y,
978 const uint8_t *remap = nullptr, int scale = 256);
979/**
980 * @brief A span sprite's width.
981 * @param spr The sprite data.
982 * @return Its width in pixels, at 1:1.
983 */
984static inline int gfx_sprite4W(const uint8_t *spr) { return spr[0]; }
985/**
986 * @brief A span sprite's height.
987 * @param spr The sprite data.
988 * @return Its height in pixels, at 1:1.
989 */
990static inline int gfx_sprite4H(const uint8_t *spr) { return spr[1]; }
991
992/**
993 * @brief Draws a span sprite rotated and scaled about a pivot.
994 *
995 * The sprite's pixel (ax, ay) lands on screen at (px, py), turned by
996 * `angle` and scaled by `scale`. The art is decoded into
997 * gfx_chunkScratch(), so it must fit in 1 KB at 4 bpp (32x64, 45x45; a
998 * larger sprite draws nothing) and this call waits for any flush in
999 * flight first. Per pixel, so costlier than gfx_sprite4().
1000 * @param spr The sprite data.
1001 * @param ax Pivot column in the sprite.
1002 * @param ay Pivot row in the sprite.
1003 * @param px Screen column the pivot lands on.
1004 * @param py Screen row the pivot lands on.
1005 * @param angle Rotation, 256 = a full turn, clockwise on screen.
1006 * @param scale Q8 scale, 256 = 1:1 (the default); below 8 counts as 8,
1007 * 0 or less draws nothing.
1008 * @param remap 16 palette indices to draw each colour as, or nullptr.
1009 */
1010void gfx_sprite4Rot(const uint8_t *spr, int ax, int ay, int px, int py,
1011 uint8_t angle, int scale = 256, const uint8_t *remap = nullptr);
1012
1013/** @} */
1014
1015/* ------------------------------------------------------------------ */
1016/* Row operations */
1017/* ------------------------------------------------------------------ */
1018/**
1019 * @defgroup chgfx_rows Row operations
1020 * @ingroup lib_chgfx
1021 * @brief Scrolling and stamping whole framebuffer rows at word speed.
1022 *
1023 * Word copies in SRAM. newlib-nano's memmove/memcpy are byte loops in
1024 * flash here: a screen shake built on memmove cost ~10 ms a frame.
1025 * @{
1026 */
1027
1028/**
1029 * @brief Moves a band of rows by (dx, dy) pixels inside the band.
1030 *
1031 * Moves the band of rows y..y+h-1 by dx pixels right and dy rows down
1032 * (negative = left/up). Odd dx is fine (nibble shifts). It works on whole
1033 * rows and ignores the clip rectangle - it is a post-process: shake,
1034 * scrolling backgrounds.
1035 * @param y First row of the band.
1036 * @param h Rows in the band (clipped to the screen).
1037 * @param dx Pixels to move right; negative moves left.
1038 * @param dy Rows to move down; negative moves up.
1039 * @param fill Palette index for the pixels uncovered by the move, or -1
1040 * (the default) to leave them as they were.
1041 */
1042void gfx_scroll(int y, int h, int dx, int dy, int fill = -1);
1043
1044/**
1045 * @brief Copies pixels [x0, x1) of a full-width row buffer into
1046 * framebuffer row y, clipped.
1047 *
1048 * Build a pattern row once, stamp it into many rows at word speed: tiled
1049 * floors, checkerboards, gradients.
1050 * @param y Framebuffer row.
1051 * @param src A row of GFX_FB_STRIDE bytes, packed like the framebuffer.
1052 * @param x0 First pixel copied.
1053 * @param x1 One past the last pixel copied.
1054 */
1055void gfx_copyRow(int y, const uint8_t *src, int x0, int x1);
1056
1057/** @} */
1058
1059/* ------------------------------------------------------------------ */
1060/* Text */
1061/* ------------------------------------------------------------------ */
1062/**
1063 * @defgroup chgfx_text Text
1064 * @ingroup lib_chgfx
1065 * @brief Text in the built-in 5x7 font or any GFXfont: plain, scaled,
1066 * measured, and outlined/shadowed banners.
1067 *
1068 * The default font is the built-in 5x7, ASCII 32..126, 475 bytes, no
1069 * setup. gfx_setFont() swaps in a proportional GFXfont;
1070 * gfx_setFont(nullptr) puts the built-in one back.
1071 *
1072 * @code
1073 * #include <fonts/CHGfx_Sans12.h>
1074 * Gfx.setFont(&CHGfx_Sans12);
1075 * Gfx.print(4, 20, "Hello", WHITE);
1076 * @endcode
1077 *
1078 * GFXfont is byte-for-byte Adafruit's format (see CHGfx_gfxfont.h), so
1079 * anything from Adafruit_GFX's Fonts/ directory, or produced by either
1080 * font converter, works here as-is:
1081 *
1082 * @code
1083 * #include <Fonts/FreeSans9pt7b.h>
1084 * Gfx.setFont(&FreeSans9pt7b);
1085 * @endcode
1086 *
1087 * **The origin changes with the font.** Built-in font: y is the TOP of
1088 * the glyph box. Custom font: y is the BASELINE, with ascenders above it
1089 * and descenders below. Adafruit_GFX behaves exactly the same way, which
1090 * is why it is worth living with. gfx_fontBaseline() converts:
1091 *
1092 * @code
1093 * gfx_text(x, y + gfx_fontBaseline(), s, c); // y = top, either font
1094 * @endcode
1095 *
1096 * A newline starts a new line at the original x; a carriage return is
1097 * ignored. Characters outside the font's range are drawn as '?', or
1098 * dropped if the font has no '?'.
1099 *
1100 * Bundled fonts live in src/fonts/ - see @ref chgfx_fonts for the list,
1101 * their flash cost, and how to convert your own with
1102 * `extras/fontconvert.py`.
1103 * @{
1104 */
1105
1106/**
1107 * @brief Selects the font every text call uses from now on.
1108 *
1109 * Scans the glyphs once to find the font's ascent (for
1110 * gfx_fontBaseline()).
1111 * @param f A GFXfont, or nullptr for the built-in 5x7.
1112 */
1113void gfx_setFont(const GFXfont *f);
1114/**
1115 * @brief The current font.
1116 * @return The GFXfont last given to gfx_setFont(), or nullptr for the
1117 * built-in 5x7.
1118 */
1119const GFXfont *gfx_font(void);
1120
1121/**
1122 * @brief Baseline-to-baseline line spacing of the current font, at scale 1.
1123 * @return Pixels: the font's yAdvance, or 8 for the built-in font.
1124 * Multiply by your scale.
1125 */
1127/**
1128 * @brief The current font's ascent: how far its tallest ink reaches above
1129 * the baseline, at scale 1.
1130 * @return Pixels; 0 for the built-in font, since that one is already
1131 * top-anchored. Add it to a top y to get the y to draw at.
1132 */
1134
1135/**
1136 * @brief Draws one character.
1137 * @param x Left edge (pen position).
1138 * @param y Top of the glyph box (built-in font) or baseline (GFXfont).
1139 * @param ch The character.
1140 * @param c Palette index.
1141 */
1142void gfx_char(int x, int y, char ch, uint8_t c);
1143/**
1144 * @brief Draws one character, scaled up by a whole number.
1145 * @param x Left edge (pen position).
1146 * @param y Top of the glyph box (built-in font) or baseline (GFXfont).
1147 * @param ch The character.
1148 * @param c Palette index.
1149 * @param scale Integer scale, 1 or more (0 counts as 1).
1150 */
1151void gfx_charScaled(int x, int y, char ch, uint8_t c, uint8_t scale);
1152/**
1153 * @brief Draws a string in the current font.
1154 *
1155 * The built-in font advances 6 pixels a character.
1156 * @param x Left edge of the first character.
1157 * @param y Top of the glyph box (built-in font) or baseline (GFXfont).
1158 * @param s Null-terminated string; a newline starts a new line at x.
1159 * @param c Palette index.
1160 */
1161void gfx_text(int x, int y, const char *s, uint8_t c);
1162/**
1163 * @brief Draws a string in the current font, scaled up by a whole number.
1164 * @param x Left edge of the first character.
1165 * @param y Top of the glyph box (built-in font) or baseline (GFXfont).
1166 * @param s Null-terminated string; a newline starts a new line at x.
1167 * @param c Palette index.
1168 * @param scale Integer scale, 1 or more (0 counts as 1).
1169 */
1170void gfx_textScaled(int x, int y, const char *s, uint8_t c, uint8_t scale);
1171
1172/**
1173 * @brief Advance width of a string in the current font - the number to
1174 * use for centring and right-alignment.
1175 * @param s Null-terminated string.
1176 * @return Width in pixels; for a multi-line string, the widest line.
1177 */
1178int gfx_textWidth(const char *s);
1179/**
1180 * @brief Advance width of a string in the current font at a scale.
1181 * @param s Null-terminated string.
1182 * @param scale Integer scale, 1 or more (0 counts as 1).
1183 * @return Width in pixels; for a multi-line string, the widest line.
1184 */
1185int gfx_textWidthScaled(const char *s, uint8_t scale);
1186
1187/**
1188 * @brief Bounding box of a string drawn at (x, y).
1189 *
1190 * Same units and origin convention as gfx_text() - use it to frame or
1191 * erase text without guessing. With a custom font this is the tight ink
1192 * box; with the built-in font it is the 5x7 cell box, so a leading space
1193 * still counts. A string with no ink gives a 0x0 box at (x, y).
1194 * @param s Null-terminated string.
1195 * @param x Where the string would be drawn.
1196 * @param y Where the string would be drawn (top or baseline, as
1197 * gfx_text()).
1198 * @param scale Integer scale, 1 or more (0 counts as 1).
1199 * @param[out] bx Left edge of the box (may be nullptr).
1200 * @param[out] by Top edge of the box (may be nullptr).
1201 * @param[out] bw Width of the box (may be nullptr).
1202 * @param[out] bh Height of the box (may be nullptr).
1203 */
1204void gfx_textBounds(const char *s, int x, int y, uint8_t scale,
1205 int *bx, int *by, int *bw, int *bh);
1206
1207/**
1208 * @brief Draws outlined, shadowed or gradient-filled text - titles and
1209 * banners.
1210 *
1211 * Same font, origin and scale rules as gfx_textScaled(). Drawing the
1212 * glyphs nine times over would cost ~9x a plain print. This renders the
1213 * text once into a 1 bpp mask in gfx_chunkScratch(), grows the outline
1214 * out of it with word-wide ORs and paints each row as spans, so a 3x
1215 * outlined, shadowed nine-letter banner costs about 2.9 ms. The mask -
1216 * the text's ink box plus a 1 px margin - must fit in 1 KB: text up to
1217 * 126x62 px, or 254x30. Waits for any flush in flight first.
1218 *
1219 * @param x Left edge, as gfx_text().
1220 * @param y Top (built-in font) or baseline (GFXfont), as gfx_text().
1221 * @param s Null-terminated string.
1222 * @param scale Integer scale, 1 or more.
1223 * @param fill Palette index of the letters.
1224 * @param outline Palette index of a 1 px ring around them (all 8
1225 * directions), or -1 (the default) for none.
1226 * @param shadow Palette index of the outlined shape again, 1 px
1227 * down-right, underneath, or -1 (the default) for none.
1228 * @param ramp Optional: a fill colour per pixel row of the text, top
1229 * to bottom (as many entries as the text is tall),
1230 * replacing `fill`; nullptr for none.
1231 * @param dy Optional: a vertical offset per character, for wavy
1232 * text; nullptr for none.
1233 * @return false, having drawn nothing, if the text is too big for the
1234 * mask; true otherwise (also when nothing was inside the clip).
1235 */
1236bool gfx_textFx(int x, int y, const char *s, uint8_t scale, uint8_t fill,
1237 int outline = -1, int shadow = -1,
1238 const uint8_t *ramp = nullptr, const int8_t *dy = nullptr);
1239
1240/** @} */
1241
1242/* ------------------------------------------------------------------ */
1243/* Direct-to-panel paths (bypass the framebuffer entirely) */
1244/* ------------------------------------------------------------------ */
1245/**
1246 * @defgroup chgfx_direct Direct to the panel
1247 * @ingroup lib_chgfx
1248 * @brief Talking to the ST7735 without the framebuffer: chip select,
1249 * commands, address windows, DMA fills and raw blits.
1250 *
1251 * These write to the panel at once, so call them only when no flush is
1252 * in flight (after gfx_wait()); the SD card shares the bus too. Raw
1253 * pixel data must already be in the panel's current format.
1254 *
1255 * @code
1256 * gfx_wait();
1257 * gfx_select();
1258 * gfx_setWindow(0, 0, 32, 32);
1259 * gfx_directBlit(pixels565, 32 * 32 * 2, true);
1260 * gfx_deselect();
1261 * @endcode
1262 * @{
1263 */
1264
1265/**
1266 * @brief Asserts the panel's chip select.
1267 *
1268 * Assert once, stream a whole frame, deassert - that is the entire
1269 * performance thesis of this driver in two functions. The panel latches
1270 * nothing while CS is high.
1271 */
1272void gfx_select(void);
1273/** @brief Waits for the last byte to leave SPI1, then releases the panel's chip select. */
1274void gfx_deselect(void);
1275
1276/**
1277 * @brief Sets the panel's address window and starts a memory write
1278 * (CASET, RASET, RAMWR).
1279 *
1280 * Pixel data sent after it fills the window left to right, top to
1281 * bottom. The panel offsets (gfx_setPanelOffsets()) are added; nothing
1282 * is clipped. Needs gfx_select() first.
1283 * @param x Left edge, in screen pixels.
1284 * @param y Top edge, in screen pixels.
1285 * @param w Width in pixels, 1 or more.
1286 * @param h Height in pixels, 1 or more.
1287 */
1288void gfx_setWindow(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
1289/**
1290 * @brief Sends one command byte (D/C low), then sets D/C back to data.
1291 * @param c ST7735 command.
1292 */
1293void gfx_cmd(uint8_t c);
1294/**
1295 * @brief Sends one data byte (D/C high).
1296 * @param d The byte.
1297 */
1298void gfx_data8(uint8_t d);
1299
1300/**
1301 * @brief Programs the ST7735 RGBSET (2Dh) colour-depth conversion LUT for
1302 * the current mode.
1303 *
1304 * Done automatically for 12 bpp because the datasheet says the table
1305 * powers up "Random"; call gfx_setWriteColorLut(false) before
1306 * gfx_setColorMode() if you would rather trust the factory contents.
1307 */
1309/**
1310 * @brief Chooses whether entering 12 bpp writes the colour LUT
1311 * (gfx_writeColorLut()).
1312 * @param on true (the default) to write it, false to trust the panel's
1313 * factory contents.
1314 */
1316
1317/**
1318 * @brief Fills a rectangle of the panel with one colour by DMA, bypassing
1319 * the framebuffer.
1320 *
1321 * DMA with memory-increment DISABLED: the DMA engine re-reads one
1322 * halfword N times. Zero RAM, zero CPU, full wire speed. Waits for any
1323 * flush in flight; handles chip select itself; not clipped.
1324 * @param x Left edge, in screen pixels.
1325 * @param y Top edge, in screen pixels.
1326 * @param w Width in pixels.
1327 * @param h Height in pixels.
1328 * @param rgb565 The colour, in RGB565.
1329 * @warning 16 bpp only - a 12 bpp solid colour has a 3-byte repeat that
1330 * does not fit in a single halfword.
1331 */
1332void gfx_directFillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t rgb565);
1333
1334/**
1335 * @brief Sends a caller-owned buffer, already in panel format, by DMA and
1336 * waits for it.
1337 *
1338 * Needs gfx_select() and gfx_setWindow() first.
1339 * @param data The pixel data.
1340 * @param bytes Its length in bytes (even when `halfword`).
1341 * @param halfword true to send 16-bit SPI frames (RGB565 as uint16_t,
1342 * 16 bpp), false for bytes (12 and 18 bpp).
1343 */
1344void gfx_directBlit(const void *data, uint32_t bytes, bool halfword);
1345
1346/**
1347 * @brief Sends bytes one at a time in a polled loop, for baseline
1348 * comparisons.
1349 * @param data The bytes.
1350 * @param bytes How many.
1351 */
1352void gfx_blockingWrite(const uint8_t *data, uint32_t bytes);
1353
1354/** @} */
1355
1356/* ------------------------------------------------------------------ */
1357/* Internals exposed for the benchmark */
1358/* ------------------------------------------------------------------ */
1359/**
1360 * @defgroup chgfx_internals Internals and scratch
1361 * @ingroup lib_chgfx
1362 * @brief The converters the Benchmark example measures, the flush's
1363 * chunk buffers as scratch memory, and the frame size.
1364 * @{
1365 */
1366
1367/**
1368 * @brief Converts framebuffer rows into the panel's format, with the
1369 * converter in SRAM.
1370 *
1371 * _ram lives in SRAM, _flash lives in flash. Benchmarking both is how
1372 * you measure the 3-wait-state penalty.
1373 * @param dst Where the panel-format bytes go.
1374 * @param row First framebuffer row.
1375 * @param rows How many rows.
1376 * @return Bytes written to `dst`.
1377 */
1378uint32_t gfx_convertRows_ram(uint8_t *dst, uint16_t row, uint16_t rows);
1379/**
1380 * @brief Converts framebuffer rows into the panel's format, with the
1381 * converter in flash (for comparison with gfx_convertRows_ram()).
1382 * @param dst Where the panel-format bytes go.
1383 * @param row First framebuffer row.
1384 * @param rows How many rows.
1385 * @return Bytes written to `dst`.
1386 */
1387uint32_t gfx_convertRows_flash(uint8_t *dst, uint16_t row, uint16_t rows);
1388/**
1389 * @brief Converts a run of framebuffer bytes into the panel's format (the
1390 * SRAM converter every flush uses).
1391 * @param dst Where the panel-format bytes go.
1392 * @param src 4 bpp source bytes, two pixels each.
1393 * @param srcBytes How many source bytes.
1394 * @return Bytes written to `dst`.
1395 */
1396uint32_t gfx_convertSpan_ram(uint8_t *dst, const uint8_t *src, uint32_t srcBytes);
1397
1398/**
1399 * @brief 1 KB of word-aligned scratch memory: the flush's chunk buffers.
1400 *
1401 * 2 * GFX_CHUNK_BYTES, idle from gfx_wait() until the next flush starts.
1402 * Handy for decoding, masks, building a flash page, an SD card block -
1403 * never across a flush. gfx_sprite4Rot() and gfx_textFx() use it, so it
1404 * does not survive them either.
1405 * @return The start of the scratch.
1406 */
1407uint8_t *gfx_chunkScratch(void);
1408
1409/**
1410 * @brief Bytes the panel receives for a full frame in the current mode.
1411 * @return 32768 (16 bpp), 24576 (12 bpp) or 49152 (18 bpp) at 128x128.
1412 */
1413uint32_t gfx_frameBytes(void);
1414
1415/** @} */
1416
1417/* ------------------------------------------------------------------ */
1418/* Palette helper */
1419/* ------------------------------------------------------------------ */
1420/**
1421 * @brief Nearest palette index for a full RGB565 colour.
1422 * @ingroup chgfx_palette
1423 *
1424 * Linear search over 16 entries, by weighted distance, against the
1425 * palette as set (not as faded) - fine at setup time to build named
1426 * constants, far too slow to call per pixel.
1427 * @param rgb565 The colour, in RGB565.
1428 * @return The palette index, 0..15, closest to it.
1429 */
1430uint8_t gfx_nearest(uint16_t rgb565);
1431
1432/* ------------------------------------------------------------------ */
1433/* Idiomatic Arduino wrapper */
1434/* ------------------------------------------------------------------ */
1435/**
1436 * @defgroup chgfx_class The Gfx object
1437 * @ingroup lib_chgfx
1438 * @brief The CHGfx class and its one instance, Gfx: the same API with
1439 * Arduino-style names.
1440 * @{
1441 */
1442
1443/**
1444 * @brief Arduino-style access to CHGfx: every method is a zero-cost
1445 * inline forwarder to a `gfx_*` function.
1446 *
1447 * There is exactly one panel, one SPI peripheral and one DMA channel, so
1448 * the driver state is inherently global - the class exists for the
1449 * familiar `Gfx.clear(0)` spelling, not to allow two instances. Use the
1450 * one instance, Gfx. Use whichever style you prefer; they are the same
1451 * code. Each method's full description is on the function it forwards to.
1452 *
1453 * @code
1454 * Gfx.begin(GFX_DIV2, GFX_12BPP);
1455 * Gfx.clear(0);
1456 * Gfx.print(4, 4, "Hello", 1);
1457 * Gfx.display();
1458 * @endcode
1459 */
1460class CHGfx {
1461public:
1462 /**
1463 * @brief Starts the panel.
1464 * @param spiDiv SPI clock divider (default GFX_DIV2, 24 MHz).
1465 * @param colorMode GFX_16BPP (the default), GFX_12BPP or GFX_18BPP.
1466 * @see gfx_begin()
1467 */
1468 void begin(uint8_t spiDiv = GFX_DIV2, uint8_t colorMode = GFX_16BPP) { gfx_begin(spiDiv, colorMode); }
1469
1470 /** @name Configuration */
1471 /** @{ */
1472 /** @brief Changes the SPI clock divider. @param d GFX_DIV2..GFX_DIV16. @see gfx_setSpiDiv() */
1473 void setSpiDiv(uint8_t d) { gfx_setSpiDiv(d); }
1474 /** @brief Switches the colour output mode. @param m GFX_16BPP, GFX_12BPP or GFX_18BPP. @see gfx_setColorMode() */
1475 void setColorMode(uint8_t m) { gfx_setColorMode(m); }
1476 /** @brief The current colour output mode. @return GFX_16BPP, GFX_12BPP or GFX_18BPP. @see gfx_colorMode() */
1477 uint8_t colorMode() const { return gfx_colorMode(); }
1478 /** @brief The current SPI clock. @return Hz. @see gfx_spiHz() */
1479 uint32_t spiHz() const { return gfx_spiHz(); }
1480 /**
1481 * @brief Sets the panel's MADCTL and window offsets.
1482 * @param m MADCTL value.
1483 * @param cs First visible column.
1484 * @param rs First visible row.
1485 * @see gfx_setPanelOffsets()
1486 */
1487 void setPanelOffsets(uint8_t m, uint8_t cs, uint8_t rs) { gfx_setPanelOffsets(m, cs, rs); }
1488 /** @brief Turns colour inversion on or off. @param on true to invert. @see gfx_setInverted() */
1489 void setInverted(bool on) { gfx_setInverted(on); }
1490 /**
1491 * @brief Sets the panel's own refresh rate (FRMCTR1).
1492 * @param r RTNA.
1493 * @param f Front porch.
1494 * @param b Back porch.
1495 * @see gfx_setPanelFrameRate()
1496 */
1497 void setPanelFrameRate(uint8_t r, uint8_t f, uint8_t b) { gfx_setPanelFrameRate(r, f, b); }
1498 /** @} */
1499
1500 /** @name Palette */
1501 /** @{ */
1502 /**
1503 * @brief Sets the first `n` palette entries.
1504 * @param p RGB565 colours.
1505 * @param n How many, at most 16.
1506 * @see gfx_setPalette()
1507 */
1508 void setPalette(const uint16_t *p, uint8_t n) { gfx_setPalette(p, n); }
1509 /**
1510 * @brief Sets one palette entry.
1511 * @param i Palette index, 0..15.
1512 * @param c RGB565 colour.
1513 * @see gfx_setPaletteEntry()
1514 */
1515 void setPaletteEntry(uint8_t i, uint16_t c) { gfx_setPaletteEntry(i, c); }
1516 /**
1517 * @brief Fades every colour toward one colour.
1518 * @param amount 0 = none, 255 = solid `rgb565`.
1519 * @param rgb565 The colour faded toward (default black).
1520 * @see gfx_setFade()
1521 */
1522 void setFade(uint8_t amount, uint16_t rgb565 = 0) { gfx_setFade(amount, rgb565); }
1523 /** @brief The current fade amount. @return 0..255. @see gfx_fade() */
1524 uint8_t fade() const { return gfx_fade(); }
1525 /**
1526 * @brief Nearest palette index for an RGB565 colour (slow: setup only).
1527 * @param rgb565 The colour.
1528 * @return Palette index, 0..15.
1529 * @see gfx_nearest()
1530 */
1531 uint8_t nearest(uint16_t rgb565) const { return gfx_nearest(rgb565); }
1532 /**
1533 * @brief Packs an 8-bit-per-channel colour into RGB565.
1534 * @param r Red, 0..255.
1535 * @param g Green, 0..255.
1536 * @param b Blue, 0..255.
1537 * @return RGB565.
1538 * @see gfx_rgb()
1539 */
1540 static uint16_t rgb(uint8_t r, uint8_t g, uint8_t b) { return gfx_rgb(r, g, b); }
1541 /** @} */
1542
1543 /** @name Present */
1544 /** @{ */
1545 /** @brief Sends the whole framebuffer and waits for it. @see gfx_flush() */
1546 void display() { gfx_flush(); }
1547 /**
1548 * @brief Draws one full-colour frame from a callback, bypassing the
1549 * framebuffer.
1550 * @param fn Fills each chunk of rows.
1551 * @param user Passed to `fn` (default nullptr).
1552 * @see gfx_stream()
1553 */
1554 void stream(gfx_streamFn fn, void *user = nullptr) { gfx_stream(fn, user); }
1555 /** @brief Starts sending the whole framebuffer by DMA and returns at once. @see gfx_flushAsync() */
1557 /**
1558 * @brief Sends one rectangle of the framebuffer and waits for it.
1559 * @param x Left edge.
1560 * @param y Top edge.
1561 * @param w Width.
1562 * @param h Height.
1563 * @see gfx_flushRect()
1564 */
1565 void displayRect(int x, int y, int w, int h) { gfx_flushRect(x, y, w, h); }
1566 /**
1567 * @brief Starts sending one rectangle of the framebuffer and returns at once.
1568 * @param x Left edge.
1569 * @param y Top edge.
1570 * @param w Width.
1571 * @param h Height.
1572 * @see gfx_flushRectAsync()
1573 */
1574 void displayRectAsync(int x, int y, int w, int h){ gfx_flushRectAsync(x, y, w, h); }
1575 /** @brief Whether an async flush is in flight. @return true while sending. @see gfx_busy() */
1576 bool busy() const { return gfx_busy(); }
1577 /** @brief Waits for the flush in flight to finish. @see gfx_wait() */
1578 void wait() { gfx_wait(); }
1579 /** @brief The first row the flush in flight may still read. @return A row, or GFX_H when idle. @see gfx_flushRow() */
1580 int flushRow() const { return gfx_flushRow(); }
1581 /** @brief Waits until rows 0..y-1 are free to draw into. @param y One past the last row needed. @see gfx_waitRow() */
1582 void waitRow(int y) { gfx_waitRow(y); }
1583 /** @} */
1584
1585 /** @name Clip */
1586 /** @{ */
1587 /**
1588 * @brief Sets the clip rectangle.
1589 * @param x Left edge.
1590 * @param y Top edge.
1591 * @param w Width.
1592 * @param h Height.
1593 * @see gfx_setClip()
1594 */
1595 void setClip(int x, int y, int w, int h) { gfx_setClip(x, y, w, h); }
1596 /** @brief Puts the clip rectangle back to the whole screen. @see gfx_resetClip() */
1598 /**
1599 * @brief Reads the clip rectangle.
1600 * @param[out] x Left edge (may be nullptr).
1601 * @param[out] y Top edge (may be nullptr).
1602 * @param[out] w Width (may be nullptr).
1603 * @param[out] h Height (may be nullptr).
1604 * @see gfx_getClip()
1605 */
1606 void getClip(int *x, int *y, int *w, int *h) const { gfx_getClip(x, y, w, h); }
1607 /** @} */
1608
1609 /** @name Draw */
1610 /** @{ */
1611 /** @brief Fills the clip rectangle with one colour. @param c Palette index. @see gfx_clear() */
1612 void clear(uint8_t c) { gfx_clear(c); }
1613 /**
1614 * @brief Sets one pixel.
1615 * @param x Column.
1616 * @param y Row.
1617 * @param c Palette index.
1618 * @see gfx_pixel()
1619 */
1620 void drawPixel(int x, int y, uint8_t c) { gfx_pixel(x, y, c); }
1621 /**
1622 * @brief Reads one pixel.
1623 * @param x Column.
1624 * @param y Row.
1625 * @return Palette index, or 0 off the screen.
1626 * @see gfx_getPixel()
1627 */
1628 uint8_t getPixel(int x, int y) const { return gfx_getPixel(x, y); }
1629 /**
1630 * @brief Draws a horizontal line.
1631 * @param x Left end.
1632 * @param y Row.
1633 * @param w Length.
1634 * @param c Palette index.
1635 * @see gfx_hline()
1636 */
1637 void drawFastHLine(int x, int y, int w, uint8_t c) { gfx_hline(x, y, w, c); }
1638 /**
1639 * @brief Draws a vertical line.
1640 * @param x Column.
1641 * @param y Top end.
1642 * @param h Length.
1643 * @param c Palette index.
1644 * @see gfx_vline()
1645 */
1646 void drawFastVLine(int x, int y, int h, uint8_t c) { gfx_vline(x, y, h, c); }
1647 /**
1648 * @brief Fills a rectangle.
1649 * @param x Left edge.
1650 * @param y Top edge.
1651 * @param w Width.
1652 * @param h Height.
1653 * @param c Palette index.
1654 * @see gfx_fillRect()
1655 */
1656 void fillRect(int x, int y, int w, int h, uint8_t c) { gfx_fillRect(x, y, w, h, c); }
1657 /**
1658 * @brief Draws a rectangle's outline.
1659 * @param x Left edge.
1660 * @param y Top edge.
1661 * @param w Width.
1662 * @param h Height.
1663 * @param c Palette index.
1664 * @see gfx_rect()
1665 */
1666 void drawRect(int x, int y, int w, int h, uint8_t c) { gfx_rect(x, y, w, h, c); }
1667 /**
1668 * @brief Draws a line, both ends included.
1669 * @param x0 Start column.
1670 * @param y0 Start row.
1671 * @param x1 End column.
1672 * @param y1 End row.
1673 * @param c Palette index.
1674 * @see gfx_line()
1675 */
1676 void drawLine(int x0, int y0, int x1, int y1, uint8_t c) { gfx_line(x0, y0, x1, y1, c); }
1677 /**
1678 * @brief Draws a circle's outline.
1679 * @param cx Centre column.
1680 * @param cy Centre row.
1681 * @param r Radius.
1682 * @param c Palette index.
1683 * @see gfx_circle()
1684 */
1685 void drawCircle(int cx, int cy, int r, uint8_t c) { gfx_circle(cx, cy, r, c); }
1686 /**
1687 * @brief Draws a filled circle.
1688 * @param cx Centre column.
1689 * @param cy Centre row.
1690 * @param r Radius.
1691 * @param c Palette index.
1692 * @see gfx_fillCircle()
1693 */
1694 void fillCircle(int cx, int cy, int r, uint8_t c) { gfx_fillCircle(cx, cy, r, c); }
1695 /**
1696 * @brief Copies a 4 bpp bitmap into the framebuffer.
1697 * @param s The bitmap, packed like the framebuffer.
1698 * @param x Left edge.
1699 * @param y Top edge.
1700 * @param w Width in pixels.
1701 * @param h Height in pixels.
1702 * @param transparent Colour index skipped, or -1 (the default) for opaque.
1703 * @see gfx_blit()
1704 */
1705 void drawSprite(const uint8_t *s, int x, int y, int w, int h, int transparent = -1)
1706 { gfx_blit(s, x, y, w, h, transparent); }
1707 /**
1708 * @brief Draws a rounded rectangle's outline.
1709 * @param x Left edge.
1710 * @param y Top edge.
1711 * @param w Width.
1712 * @param h Height.
1713 * @param r Corner radius.
1714 * @param c Palette index.
1715 * @see gfx_roundRect()
1716 */
1717 void drawRoundRect(int x, int y, int w, int h, int r, uint8_t c) { gfx_roundRect(x, y, w, h, r, c); }
1718 /**
1719 * @brief Fills a rounded rectangle.
1720 * @param x Left edge.
1721 * @param y Top edge.
1722 * @param w Width.
1723 * @param h Height.
1724 * @param r Corner radius.
1725 * @param c Palette index.
1726 * @see gfx_fillRoundRect()
1727 */
1728 void fillRoundRect(int x, int y, int w, int h, int r, uint8_t c) { gfx_fillRoundRect(x, y, w, h, r, c); }
1729 /**
1730 * @brief Draws an ellipse's outline.
1731 * @param cx Centre column.
1732 * @param cy Centre row.
1733 * @param rx Horizontal radius.
1734 * @param ry Vertical radius.
1735 * @param c Palette index.
1736 * @see gfx_ellipse()
1737 */
1738 void drawEllipse(int cx, int cy, int rx, int ry, uint8_t c) { gfx_ellipse(cx, cy, rx, ry, c); }
1739 /**
1740 * @brief Draws a filled ellipse.
1741 * @param cx Centre column.
1742 * @param cy Centre row.
1743 * @param rx Horizontal radius.
1744 * @param ry Vertical radius.
1745 * @param c Palette index.
1746 * @see gfx_fillEllipse()
1747 */
1748 void fillEllipse(int cx, int cy, int rx, int ry, uint8_t c) { gfx_fillEllipse(cx, cy, rx, ry, c); }
1749 /**
1750 * @brief Paints a 50% checkerboard of one colour over a rectangle.
1751 * @param x Left edge.
1752 * @param y Top edge.
1753 * @param w Width.
1754 * @param h Height.
1755 * @param c Palette index.
1756 * @param phase 0 (the default) paints where x + y is even, 1 where odd.
1757 * @see gfx_dither()
1758 */
1759 void dither(int x, int y, int w, int h, uint8_t c, uint8_t phase = 0) { gfx_dither(x, y, w, h, c, phase); }
1760 /**
1761 * @brief Recolours a rectangle in place through a 16-entry table.
1762 * @param x Left edge.
1763 * @param y Top edge.
1764 * @param w Width.
1765 * @param h Height.
1766 * @param remap 16 palette indices.
1767 * @see gfx_remapRect()
1768 */
1769 void remapRect(int x, int y, int w, int h, const uint8_t *remap) { gfx_remapRect(x, y, w, h, remap); }
1770 /**
1771 * @brief Draws a span sprite.
1772 * @param s The sprite data.
1773 * @param x Left edge.
1774 * @param y Top edge.
1775 * @param remap 16 palette indices, or nullptr (the default).
1776 * @param scale Q8 scale, 256 = 1:1 (the default).
1777 * @see gfx_sprite4()
1778 */
1779 void drawSprite4(const uint8_t *s, int x, int y, const uint8_t *remap = nullptr, int scale = 256)
1780 { gfx_sprite4(s, x, y, remap, scale); }
1781 /**
1782 * @brief Draws a span sprite rotated and scaled about a pivot.
1783 * @param s The sprite data (at most 1 KB decoded).
1784 * @param ax Pivot column in the sprite.
1785 * @param ay Pivot row in the sprite.
1786 * @param px Screen column of the pivot.
1787 * @param py Screen row of the pivot.
1788 * @param angle 256 = a full turn, clockwise.
1789 * @param scale Q8 scale, 256 = 1:1 (the default).
1790 * @param remap 16 palette indices, or nullptr (the default).
1791 * @see gfx_sprite4Rot()
1792 */
1793 void drawSprite4Rot(const uint8_t *s, int ax, int ay, int px, int py, uint8_t angle,
1794 int scale = 256, const uint8_t *remap = nullptr)
1795 { gfx_sprite4Rot(s, ax, ay, px, py, angle, scale, remap); }
1796 /**
1797 * @brief Moves a band of rows by (dx, dy) inside the band.
1798 * @param y First row.
1799 * @param h Rows.
1800 * @param dx Pixels right (negative: left).
1801 * @param dy Rows down (negative: up).
1802 * @param fill Palette index for uncovered pixels, or -1 (the default) to keep them.
1803 * @see gfx_scroll()
1804 */
1805 void scroll(int y, int h, int dx, int dy, int fill = -1) { gfx_scroll(y, h, dx, dy, fill); }
1806 /**
1807 * @brief Copies pixels [x0, x1) of a row buffer into a framebuffer row.
1808 * @param y Framebuffer row.
1809 * @param src GFX_FB_STRIDE bytes, packed like the framebuffer.
1810 * @param x0 First pixel.
1811 * @param x1 One past the last pixel.
1812 * @see gfx_copyRow()
1813 */
1814 void copyRow(int y, const uint8_t *src, int x0, int x1) { gfx_copyRow(y, src, x0, x1); }
1815 /**
1816 * @brief Draws one character.
1817 * @param x Left edge.
1818 * @param y Top (built-in font) or baseline (GFXfont).
1819 * @param ch The character.
1820 * @param c Palette index.
1821 * @see gfx_char()
1822 */
1823 void drawChar(int x, int y, char ch, uint8_t c) { gfx_char(x, y, ch, c); }
1824 /**
1825 * @brief Draws one character, scaled.
1826 * @param x Left edge.
1827 * @param y Top (built-in font) or baseline (GFXfont).
1828 * @param ch The character.
1829 * @param c Palette index.
1830 * @param scale Integer scale.
1831 * @see gfx_charScaled()
1832 */
1833 void drawChar(int x, int y, char ch, uint8_t c, uint8_t scale)
1834 { gfx_charScaled(x, y, ch, c, scale); }
1835 /**
1836 * @brief Draws a string.
1837 * @param x Left edge.
1838 * @param y Top (built-in font) or baseline (GFXfont).
1839 * @param s Null-terminated string.
1840 * @param c Palette index.
1841 * @see gfx_text()
1842 */
1843 void print(int x, int y, const char *s, uint8_t c) { gfx_text(x, y, s, c); }
1844 /**
1845 * @brief Draws a string, scaled.
1846 * @param x Left edge.
1847 * @param y Top (built-in font) or baseline (GFXfont).
1848 * @param s Null-terminated string.
1849 * @param c Palette index.
1850 * @param scale Integer scale.
1851 * @see gfx_textScaled()
1852 */
1853 void print(int x, int y, const char *s, uint8_t c, uint8_t scale)
1854 { gfx_textScaled(x, y, s, c, scale); }
1855 /**
1856 * @brief Draws outlined, shadowed or gradient-filled text.
1857 * @param x Left edge.
1858 * @param y Top (built-in font) or baseline (GFXfont).
1859 * @param s Null-terminated string.
1860 * @param scale Integer scale.
1861 * @param fill Palette index of the letters.
1862 * @param outline Palette index of the outline, or -1 (the default).
1863 * @param shadow Palette index of the shadow, or -1 (the default).
1864 * @param ramp A fill colour per pixel row, or nullptr (the default).
1865 * @param dy A vertical offset per character, or nullptr (the default).
1866 * @return false if the text is too big for the 1 KB mask.
1867 * @see gfx_textFx()
1868 */
1869 bool printFx(int x, int y, const char *s, uint8_t scale, uint8_t fill, int outline = -1,
1870 int shadow = -1, const uint8_t *ramp = nullptr, const int8_t *dy = nullptr)
1871 { return gfx_textFx(x, y, s, scale, fill, outline, shadow, ramp, dy); }
1872 /** @} */
1873
1874 /** @name Fonts
1875 * setFont(nullptr) returns to the built-in 5x7. Note that a custom
1876 * font takes y as the baseline - see @ref chgfx_text.
1877 */
1878 /** @{ */
1879 /** @brief Selects the font. @param f A GFXfont, or nullptr (the default) for the built-in 5x7. @see gfx_setFont() */
1880 void setFont(const GFXfont *f = nullptr) { gfx_setFont(f); }
1881 /** @brief The current font. @return The GFXfont, or nullptr for the built-in one. @see gfx_font() */
1882 const GFXfont *font() const { return gfx_font(); }
1883 /** @brief Baseline-to-baseline line spacing. @return Pixels at scale 1. @see gfx_fontLineHeight() */
1884 int fontLineHeight() const { return gfx_fontLineHeight(); }
1885 /** @brief The font's ascent above the baseline. @return Pixels at scale 1; 0 for the built-in font. @see gfx_fontBaseline() */
1886 int fontBaseline() const { return gfx_fontBaseline(); }
1887 /** @brief Advance width of a string. @param s Null-terminated string. @return Pixels (the widest line). @see gfx_textWidth() */
1888 int textWidth(const char *s) const { return gfx_textWidth(s); }
1889 /**
1890 * @brief Advance width of a string at a scale.
1891 * @param s Null-terminated string.
1892 * @param scale Integer scale.
1893 * @return Pixels (the widest line).
1894 * @see gfx_textWidthScaled()
1895 */
1896 int textWidth(const char *s, uint8_t scale) const { return gfx_textWidthScaled(s, scale); }
1897 /**
1898 * @brief Bounding box of a string drawn at (x, y).
1899 * @param s Null-terminated string.
1900 * @param x Where it would be drawn.
1901 * @param y Where it would be drawn.
1902 * @param scale Integer scale.
1903 * @param[out] bx Left edge (may be nullptr).
1904 * @param[out] by Top edge (may be nullptr).
1905 * @param[out] bw Width (may be nullptr).
1906 * @param[out] bh Height (may be nullptr).
1907 * @see gfx_textBounds()
1908 */
1909 void textBounds(const char *s, int x, int y, uint8_t scale,
1910 int *bx, int *by, int *bw, int *bh) const
1911 { gfx_textBounds(s, x, y, scale, bx, by, bw, bh); }
1912 /** @} */
1913
1914 /** @name Direct to the panel */
1915 /** @{ */
1916 /**
1917 * @brief Fills a rectangle of the panel by DMA, bypassing the
1918 * framebuffer (16 bpp only).
1919 * @param x Left edge.
1920 * @param y Top edge.
1921 * @param w Width.
1922 * @param h Height.
1923 * @param rgb565 The colour.
1924 * @see gfx_directFillRect()
1925 */
1926 void fillRectDirect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t rgb565)
1927 { gfx_directFillRect(x, y, w, h, rgb565); }
1928 /** @} */
1929
1930 /** @name The raw framebuffer */
1931 /** @{ */
1932 /** @brief The framebuffer, for primitives of your own. @return gfx_fb. */
1933 uint8_t *buffer() const { return gfx_fb; }
1934 /** @brief Screen width. @return GFX_W. */
1935 static constexpr int width() { return GFX_W; }
1936 /** @brief Screen height. @return GFX_H. */
1937 static constexpr int height() { return GFX_H; }
1938 /** @} */
1939};
1940
1941/**
1942 * @brief The one CHGfx instance. Declared here, defined in CHGfx.cpp.
1943 *
1944 * `Gfx.clear(0)` is the same code as `gfx_clear(0)`.
1945 */
1946extern CHGfx Gfx;
1947
1948/** @} */
The bitmap font container, GFXfont, byte-for-byte Adafruit_GFX's.
Arduino-style access to CHGfx: every method is a zero-cost inline forwarder to a gfx_* function.
Definition CHGfx.h:1460
void stream(gfx_streamFn fn, void *user=nullptr)
Draws one full-colour frame from a callback, bypassing the framebuffer.
Definition CHGfx.h:1554
void setInverted(bool on)
Turns colour inversion on or off.
Definition CHGfx.h:1489
void setFade(uint8_t amount, uint16_t rgb565=0)
Fades every colour toward one colour.
Definition CHGfx.h:1522
void drawChar(int x, int y, char ch, uint8_t c)
Draws one character.
Definition CHGfx.h:1823
uint8_t getPixel(int x, int y) const
Reads one pixel.
Definition CHGfx.h:1628
void setPaletteEntry(uint8_t i, uint16_t c)
Sets one palette entry.
Definition CHGfx.h:1515
void drawRect(int x, int y, int w, int h, uint8_t c)
Draws a rectangle's outline.
Definition CHGfx.h:1666
void wait()
Waits for the flush in flight to finish.
Definition CHGfx.h:1578
int flushRow() const
The first row the flush in flight may still read.
Definition CHGfx.h:1580
uint8_t * buffer() const
The framebuffer, for primitives of your own.
Definition CHGfx.h:1933
int fontLineHeight() const
Baseline-to-baseline line spacing.
Definition CHGfx.h:1884
int textWidth(const char *s, uint8_t scale) const
Advance width of a string at a scale.
Definition CHGfx.h:1896
int textWidth(const char *s) const
Advance width of a string.
Definition CHGfx.h:1888
uint8_t nearest(uint16_t rgb565) const
Nearest palette index for an RGB565 colour (slow: setup only).
Definition CHGfx.h:1531
static constexpr int width()
Screen width.
Definition CHGfx.h:1935
void displayAsync()
Starts sending the whole framebuffer by DMA and returns at once.
Definition CHGfx.h:1556
void begin(uint8_t spiDiv=GFX_DIV2, uint8_t colorMode=GFX_16BPP)
Starts the panel.
Definition CHGfx.h:1468
void setPanelOffsets(uint8_t m, uint8_t cs, uint8_t rs)
Sets the panel's MADCTL and window offsets.
Definition CHGfx.h:1487
void fillCircle(int cx, int cy, int r, uint8_t c)
Draws a filled circle.
Definition CHGfx.h:1694
void drawSprite4(const uint8_t *s, int x, int y, const uint8_t *remap=nullptr, int scale=256)
Draws a span sprite.
Definition CHGfx.h:1779
void dither(int x, int y, int w, int h, uint8_t c, uint8_t phase=0)
Paints a 50% checkerboard of one colour over a rectangle.
Definition CHGfx.h:1759
void drawChar(int x, int y, char ch, uint8_t c, uint8_t scale)
Draws one character, scaled.
Definition CHGfx.h:1833
void copyRow(int y, const uint8_t *src, int x0, int x1)
Copies pixels [x0, x1) of a row buffer into a framebuffer row.
Definition CHGfx.h:1814
void drawFastHLine(int x, int y, int w, uint8_t c)
Draws a horizontal line.
Definition CHGfx.h:1637
void scroll(int y, int h, int dx, int dy, int fill=-1)
Moves a band of rows by (dx, dy) inside the band.
Definition CHGfx.h:1805
void remapRect(int x, int y, int w, int h, const uint8_t *remap)
Recolours a rectangle in place through a 16-entry table.
Definition CHGfx.h:1769
void setColorMode(uint8_t m)
Switches the colour output mode.
Definition CHGfx.h:1475
void setPalette(const uint16_t *p, uint8_t n)
Sets the first n palette entries.
Definition CHGfx.h:1508
static uint16_t rgb(uint8_t r, uint8_t g, uint8_t b)
Packs an 8-bit-per-channel colour into RGB565.
Definition CHGfx.h:1540
void setPanelFrameRate(uint8_t r, uint8_t f, uint8_t b)
Sets the panel's own refresh rate (FRMCTR1).
Definition CHGfx.h:1497
uint32_t spiHz() const
The current SPI clock.
Definition CHGfx.h:1479
void setSpiDiv(uint8_t d)
Changes the SPI clock divider.
Definition CHGfx.h:1473
void displayRect(int x, int y, int w, int h)
Sends one rectangle of the framebuffer and waits for it.
Definition CHGfx.h:1565
const GFXfont * font() const
The current font.
Definition CHGfx.h:1882
void print(int x, int y, const char *s, uint8_t c, uint8_t scale)
Draws a string, scaled.
Definition CHGfx.h:1853
void displayRectAsync(int x, int y, int w, int h)
Starts sending one rectangle of the framebuffer and returns at once.
Definition CHGfx.h:1574
void drawLine(int x0, int y0, int x1, int y1, uint8_t c)
Draws a line, both ends included.
Definition CHGfx.h:1676
void textBounds(const char *s, int x, int y, uint8_t scale, int *bx, int *by, int *bw, int *bh) const
Bounding box of a string drawn at (x, y).
Definition CHGfx.h:1909
int fontBaseline() const
The font's ascent above the baseline.
Definition CHGfx.h:1886
bool printFx(int x, int y, const char *s, uint8_t scale, uint8_t fill, int outline=-1, int shadow=-1, const uint8_t *ramp=nullptr, const int8_t *dy=nullptr)
Draws outlined, shadowed or gradient-filled text.
Definition CHGfx.h:1869
void fillRect(int x, int y, int w, int h, uint8_t c)
Fills a rectangle.
Definition CHGfx.h:1656
void drawPixel(int x, int y, uint8_t c)
Sets one pixel.
Definition CHGfx.h:1620
void drawCircle(int cx, int cy, int r, uint8_t c)
Draws a circle's outline.
Definition CHGfx.h:1685
void clear(uint8_t c)
Fills the clip rectangle with one colour.
Definition CHGfx.h:1612
void waitRow(int y)
Waits until rows 0..y-1 are free to draw into.
Definition CHGfx.h:1582
void resetClip()
Puts the clip rectangle back to the whole screen.
Definition CHGfx.h:1597
uint8_t colorMode() const
The current colour output mode.
Definition CHGfx.h:1477
void fillEllipse(int cx, int cy, int rx, int ry, uint8_t c)
Draws a filled ellipse.
Definition CHGfx.h:1748
void setFont(const GFXfont *f=nullptr)
Selects the font.
Definition CHGfx.h:1880
void drawRoundRect(int x, int y, int w, int h, int r, uint8_t c)
Draws a rounded rectangle's outline.
Definition CHGfx.h:1717
void drawEllipse(int cx, int cy, int rx, int ry, uint8_t c)
Draws an ellipse's outline.
Definition CHGfx.h:1738
void display()
Sends the whole framebuffer and waits for it.
Definition CHGfx.h:1546
void drawFastVLine(int x, int y, int h, uint8_t c)
Draws a vertical line.
Definition CHGfx.h:1646
uint8_t fade() const
The current fade amount.
Definition CHGfx.h:1524
void fillRoundRect(int x, int y, int w, int h, int r, uint8_t c)
Fills a rounded rectangle.
Definition CHGfx.h:1728
void print(int x, int y, const char *s, uint8_t c)
Draws a string.
Definition CHGfx.h:1843
void drawSprite4Rot(const uint8_t *s, int ax, int ay, int px, int py, uint8_t angle, int scale=256, const uint8_t *remap=nullptr)
Draws a span sprite rotated and scaled about a pivot.
Definition CHGfx.h:1793
static constexpr int height()
Screen height.
Definition CHGfx.h:1937
void getClip(int *x, int *y, int *w, int *h) const
Reads the clip rectangle.
Definition CHGfx.h:1606
bool busy() const
Whether an async flush is in flight.
Definition CHGfx.h:1576
void fillRectDirect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t rgb565)
Fills a rectangle of the panel by DMA, bypassing the framebuffer (16 bpp only).
Definition CHGfx.h:1926
void drawSprite(const uint8_t *s, int x, int y, int w, int h, int transparent=-1)
Copies a 4 bpp bitmap into the framebuffer.
Definition CHGfx.h:1705
void setClip(int x, int y, int w, int h)
Sets the clip rectangle.
Definition CHGfx.h:1595
CHGfx Gfx
The one CHGfx instance.
#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
#define GFX_FB_BYTES
Size of the framebuffer, gfx_fb, in bytes: 8192 at 128x128.
Definition CHGfx.h:114
@ GFX_DIV2
HCLK/2 = 24 MHz: the fastest the chip can clock SPI, and the default.
Definition CHGfx.h:232
@ GFX_DIV16
HCLK/16 = 3 MHz.
Definition CHGfx.h:232
@ GFX_DIV8
HCLK/8 = 6 MHz.
Definition CHGfx.h:232
@ GFX_DIV4
HCLK/4 = 12 MHz: within the ST7735S datasheet's limit.
Definition CHGfx.h:232
@ GFX_12BPP
ST7735 COLMOD 0x03, RGB444, 1.5 bytes/px -> 119 fps.
Definition CHGfx.h:220
@ GFX_18BPP
ST7735 COLMOD 0x06, RGB666, 3 bytes/px -> 61 fps.
Definition CHGfx.h:221
@ GFX_16BPP
ST7735 COLMOD 0x05, RGB565, 2 bytes/px -> 90 fps.
Definition CHGfx.h:219
void gfx_select(void)
Asserts the panel's chip select.
void gfx_blockingWrite(const uint8_t *data, uint32_t bytes)
Sends bytes one at a time in a polled loop, for baseline comparisons.
void gfx_setWriteColorLut(bool on)
Chooses whether entering 12 bpp writes the colour LUT (gfx_writeColorLut()).
void gfx_writeColorLut(void)
Programs the ST7735 RGBSET (2Dh) colour-depth conversion LUT for the current mode.
void gfx_deselect(void)
Waits for the last byte to leave SPI1, then releases the panel's chip select.
void gfx_directFillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t rgb565)
Fills a rectangle of the panel with one colour by DMA, bypassing the framebuffer.
void gfx_directBlit(const void *data, uint32_t bytes, bool halfword)
Sends a caller-owned buffer, already in panel format, by DMA and waits for it.
void gfx_cmd(uint8_t c)
Sends one command byte (D/C low), then sets D/C back to data.
void gfx_setWindow(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Sets the panel's address window and starts a memory write (CASET, RASET, RAMWR).
void gfx_data8(uint8_t d)
Sends one data byte (D/C high).
void gfx_getClip(int *x, int *y, int *w, int *h)
Reads the clip rectangle, as intersected with the screen.
void gfx_blit(const uint8_t *spr, int x, int y, int w, int h, int transparent)
Copies a 4 bpp bitmap into the framebuffer, optionally with one colour transparent.
uint8_t gfx_getPixel(int x, int y)
Reads one pixel of the framebuffer (the clip is ignored).
void gfx_circle(int cx, int cy, int r, uint8_t c)
Draws a circle's 1-pixel outline, 2*r+1 pixels across.
void gfx_rect(int x, int y, int w, int h, uint8_t c)
Draws a rectangle's 1-pixel outline.
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_setClip(int x, int y, int w, int h)
Sets the clip rectangle every drawing call stays inside.
uint8_t gfx_fb[GFX_FB_BYTES]
The framebuffer: GFX_FB_BYTES of 4 bpp pixels, two per byte.
void gfx_fillCircle(int cx, int cy, int r, uint8_t c)
Draws a filled circle, 2*r+1 pixels across.
void gfx_resetClip(void)
Puts the clip rectangle back to the whole screen.
void gfx_vline(int x, int y, int h, uint8_t c)
Draws a vertical line from (x, y), h pixels down.
void gfx_line(int x0, int y0, int x1, int y1, uint8_t c)
Draws a line between two points, both ends included.
uint32_t gfx_convertRows_flash(uint8_t *dst, uint16_t row, uint16_t rows)
Converts framebuffer rows into the panel's format, with the converter in flash (for comparison with g...
uint8_t * gfx_chunkScratch(void)
1 KB of word-aligned scratch memory: the flush's chunk buffers.
uint32_t gfx_convertRows_ram(uint8_t *dst, uint16_t row, uint16_t rows)
Converts framebuffer rows into the panel's format, with the converter in SRAM.
uint32_t gfx_convertSpan_ram(uint8_t *dst, const uint8_t *src, uint32_t srcBytes)
Converts a run of framebuffer bytes into the panel's format (the SRAM converter every flush uses).
uint32_t gfx_frameBytes(void)
Bytes the panel receives for a full frame in the current mode.
uint16_t gfx_pal[16]
The 16 palette colours as set, in RGB565.
uint16_t gfx_paletteOut(uint8_t index)
The colour a palette index actually reaches the panel as, fade included.
void gfx_setPaletteEntry(uint8_t index, uint16_t rgb565)
Sets one palette entry.
void gfx_setFade(uint8_t amount, uint16_t rgb565=0x0000)
Fades every colour toward one colour (black by default).
uint8_t gfx_fade(void)
The current fade amount.
void gfx_setPalette(const uint16_t *rgb565, uint8_t count)
Sets the first count palette entries.
static uint16_t gfx_rgb(uint8_t r, uint8_t g, uint8_t b)
Packs an 8-bit-per-channel colour into RGB565.
Definition CHGfx.h:456
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.
void gfx_waitRow(int y)
Waits until rows 0..y-1 are free to draw into.
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.
int gfx_flushRow(void)
The first framebuffer row the flush in flight may still read.
void gfx_copyRow(int y, const uint8_t *src, int x0, int x1)
Copies pixels [x0, x1) of a full-width row buffer into framebuffer row y, clipped.
void gfx_scroll(int y, int h, int dx, int dy, int fill=-1)
Moves a band of rows by (dx, dy) pixels inside the band.
uint32_t gfx_spiHz(void)
The current SPI clock.
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_setPanelOffsets(uint8_t madctl, uint8_t colStart, uint8_t rowStart)
Sets the panel's orientation (MADCTL) and the offsets of the visible window in its memory.
void gfx_setSpiDiv(uint8_t div)
Changes the SPI clock divider, and sets SPI1 up afresh for the panel.
void gfx_setInverted(bool on)
Turns the panel's colour inversion (INVON / INVOFF) on or off.
void gfx_setPanelFrameRate(uint8_t rtna, uint8_t fpa, uint8_t bpa)
Sets the panel's own refresh rate (ST7735 FRMCTR1, 0xB1).
void gfx_setColorMode(uint8_t mode)
Switches the panel's colour output mode.
uint8_t gfx_colorMode(void)
The current colour output mode.
uint8_t gfx_spiDiv(void)
The current SPI clock divider.
void gfx_fillEllipse(int cx, int cy, int rx, int ry, uint8_t c)
Draws a filled axis-aligned ellipse, 2*rx+1 by 2*ry+1 pixels, centred on (cx, cy).
void gfx_remapRect(int x, int y, int w, int h, const uint8_t *remap)
Recolours a rectangle in place through a 16-entry table: pixel = remap[pixel].
void gfx_dither(int x, int y, int w, int h, uint8_t c, uint8_t phase)
Paints a 50% checkerboard of one colour over a rectangle, leaving the pixels in between alone.
void gfx_ellipse(int cx, int cy, int rx, int ry, uint8_t c)
Draws an axis-aligned ellipse's 1-pixel outline, 2*rx+1 by 2*ry+1 pixels, centred on (cx,...
void gfx_fillRoundRect(int x, int y, int w, int h, int r, uint8_t c)
Fills a rounded rectangle (corners as gfx_roundRect()).
void gfx_roundRect(int x, int y, int w, int h, int r, uint8_t c)
Draws a rounded rectangle's 1-pixel outline.
void gfx_sprite4(const uint8_t *spr, int x, int y, const uint8_t *remap=nullptr, int scale=256)
Draws a span sprite, optionally recoloured and scaled.
void gfx_sprite4Rot(const uint8_t *spr, int ax, int ay, int px, int py, uint8_t angle, int scale=256, const uint8_t *remap=nullptr)
Draws a span sprite rotated and scaled about a pivot.
static int gfx_sprite4H(const uint8_t *spr)
A span sprite's height.
Definition CHGfx.h:990
static int gfx_sprite4W(const uint8_t *spr)
A span sprite's width.
Definition CHGfx.h:984
uint8_t gfx_bytesPerPixel(void)
Bytes per pixel a stream callback writes in the current mode.
void(* gfx_streamFn)(uint8_t *dst, int y0, int rows, void *user)
A direct-streaming callback: fills rows rows starting at row y0 into dst, in the panel's native forma...
Definition CHGfx.h:604
static uint8_t * gfx_px565(uint8_t *p, uint16_t rgb565)
Writes one 16 bpp pixel for a stream callback.
Definition CHGfx.h:632
static uint8_t * gfx_px666(uint8_t *p, uint8_t r6, uint8_t g6, uint8_t b6)
Writes one 18 bpp pixel for a stream callback.
Definition CHGfx.h:644
void gfx_stream(gfx_streamFn fn, void *user)
Draws one full-screen frame by calling fn for every chunk of rows and sending the result straight to ...
void gfx_charScaled(int x, int y, char ch, uint8_t c, uint8_t scale)
Draws one character, scaled up by a whole number.
int gfx_fontLineHeight(void)
Baseline-to-baseline line spacing of the current font, at scale 1.
void gfx_textBounds(const char *s, int x, int y, uint8_t scale, int *bx, int *by, int *bw, int *bh)
Bounding box of a string drawn at (x, y).
int gfx_textWidth(const char *s)
Advance width of a string in the current font - the number to use for centring and right-alignment.
void gfx_textScaled(int x, int y, const char *s, uint8_t c, uint8_t scale)
Draws a string in the current font, scaled up by a whole number.
bool gfx_textFx(int x, int y, const char *s, uint8_t scale, uint8_t fill, int outline=-1, int shadow=-1, const uint8_t *ramp=nullptr, const int8_t *dy=nullptr)
Draws outlined, shadowed or gradient-filled text - titles and banners.
int gfx_textWidthScaled(const char *s, uint8_t scale)
Advance width of a string in the current font at a scale.
void gfx_char(int x, int y, char ch, uint8_t c)
Draws one character.
const GFXfont * gfx_font(void)
The current font.
void gfx_text(int x, int y, const char *s, uint8_t c)
Draws a string in the current font.
void gfx_setFont(const GFXfont *f)
Selects the font every text call uses from now on.
int gfx_fontBaseline(void)
The current font's ascent: how far its tallest ink reaches above the baseline, at scale 1.
A whole bitmap font, for gfx_setFont(): glyph bitmaps, glyph records, the character range and the lin...
Definition CHGfx_gfxfont.h:65