quantum_painter.md (43284B)
1 # Quantum Painter {#quantum-painter} 2 3 Quantum Painter is the standardised API for graphical displays. It currently includes support for basic drawing primitives, as well as custom images, animations, and fonts. 4 5 Due to the complexity, there is no support for Quantum Painter on AVR-based boards. 6 7 To enable overall Quantum Painter to be built into your firmware, add the following to `rules.mk`: 8 9 ```make 10 QUANTUM_PAINTER_ENABLE = yes 11 QUANTUM_PAINTER_DRIVERS += ...... 12 ``` 13 14 You will also likely need to select an appropriate driver in `rules.mk`, which is listed below. 15 16 ::: warning 17 Quantum Painter is not currently integrated with system-level operations such as when the keyboard goes into suspend. Users will need to handle this manually at the current time. 18 ::: 19 20 The QMK CLI can be used to convert from normal images such as PNG files or animated GIFs, as well as fonts from TTF files. 21 22 Supported devices: 23 24 | Display Panel | Panel Type | Size | Comms Transport | Driver | 25 |----------------|--------------------|------------------|-----------------|------------------------------------------| 26 | GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += gc9a01_spi` | 27 | ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9163_spi` | 28 | ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9341_spi` | 29 | ILI9486 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9486_spi` | 30 | ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ili9488_spi` | 31 | LD7032 (SPI) | Monochrome OLED | 128x40 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ld7032_spi` | 32 | LD7032 (I2C) | Monochrome OLED | 128x40 | I2C | `QUANTUM_PAINTER_DRIVERS += ld7032_i2c` | 33 | SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += ssd1351_spi` | 34 | ST7735 | RGB LCD | 132x162, 80x160 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7735_spi` | 35 | ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += st7789_spi` | 36 | SH1106 (SPI) | Monochrome OLED | 128x64 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += sh1106_spi` | 37 | SH1106 (I2C) | Monochrome OLED | 128x64 | I2C | `QUANTUM_PAINTER_DRIVERS += sh1106_i2c` | 38 | SSD1306 (SPI) | Monochrome OLED | 128x64 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS += sh1106_spi` | 39 | SSD1306 (I2C) | Monochrome OLED | 128x32 | I2C | `QUANTUM_PAINTER_DRIVERS += sh1106_i2c` | 40 | Surface | Virtual | User-defined | None | `QUANTUM_PAINTER_DRIVERS += surface` | 41 42 ## Quantum Painter Configuration {#quantum-painter-config} 43 44 | Option | Default | Purpose | 45 |---------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 46 | `QUANTUM_PAINTER_DISPLAY_TIMEOUT` | `30000` | This controls the amount of time (in milliseconds) that all displays will remain on after the last user input. If set to `0`, the display will remain on indefinitely. | 47 | `QUANTUM_PAINTER_TASK_THROTTLE` | `1` | This controls the amount of time (in milliseconds) that the Quantum Painter internal task will wait between each execution. Affects animations, display timeout, and LVGL timing if enabled. | 48 | `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. | 49 | `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. | 50 | `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. | 51 | `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. | 52 | `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `1024` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. | 53 | `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. | 54 | `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. | 55 | `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. | 56 | `QUANTUM_PAINTER_DEBUG_ENABLE_FLUSH_TASK_OUTPUT` | _unset_ | By default, debug output is disabled while the internal task is flushing the display(s). If you want to keep it enabled, add this to your `config.h`. Note: Console will get clogged. | 57 58 59 Drivers have their own set of configurable options, and are described in their respective sections. 60 61 ## Quantum Painter CLI Commands {#quantum-painter-cli} 62 63 :::::tabs 64 65 ==== `qmk painter-convert-graphics` 66 67 This command converts images to a format usable by QMK, i.e. the QGF File Format. 68 69 **Usage**: 70 71 ``` 72 usage: qmk painter-convert-graphics [-h] [-w] [-d] [-r] -f FORMAT [-o OUTPUT] -i INPUT [-v] 73 74 options: 75 -h, --help show this help message and exit 76 -w, --raw Writes out the QGF file as raw data instead of c/h combo. 77 -d, --no-deltas Disables the use of delta frames when encoding animations. 78 -r, --no-rle Disables the use of RLE when encoding images. 79 -f FORMAT, --format FORMAT 80 Output format, valid types: rgb888, rgb565, pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2 81 -o OUTPUT, --output OUTPUT 82 Specify output directory. Defaults to same directory as input. 83 -i INPUT, --input INPUT 84 Specify input graphic file. 85 -v, --verbose Turns on verbose output. 86 ``` 87 88 The `INPUT` argument can be any image file loadable by Python's Pillow module. Common formats include PNG, or Animated GIF. 89 90 The `OUTPUT` argument needs to be a directory, and will default to the same directory as the input argument. 91 92 The `FORMAT` argument can be any of the following: 93 94 | Format | Meaning | 95 |-----------|-------------------------------------------------------------------------------------------| 96 | `rgb888` | 16,777,216 colors in 8-8-8 RGB format (requires `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS`) | 97 | `rgb565` | 65,536 colors in 5-6-5 RGB format (requires `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS`) | 98 | `pal256` | 256-color palette (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) | 99 | `pal16` | 16-color palette | 100 | `pal4` | 4-color palette | 101 | `pal2` | 2-color palette | 102 | `mono256` | 256-shade grayscale (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) | 103 | `mono16` | 16-shade grayscale | 104 | `mono4` | 4-shade grayscale | 105 | `mono2` | 2-shade grayscale | 106 107 **Examples**: 108 109 ``` 110 $ cd /home/qmk/qmk_firmware/keyboards/my_keeb 111 $ qmk painter-convert-graphics -f mono16 -i my_image.gif -o ./generated/ 112 Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.h... 113 Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/my_image.qgf.c... 114 ``` 115 116 ==== `qmk painter-make-font-image` 117 118 This command converts a TTF font to an intermediate format for editing, before converting to the QFF File Format. 119 120 **Usage**: 121 122 ``` 123 usage: qmk painter-make-font-image [-h] [-a] [-u UNICODE_GLYPHS] [-n] [-s SIZE] -o OUTPUT -f FONT 124 125 optional arguments: 126 -h, --help show this help message and exit 127 -a, --no-aa Disable anti-aliasing on fonts. 128 -u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS 129 Also generate the specified unicode glyphs. 130 -n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified. 131 -s SIZE, --size SIZE Specify font size. Default 12. 132 -o OUTPUT, --output OUTPUT 133 Specify output image path. 134 -f FONT, --font FONT Specify input font file. 135 ``` 136 137 The `FONT` argument is generally a TrueType Font file (TTF). 138 139 The `OUTPUT` argument is the output image to generate, generally something like `my_font.png`. 140 141 The `UNICODE_GLYPHS` argument allows for specifying extra unicode glyphs to generate, and accepts a string. 142 143 **Examples**: 144 145 ``` 146 $ qmk painter-make-font-image --font NotoSans-ExtraCondensedBold.ttf --size 11 -o noto11.png --unicode-glyphs "ĄȽɂɻɣɈʣ" 147 ``` 148 149 ==== `qmk painter-convert-font-image` 150 151 This command converts an intermediate font image to the QFF File Format. 152 153 This command expects an image that conforms to the following format: 154 155 * Top-left pixel (at `0,0`) is the "delimiter" color: 156 * Each glyph in the font starts when a pixel of this color is found on the first row 157 * The first row is discarded when converting to the QFF format 158 * The number of delimited glyphs must match the supplied arguments to the command: 159 * The full ASCII set `0x20..0x7E` (if `--no-ascii` was not specified) 160 * The corresponding number of unicode glyphs if any were specified with `--unicode-glyphs` 161 * The order of the glyphs matches the ASCII set, if any, followed by the Unicode glyph set, if any. 162 163 **Usage**: 164 165 ``` 166 usage: qmk painter-convert-font-image [-h] [-w] [-r] -f FORMAT [-u UNICODE_GLYPHS] [-n] [-o OUTPUT] [-i INPUT] 167 168 options: 169 -h, --help show this help message and exit 170 -w, --raw Writes out the QFF file as raw data instead of c/h combo. 171 -r, --no-rle Disable the use of RLE to minimise converted image size. 172 -f FORMAT, --format FORMAT 173 Output format, valid types: rgb565, pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2 174 -u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS 175 Also generate the specified unicode glyphs. 176 -n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified. 177 -o OUTPUT, --output OUTPUT 178 Specify output directory. Defaults to same directory as input. 179 -i INPUT, --input INPUT 180 Specify input graphic file. 181 ``` 182 183 The same arguments for `--no-ascii` and `--unicode-glyphs` need to be specified, as per `qmk painter-make-font-image`. 184 185 **Examples**: 186 187 ``` 188 $ cd /home/qmk/qmk_firmware/keyboards/my_keeb 189 $ qmk painter-convert-font-image --input noto11.png -f mono4 --unicode-glyphs "ĄȽɂɻɣɈʣ" 190 Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.h... 191 Writing /home/qmk/qmk_firmware/keyboards/my_keeb/generated/noto11.qff.c... 192 ``` 193 194 ::::: 195 196 ## Quantum Painter Display Drivers {#quantum-painter-drivers} 197 198 ::::::tabs 199 200 ===== LCD 201 202 Most TFT display panels use a 5-pin interface -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins. 203 204 For these displays, QMK's `spi_master` must already be correctly configured for the platform you're building for. 205 206 The pin assignments for SPI CS, D/C, and RST are specified during device construction. 207 208 :::::tabs 209 210 ==== GC9A01 211 212 Enabling support for the GC9A01 in Quantum Painter is done by adding the following to `rules.mk`: 213 214 ```make 215 QUANTUM_PAINTER_ENABLE = yes 216 QUANTUM_PAINTER_DRIVERS += gc9a01_spi 217 ``` 218 219 Creating a GC9A01 device in firmware can then be done with the following API: 220 221 ```c 222 painter_device_t qp_gc9a01_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 223 ``` 224 225 The device handle returned from the `qp_gc9a01_make_spi_device` function can be used to perform all other drawing operations. 226 227 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 228 229 ```c 230 // 3 displays: 231 #define GC9A01_NUM_DEVICES 3 232 ``` 233 234 Native color format rgb565 is compatible with GC9A01 235 236 ==== ILI9163 237 238 Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`: 239 240 ```make 241 QUANTUM_PAINTER_ENABLE = yes 242 QUANTUM_PAINTER_DRIVERS += ili9163_spi 243 ``` 244 245 Creating a ILI9163 device in firmware can then be done with the following API: 246 247 ```c 248 painter_device_t qp_ili9163_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 249 ``` 250 251 The device handle returned from the `qp_ili9163_make_spi_device` function can be used to perform all other drawing operations. 252 253 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 254 255 ```c 256 // 3 displays: 257 #define ILI9163_NUM_DEVICES 3 258 ``` 259 260 Native color format rgb565 is compatible with ILI9163 261 262 ==== ILI9341 263 264 Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`: 265 266 ```make 267 QUANTUM_PAINTER_ENABLE = yes 268 QUANTUM_PAINTER_DRIVERS += ili9341_spi 269 ``` 270 271 Creating a ILI9341 device in firmware can then be done with the following API: 272 273 ```c 274 painter_device_t qp_ili9341_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 275 ``` 276 277 The device handle returned from the `qp_ili9341_make_spi_device` function can be used to perform all other drawing operations. 278 279 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 280 281 ```c 282 // 3 displays: 283 #define ILI9341_NUM_DEVICES 3 284 ``` 285 286 Native color format rgb565 is compatible with ILI9341 287 288 ==== ILI9486 289 290 Enabling support for the ILI9486 in Quantum Painter is done by adding the following to `rules.mk`: 291 292 ```make 293 QUANTUM_PAINTER_ENABLE = yes 294 QUANTUM_PAINTER_DRIVERS += ili9486_spi 295 ``` 296 297 Creating a ILI9486 device in firmware can then be done with the following API: 298 299 ```c 300 painter_device_t qp_ili9486_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 301 ``` 302 303 There's another variant for this [Waveshare module](https://www.waveshare.com/wiki/3.5inch_TFT_Touch_Shield), because it has a quirky SPI->Parallel converter. You can create it with: 304 305 ```c 306 painter_device_t qp_ili9486_make_spi_waveshare_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 307 ``` 308 309 The device handle returned from these functions can be used to perform all other drawing operations. 310 311 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 312 313 ```c 314 // 3 displays: 315 #define ILI9486_NUM_DEVICES 3 316 ``` 317 318 Native color format rgb888 is compatible with ILI9486 319 Native color format rgb565 is compatible with ILI9486 Waveshare 320 321 ==== ILI9488 322 323 Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`: 324 325 ```make 326 QUANTUM_PAINTER_ENABLE = yes 327 QUANTUM_PAINTER_DRIVERS += ili9488_spi 328 ``` 329 330 Creating a ILI9488 device in firmware can then be done with the following API: 331 332 ```c 333 painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 334 ``` 335 336 The device handle returned from the `qp_ili9488_make_spi_device` function can be used to perform all other drawing operations. 337 338 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 339 340 ```c 341 // 3 displays: 342 #define ILI9488_NUM_DEVICES 3 343 ``` 344 345 Native color format rgb888 is compatible with ILI9488 346 347 ==== ST7735 348 349 Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`: 350 351 ```make 352 QUANTUM_PAINTER_ENABLE = yes 353 QUANTUM_PAINTER_DRIVERS += st7735_spi 354 ``` 355 356 Creating a ST7735 device in firmware can then be done with the following API: 357 358 ```c 359 painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 360 ``` 361 362 The device handle returned from the `qp_st7735_make_spi_device` function can be used to perform all other drawing operations. 363 364 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 365 366 ```c 367 // 3 displays: 368 #define ST7735_NUM_DEVICES 3 369 ``` 370 371 Native color format rgb565 is compatible with ST7735 372 373 ::: warning 374 Some ST7735 devices are known to have different drawing offsets -- despite being a 132x162 pixel display controller internally, some display panels are only 80x160, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. 375 ::: 376 377 ==== ST7789 378 379 Enabling support for the ST7789 in Quantum Painter is done by adding the following to `rules.mk`: 380 381 ```make 382 QUANTUM_PAINTER_ENABLE = yes 383 QUANTUM_PAINTER_DRIVERS += st7789_spi 384 ``` 385 386 Creating a ST7789 device in firmware can then be done with the following API: 387 388 ```c 389 painter_device_t qp_st7789_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 390 ``` 391 392 The device handle returned from the `qp_st7789_make_spi_device` function can be used to perform all other drawing operations. 393 394 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 395 396 ```c 397 // 3 displays: 398 #define ST7789_NUM_DEVICES 3 399 ``` 400 401 Native color format rgb565 is compatible with ST7789 402 403 ::: warning 404 Some ST7789 devices are known to have different drawing offsets -- despite being a 240x320 pixel display controller internally, some display panels are only 240x240, or smaller. These may require an offset to be applied; see `qp_set_viewport_offsets` above for information on how to override the offsets if they aren't correctly rendered. 405 ::: 406 407 ::::: 408 409 ===== OLED 410 411 OLED displays tend to use 5-pin SPI when at larger resolutions, or when using color -- SPI SCK, SPI MOSI, SPI CS, D/C, and RST pins. Smaller OLEDs may use I2C instead. 412 413 When using these displays, either `spi_master` or `i2c_master` must already be correctly configured for both the platform and panel you're building for. 414 415 For SPI, the pin assignments for SPI CS, D/C, and RST are specified during device construction -- for I2C the panel's address is specified instead. 416 417 :::::tabs 418 419 ==== SSD1351 420 421 Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`: 422 423 ```make 424 QUANTUM_PAINTER_ENABLE = yes 425 QUANTUM_PAINTER_DRIVERS += ssd1351_spi 426 ``` 427 428 Creating a SSD1351 device in firmware can then be done with the following API: 429 430 ```c 431 painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 432 ``` 433 434 The device handle returned from the `qp_ssd1351_make_spi_device` function can be used to perform all other drawing operations. 435 436 The maximum number of displays can be configured by changing the following in your `config.h` (default is 1): 437 438 ```c 439 // 3 displays: 440 #define SSD1351_NUM_DEVICES 3 441 ``` 442 443 Native color format rgb565 is compatible with SSD1351 444 445 ==== SH1106 446 447 Enabling support for the SH1106 in Quantum Painter is done by adding the following to `rules.mk`: 448 449 ```make 450 QUANTUM_PAINTER_ENABLE = yes 451 # For SPI: 452 QUANTUM_PAINTER_DRIVERS += sh1106_spi 453 # For I2C: 454 QUANTUM_PAINTER_DRIVERS += sh1106_i2c 455 ``` 456 457 Creating a SH1106 device in firmware can then be done with the following APIs: 458 459 ```c 460 // SPI-based SH1106: 461 painter_device_t qp_sh1106_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 462 // I2C-based SH1106: 463 painter_device_t qp_sh1106_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address); 464 ``` 465 466 The device handle returned from the `qp_sh1106_make_???_device` function can be used to perform all other drawing operations. 467 468 The maximum number of displays of each type can be configured by changing the following in your `config.h` (default is 1): 469 470 ```c 471 // 3 SPI displays: 472 #define SH1106_NUM_SPI_DEVICES 3 473 // 3 I2C displays: 474 #define SH1106_NUM_I2C_DEVICES 3 475 ``` 476 477 Native color format mono2 is compatible with SH1106 478 479 ==== SSD1306 480 481 SSD1306 and SH1106 are almost entirely identical, to the point of being indisinguishable by Quantum Painter. Enable SH1106 support in Quantum Painter and create SH1106 devices in firmware to perform drawing operations on SSD1306 displays. 482 483 ==== LD7032 484 485 Enabling support for the LD7032 in Quantum Painter is done by adding the following to `rules.mk`: 486 487 ```make 488 QUANTUM_PAINTER_ENABLE = yes 489 # For SPI: 490 QUANTUM_PAINTER_DRIVERS += ld7032_spi 491 # For I2C: 492 QUANTUM_PAINTER_DRIVERS += ld7032_i2c 493 ``` 494 495 Creating a SH1106 device in firmware can then be done with the following APIs: 496 497 ```c 498 // SPI-based LD7032: 499 painter_device_t qp_ld7032_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode); 500 // I2C-based LD7032: 501 painter_device_t qp_ld7032_make_i2c_device(uint16_t panel_width, uint16_t panel_height, uint8_t i2c_address); 502 ``` 503 504 The device handle returned from the `qp_ld7032_make_???_device` function can be used to perform all other drawing operations. 505 506 The maximum number of displays of each type can be configured by changing the following in your `config.h` (default is 1): 507 508 ```c 509 // 3 SPI displays: 510 #define LD7032_NUM_SPI_DEVICES 3 511 // 3 I2C displays: 512 #define LD7032_NUM_I2C_DEVICES 3 513 ``` 514 515 Native color format mono2 is compatible with LD7032. 516 517 ::::: 518 519 ===== Surface 520 521 Quantum Painter has a surface driver which is able to target a buffer in RAM. In general, surfaces keep track of the "dirty" region -- the area that has been drawn to since the last flush -- so that when transferring to the display they can transfer the minimal amount of data to achieve the end result. 522 523 ::: warning 524 These generally require significant amounts of RAM, so at large sizes and/or higher bit depths, they may not be usable on all MCUs. 525 ::: 526 527 Enabling support for surfaces in Quantum Painter is done by adding the following to `rules.mk`: 528 529 ```make 530 QUANTUM_PAINTER_ENABLE = yes 531 QUANTUM_PAINTER_DRIVERS += surface 532 ``` 533 534 Creating a surface in firmware can then be done with the following APIs: 535 536 ```c 537 // 24bpp RGB888 surface: 538 painter_device_t qp_make_rgb888_surface(uint16_t panel_width, uint16_t panel_height, void *buffer); 539 // 16bpp RGB565 surface: 540 painter_device_t qp_make_rgb565_surface(uint16_t panel_width, uint16_t panel_height, void *buffer); 541 // 1bpp monochrome surface: 542 painter_device_t qp_make_mono1bpp_surface(uint16_t panel_width, uint16_t panel_height, void *buffer); 543 ``` 544 545 The `buffer` is a user-supplied area of memory, which can be statically allocated using `SURFACE_REQUIRED_BUFFER_BYTE_SIZE`: 546 547 ```c 548 // Buffer required for a 240x80 16bpp surface: 549 uint8_t framebuffer[SURFACE_REQUIRED_BUFFER_BYTE_SIZE(240, 80, 16)]; 550 ``` 551 552 The device handle returned from the `qp_make_?????_surface` function can be used to perform all other drawing operations. 553 554 Example: 555 556 ```c 557 static painter_device_t my_surface; 558 static uint8_t my_framebuffer[SURFACE_REQUIRED_BUFFER_BYTE_SIZE(240, 80, 16)]; // Allocate a buffer for a 16bpp 240x80 RGB565 display 559 void keyboard_post_init_kb(void) { 560 my_surface = qp_rgb565_make_surface(240, 80, my_framebuffer); 561 qp_init(my_surface, QP_ROTATION_0); 562 keyboard_post_init_user(); 563 } 564 ``` 565 566 The maximum number of surfaces can be configured by changing the following in your `config.h` (default is 1): 567 568 ```c 569 // 3 surfaces: 570 #define SURFACE_NUM_DEVICES 3 571 ``` 572 573 To transfer the contents of the surface to another display of the same pixel format, the following API can be invoked: 574 575 ```c 576 bool qp_surface_draw(painter_device_t surface, painter_device_t display, uint16_t x, uint16_t y, bool entire_surface); 577 ``` 578 579 The `surface` is the surface to copy out from. The `display` is the target display to draw into. `x` and `y` are the target location to draw the surface pixel data. Under normal circumstances, the location should be consistent, as the dirty region is calculated with respect to the `x` and `y` coordinates -- changing those will result in partial, overlapping draws. `entire_surface` whether the entire surface should be drawn, instead of just the dirty region. 580 581 ::: warning 582 The surface and display panel must have the same native pixel format. 583 ::: 584 585 ::: tip 586 Calling `qp_flush()` on the surface resets its dirty region. Copying the surface contents to the display also automatically resets the dirty region. 587 ::: 588 589 :::::: 590 591 ## Quantum Painter Drawing API {#quantum-painter-api} 592 593 All APIs require a `painter_device_t` object as their first parameter -- this object comes from the specific device initialisation, and instructions on creating it can be found in each driver's respective section. 594 595 To use any of the APIs, you need to include `qp.h`: 596 ```c 597 #include <qp.h> 598 ``` 599 600 ::::::tabs 601 602 ===== General Notes 603 604 The coordinate system used in Quantum Painter generally accepts `left`, `top`, `right`, and `bottom` instead of x/y/width/height, and each coordinate is inclusive of where pixels should be drawn. This is required as some datatypes used by display panels have a maximum value of `255` -- for any value or geometry extent that matches `256`, this would be represented as a `0`, instead. 605 606 ::: tip 607 Drawing a horizontal line 8 pixels long, starting from 4 pixels inside the left side of the display, will need `left=4`, `right=11`. 608 ::: 609 610 All color data matches the standard QMK HSV triplet definitions: 611 612 * Hue is of the range `0...255` and is internally mapped to 0...360 degrees. 613 * Saturation is of the range `0...255` and is internally mapped to 0...100% saturation. 614 * Value is of the range `0...255` and is internally mapped to 0...100% brightness. 615 616 ::: tip 617 Colors used in Quantum Painter are not subject to the RGB lighting CIE curve, if it is enabled. 618 ::: 619 620 ===== Device Control 621 622 :::::tabs 623 624 ==== Display Initialisation 625 626 ```c 627 bool qp_init(painter_device_t device, painter_rotation_t rotation); 628 ``` 629 630 The `qp_init` function is used to initialise a display device after it has been created. This accepts a rotation parameter (`QP_ROTATION_0`, `QP_ROTATION_90`, `QP_ROTATION_180`, `QP_ROTATION_270`), which makes sure that the orientation of what's drawn on the display is correct. 631 632 ```c 633 static painter_device_t display; 634 void keyboard_post_init_kb(void) { 635 display = qp_make_.......; // Create the display 636 qp_init(display, QP_ROTATION_0); // Initialise the display 637 } 638 ``` 639 640 ==== Display Power 641 642 ```c 643 bool qp_power(painter_device_t device, bool power_on); 644 ``` 645 646 The `qp_power` function instructs the display whether or not the display panel should be on or off. 647 648 ::: warning 649 If there is a separate backlight controlled through the normal QMK backlight API, this is not controlled by the `qp_power` function and needs to be manually handled elsewhere. 650 ::: 651 652 ```c 653 static uint8_t last_backlight = 255; 654 void suspend_power_down_user(void) { 655 if (last_backlight == 255) { 656 last_backlight = get_backlight_level(); 657 } 658 backlight_set(0); 659 rgb_matrix_set_suspend_state(true); 660 qp_power(display, false); 661 } 662 663 void suspend_wakeup_init_user(void) { 664 qp_power(display, true); 665 rgb_matrix_set_suspend_state(false); 666 if (last_backlight != 255) { 667 backlight_set(last_backlight); 668 } 669 last_backlight = 255; 670 } 671 ``` 672 673 ==== Display Clear 674 675 ```c 676 bool qp_clear(painter_device_t device); 677 ``` 678 679 The `qp_clear` function clears the display's screen. 680 681 ==== Display Flush 682 683 ```c 684 bool qp_flush(painter_device_t device); 685 ``` 686 687 The `qp_flush` function ensures that all drawing operations are "pushed" to the display. This should be done as the last operation whenever a sequence of draws occur, and guarantees that any changes are applied. 688 689 ::: warning 690 Some display panels may seem to work even without a call to `qp_flush` -- this may be because the driver cannot queue drawing operations and needs to display them immediately when invoked. In general, calling `qp_flush` at the end is still considered "best practice". 691 ::: 692 693 ```c 694 void housekeeping_task_user(void) { 695 static uint32_t last_draw = 0; 696 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 697 last_draw = timer_read32(); 698 // Draw a rect based off the current RGB color 699 qp_rect(display, 0, 7, 0, 239, rgb_matrix_get_hue(), 255, 255); 700 qp_flush(display); 701 } 702 } 703 ``` 704 705 ::::: 706 707 ===== Drawing Primitives 708 709 :::::tabs 710 711 ==== Set Pixel 712 713 ```c 714 bool qp_setpixel(painter_device_t device, uint16_t x, uint16_t y, uint8_t hue, uint8_t sat, uint8_t val); 715 ``` 716 717 The `qp_setpixel` can be used to set a specific pixel on the screen to the supplied color. 718 719 ::: tip 720 Using `qp_setpixel` for large amounts of drawing operations is inefficient and should be avoided unless they cannot be achieved with other drawing APIs. 721 ::: 722 723 ```c 724 void housekeeping_task_user(void) { 725 static uint32_t last_draw = 0; 726 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 727 last_draw = timer_read32(); 728 // Draw a 240px high vertical rainbow line on X=0: 729 for (int i = 0; i < 239; ++i) { 730 qp_setpixel(display, 0, i, i, 255, 255); 731 } 732 qp_flush(display); 733 } 734 } 735 ``` 736 737 ==== Draw Line 738 739 ```c 740 bool qp_line(painter_device_t device, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t hue, uint8_t sat, uint8_t val); 741 ``` 742 743 The `qp_line` can be used to draw lines on the screen with the supplied color. 744 745 ```c 746 void housekeeping_task_user(void) { 747 static uint32_t last_draw = 0; 748 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 749 last_draw = timer_read32(); 750 // Draw 8px-wide rainbow down the left side of the display 751 for (int i = 0; i < 239; ++i) { 752 qp_line(display, 0, i, 7, i, i, 255, 255); 753 } 754 qp_flush(display); 755 } 756 } 757 ``` 758 759 ==== Draw Rect 760 761 ```c 762 bool qp_rect(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom, uint8_t hue, uint8_t sat, uint8_t val, bool filled); 763 ``` 764 765 The `qp_rect` can be used to draw rectangles on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the rectangle will be left as-is. 766 767 ```c 768 void housekeeping_task_user(void) { 769 static uint32_t last_draw = 0; 770 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 771 last_draw = timer_read32(); 772 // Draw 8px-wide rainbow filled rectangles down the left side of the display 773 for (int i = 0; i < 239; i+=8) { 774 qp_rect(display, 0, i, 7, i+7, i, 255, 255, true); 775 } 776 qp_flush(display); 777 } 778 } 779 ``` 780 781 ==== Draw Circle 782 783 ```c 784 bool qp_circle(painter_device_t device, uint16_t x, uint16_t y, uint16_t radius, uint8_t hue, uint8_t sat, uint8_t val, bool filled); 785 ``` 786 787 The `qp_circle` can be used to draw circles on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the circle will be left as-is. 788 789 ```c 790 void housekeeping_task_user(void) { 791 static uint32_t last_draw = 0; 792 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 793 last_draw = timer_read32(); 794 // Draw r=4 filled circles down the left side of the display 795 for (int i = 0; i < 239; i+=8) { 796 qp_circle(display, 4, 4+i, 4, i, 255, 255, true); 797 } 798 qp_flush(display); 799 } 800 } 801 ``` 802 803 ==== Draw Ellipse 804 805 ```c 806 bool qp_ellipse(painter_device_t device, uint16_t x, uint16_t y, uint16_t sizex, uint16_t sizey, uint8_t hue, uint8_t sat, uint8_t val, bool filled); 807 ``` 808 809 The `qp_ellipse` can be used to draw ellipses on the screen with the supplied color, with or without a background fill. If not filled, any pixels inside the ellipses will be left as-is. 810 811 ```c 812 void housekeeping_task_user(void) { 813 static uint32_t last_draw = 0; 814 if (timer_elapsed32(last_draw) > 33) { // Throttle to 30fps 815 last_draw = timer_read32(); 816 // Draw 16x8 filled ellipses down the left side of the display 817 for (int i = 0; i < 239; i+=8) { 818 qp_ellipse(display, 8, 4+i, 16, 8, i, 255, 255, true); 819 } 820 qp_flush(display); 821 } 822 } 823 ``` 824 825 ::::: 826 827 ===== Image Functions 828 829 Making an image available for use requires compiling it into your firmware. To do so, assuming you've created `my_image.qgf.c` and `my_image.qgf.h` as per the CLI examples above, you'd add the following to your `rules.mk`: 830 831 ```make 832 SRC += my_image.qgf.c 833 ``` 834 835 ...and in your `keymap.c`, you'd add to the top of the file: 836 ```c 837 #include "my_image.qgf.h" 838 ``` 839 840 :::::tabs 841 842 ==== Load Image 843 844 ```c 845 painter_image_handle_t qp_load_image_mem(const void *buffer); 846 ``` 847 848 The `qp_load_image_mem` function loads a QGF image from memory or flash. 849 850 `qp_load_image_mem` returns a handle to the loaded image, which can then be used to draw to the screen using `qp_drawimage`, `qp_drawimage_recolor`, `qp_animate`, or `qp_animate_recolor`. If an image is no longer required, it can be unloaded by calling `qp_close_image` below. 851 852 See the [CLI Commands](quantum_painter#quantum-painter-cli) for instructions on how to convert images to [QGF](quantum_painter_qgf). 853 854 ::: tip 855 The total number of images available to load at any one time is controlled by the configurable option `QUANTUM_PAINTER_NUM_IMAGES` in the table above. If more images are required, the number should be increased in `config.h`. 856 ::: 857 858 Image information is available through accessing the handle: 859 860 | Property | Accessor | 861 |-------------|----------------------| 862 | Width | `image->width` | 863 | Height | `image->height` | 864 | Frame Count | `image->frame_count` | 865 866 ==== Unload Image 867 868 ```c 869 bool qp_close_image(painter_image_handle_t image); 870 ``` 871 872 The `qp_close_image` function releases resources related to the loading of the supplied image. 873 874 ==== Draw image 875 876 ```c 877 bool qp_drawimage(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image); 878 bool qp_drawimage_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg); 879 ``` 880 881 The `qp_drawimage` and `qp_drawimage_recolor` functions draw the supplied image to the screen at the supplied location, with the latter function allowing for monochrome-based images to be recolored. 882 883 ```c 884 // Draw an image on the bottom-right of the 240x320 display on initialisation 885 static painter_image_handle_t my_image; 886 void keyboard_post_init_kb(void) { 887 my_image = qp_load_image_mem(gfx_my_image); 888 if (my_image != NULL) { 889 qp_drawimage(display, (240 - my_image->width), (320 - my_image->height), my_image); 890 } 891 } 892 ``` 893 894 ==== Animate Image 895 896 ```c 897 deferred_token qp_animate(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image); 898 deferred_token qp_animate_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_image_handle_t image, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg); 899 ``` 900 901 The `qp_animate` and `qp_animate_recolor` functions draw the supplied image to the screen at the supplied location, with the latter function allowing for monochrome-based animations to be recolored. They also set up internal timing such that each frame is rendered at the correct time as per the animated image. 902 903 Once an image has been set to animate, it will loop indefinitely until stopped, with no user intervention required. 904 905 Both functions return a `deferred_token`, which can then be used to stop the animation, using `qp_stop_animation` below. 906 907 ```c 908 // Animate an image on the bottom-right of the 240x320 display on initialisation 909 static painter_image_handle_t my_image; 910 static deferred_token my_anim; 911 void keyboard_post_init_kb(void) { 912 my_image = qp_load_image_mem(gfx_my_image); 913 if (my_image != NULL) { 914 my_anim = qp_animate(display, (240 - my_image->width), (320 - my_image->height), my_image); 915 } 916 } 917 ``` 918 919 ==== Stop Animation 920 921 ```c 922 void qp_stop_animation(deferred_token anim_token); 923 ``` 924 925 The `qp_stop_animation` function stops the previously-started animation. 926 ```c 927 void housekeeping_task_user(void) { 928 if (some_random_stop_reason) { 929 qp_stop_animation(my_anim); 930 } 931 } 932 ``` 933 934 ::::: 935 936 ===== Font Functions 937 938 Making a font available for use requires compiling it into your firmware. To do so, assuming you've created `my_font.qff.c` and `my_font.qff.h` as per the CLI examples above, you'd add the following to your `rules.mk`: 939 940 ```make 941 SRC += noto11.qff.c 942 ``` 943 944 ...and in your `keymap.c`, you'd add to the top of the file: 945 ```c 946 #include "noto11.qff.h" 947 ``` 948 949 :::::tabs 950 951 ==== Load Font 952 953 ```c 954 painter_font_handle_t qp_load_font_mem(const void *buffer); 955 ``` 956 957 The `qp_load_font_mem` function loads a QFF font from memory or flash. 958 959 `qp_load_font_mem` returns a handle to the loaded font, which can then be measured using `qp_textwidth`, or drawn to the screen using `qp_drawtext`, or `qp_drawtext_recolor`. If a font is no longer required, it can be unloaded by calling `qp_close_font` below. 960 961 See the [CLI Commands](quantum_painter#quantum-painter-cli) for instructions on how to convert TTF fonts to [QFF](quantum_painter_qff). 962 963 ::: tip 964 The total number of fonts available to load at any one time is controlled by the configurable option `QUANTUM_PAINTER_NUM_FONTS` in the table above. If more fonts are required, the number should be increased in `config.h`. 965 ::: 966 967 Font information is available through accessing the handle: 968 969 | Property | Accessor | 970 |-------------|----------------------| 971 | Line Height | `image->line_height` | 972 973 ==== Unload Font 974 975 ```c 976 bool qp_close_font(painter_font_handle_t font); 977 ``` 978 979 The `qp_close_font` function releases resources related to the loading of the supplied font. 980 981 ==== Measure Text 982 983 ```c 984 int16_t qp_textwidth(painter_font_handle_t font, const char *str); 985 ``` 986 987 The `qp_textwidth` function allows measurement of how many pixels wide the supplied string would result in, for the given font. 988 989 ==== Draw Text 990 991 ```c 992 int16_t qp_drawtext(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str); 993 int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, painter_font_handle_t font, const char *str, uint8_t hue_fg, uint8_t sat_fg, uint8_t val_fg, uint8_t hue_bg, uint8_t sat_bg, uint8_t val_bg); 994 ``` 995 996 The `qp_drawtext` and `qp_drawtext_recolor` functions draw the supplied string to the screen at the given location using the font supplied, with the latter function allowing for monochrome-based fonts to be recolored. 997 998 ```c 999 // Draw a text message on the bottom-right of the 240x320 display on initialisation 1000 static painter_font_handle_t my_font; 1001 void keyboard_post_init_kb(void) { 1002 my_font = qp_load_font_mem(font_noto11); 1003 if (my_font != NULL) { 1004 static const char *text = "Hello from QMK!"; 1005 int16_t width = qp_textwidth(my_font, text); 1006 qp_drawtext(display, (240 - width), (320 - my_font->line_height), my_font, text); 1007 } 1008 } 1009 ``` 1010 1011 ::::: 1012 1013 ===== Advanced Functions 1014 1015 :::::tabs 1016 1017 ==== Getters 1018 1019 These functions allow external code to retrieve the current width, height, rotation, and drawing offsets. 1020 1021 ::::tabs 1022 1023 === Width 1024 1025 ```c 1026 uint16_t qp_get_width(painter_device_t device); 1027 ``` 1028 1029 === Height 1030 1031 ```c 1032 uint16_t qp_get_height(painter_device_t device); 1033 ``` 1034 1035 === Rotation 1036 1037 ```c 1038 painter_rotation_t qp_get_rotation(painter_device_t device); 1039 ``` 1040 1041 === Offset X 1042 1043 ```c 1044 uint16_t qp_get_offset_x(painter_device_t device); 1045 ``` 1046 1047 === Offset Y 1048 1049 ```c 1050 uint16_t qp_get_offset_y(painter_device_t device); 1051 ``` 1052 1053 === Everything 1054 1055 Convenience function to call all the previous ones at once. 1056 Note: You can pass `NULL` for the values you are not interested in. 1057 1058 ```c 1059 void qp_get_geometry(painter_device_t device, uint16_t *width, uint16_t *height, painter_rotation_t *rotation, uint16_t *offset_x, uint16_t *offset_y); 1060 ``` 1061 1062 :::: 1063 1064 ==== Set Viewport Offsets 1065 1066 ```c 1067 void qp_set_viewport_offsets(painter_device_t device, uint16_t offset_x, uint16_t offset_y); 1068 ``` 1069 1070 The `qp_set_viewport_offsets` function can be used to offset all subsequent drawing operations. For example, if a display controller is internally 240x320, but the display panel is 240x240 and has a Y offset of 80 pixels, you could invoke `qp_set_viewport_offsets(display, 0, 80);` and the drawing positioning would be corrected. 1071 1072 ==== Set Viewport 1073 1074 ```c 1075 bool qp_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom); 1076 ``` 1077 1078 The `qp_viewport` function controls where raw pixel data is written to. 1079 1080 ==== Stream Pixel Data 1081 1082 ```c 1083 bool qp_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count); 1084 ``` 1085 1086 The `qp_pixdata` function allows raw pixel data to be streamed to the display. It requires a native pixel count rather than the number of bytes to transfer, to ensure display panel data alignment is respected. E.g. for display panels using RGB565 internal format, sending 10 pixels will result in 20 bytes of transfer. 1087 1088 ::: warning 1089 Under normal circumstances, users will not need to manually call either `qp_viewport` or `qp_pixdata`. These allow for writing of raw pixel information, in the display panel's native format, to the area defined by the viewport. 1090 ::: 1091 1092 ::::: 1093 1094 ::::::