mirror of
https://github.com/qmk/qmk_firmware.git
synced 2024-11-25 20:56:42 +00:00
Compare commits
3 Commits
2017ffa59a
...
5594a5153b
Author | SHA1 | Date | |
---|---|---|---|
|
5594a5153b | ||
|
45851a10f6 | ||
|
03c47d295e |
@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Versions and identifiers
|
// Versions and identifiers
|
||||||
@ -15,119 +16,119 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Response flag definitions
|
// Response flag definitions
|
||||||
|
|
||||||
{% for bit,data in xap.response_flags.bits | dictsort -%}
|
{% for bit,data in xap.response_flags.bits | dictsort %}
|
||||||
#define {{ xap.response_flags.define_prefix }}_{{ data.define | to_snake | upper }} (UINT32_C(1) << ({{ bit }}))
|
#define {{ xap.response_flags.define_prefix }}_{{ data.define | to_snake | upper }} (UINT32_C(1) << ({{ bit }}))
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
#define {{ xap.response_flags.define_prefix }}_FAILED 0x00
|
#define {{ xap.response_flags.define_prefix }}_FAILED 0x00
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Broadcast message definitions
|
// Broadcast message definitions
|
||||||
|
|
||||||
{% for message_id,data in xap.broadcast_messages.messages | dictsort -%}
|
{% for message_id,data in xap.broadcast_messages.messages | dictsort %}
|
||||||
#define {{ xap.broadcast_messages.define_prefix }}_{{ data.define | to_snake | upper }} {{ message_id }}
|
#define {{ xap.broadcast_messages.define_prefix }}_{{ data.define | to_snake | upper }} {{ message_id }}
|
||||||
{% if 'return_type' in data -%}
|
{% if 'return_type' in data %}
|
||||||
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}({{ data.return_type | type_to_c('value') }});
|
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}({{ data.return_type | type_to_c('value') }});
|
||||||
{% else -%}
|
{% else %}
|
||||||
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}(const void *data, size_t length);
|
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}(const void *data, size_t length);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
#define XAP_BROADCAST_TOKEN 0xFFFF
|
#define XAP_BROADCAST_TOKEN 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Type definitions
|
// Type definitions
|
||||||
|
|
||||||
{% for name,data in xap.type_definitions | dictsort -%}
|
{% for name,data in xap.type_definitions | dictsort %}
|
||||||
{% if data.type != 'struct' -%}
|
{% if data.type != 'struct' %}
|
||||||
typedef {{ data.type | type_to_c('xap_'+(name|to_snake|lower)+'_t') }};
|
typedef {{ data.type | type_to_c('xap_'+(name|to_snake|lower)+'_t') }};
|
||||||
{% endif -%}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{%- for name,data in xap.type_definitions | dictsort %}
|
{% for name,data in xap.type_definitions | dictsort %}
|
||||||
{% if data.type == 'struct' -%}
|
{% if data.type == 'struct' %}
|
||||||
typedef struct {
|
typedef struct {
|
||||||
{%- for member in data.struct_members %}
|
{% for member in data.struct_members %}
|
||||||
{{ member.type | type_to_c(member.name) }};
|
{{ member.type | type_to_c(member.name) }};
|
||||||
{%- endfor %}
|
{% endfor %}
|
||||||
} __attribute__((__packed__)) xap_{{ name | to_snake | lower }}_t{{ data.type | type_to_c_after }};
|
} __attribute__((__packed__)) xap_{{ name | to_snake | lower }}_t{{ data.type | type_to_c_after }};
|
||||||
_Static_assert(sizeof(xap_{{ name | to_snake | lower }}_t) == {{ data.struct_length }}, "xap_{{ name | to_snake | lower }}_t needs to be {{ data.struct_length }} bytes in size");
|
_Static_assert(sizeof(xap_{{ name | to_snake | lower }}_t) == {{ data.struct_length }}, "xap_{{ name | to_snake | lower }}_t needs to be {{ data.struct_length }} bytes in size");
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Route definitions
|
// Route definitions
|
||||||
|
|
||||||
{% macro export_route_types(prefix, container) -%}
|
{% macro export_route_types(prefix, container) %}
|
||||||
{%- if 'routes' in container -%}
|
{% if 'routes' in container %}
|
||||||
{% for route, data in container.routes | dictsort -%}
|
{% for route, data in container.routes | dictsort %}
|
||||||
{%- set this_prefix_uc = (prefix + '_' + data.define) | upper -%}
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
{%- set this_prefix_lc = this_prefix_uc | lower -%}
|
{% set this_prefix_lc = this_prefix_uc | lower %}
|
||||||
|
|
||||||
{% if 'request_struct_members' in data -%}
|
{% if 'request_struct_members' in data %}
|
||||||
typedef struct {
|
typedef struct {
|
||||||
{%- for member in data.request_struct_members %}
|
{% for member in data.request_struct_members %}
|
||||||
{{ member.type | type_to_c(member.name|lower) }};
|
{{ member.type | type_to_c(member.name|lower) }};
|
||||||
{%- endfor %}
|
{% endfor %}
|
||||||
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_arg_t;
|
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_arg_t;
|
||||||
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_arg_t) == {{ data.request_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_arg_t needs to be {{ data.request_struct_length }} bytes in size");
|
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_arg_t) == {{ data.request_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_arg_t needs to be {{ data.request_struct_length }} bytes in size");
|
||||||
{% elif 'request_type' in data -%}
|
{% elif 'request_type' in data %}
|
||||||
typedef {{ data.request_type | type_to_c(this_prefix_lc+'_arg_t') }};
|
typedef {{ data.request_type | type_to_c(this_prefix_lc+'_arg_t') }};
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
|
|
||||||
{%- if 'return_struct_members' in data -%}
|
{% if 'return_struct_members' in data %}
|
||||||
typedef struct {
|
typedef struct {
|
||||||
{%- for member in data.return_struct_members %}
|
{% for member in data.return_struct_members %}
|
||||||
{{ member.type | type_to_c(member.name|lower) }};
|
{{ member.type | type_to_c(member.name|lower) }};
|
||||||
{%- endfor %}
|
{% endfor %}
|
||||||
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_t;
|
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_t;
|
||||||
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_t) == {{ data.return_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_t needs to be {{ data.return_struct_length }} bytes in size");
|
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_t) == {{ data.return_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_t needs to be {{ data.return_struct_length }} bytes in size");
|
||||||
{%- elif 'return_type' in data -%}
|
{% elif 'return_type' in data %}
|
||||||
{%- if '[' in data.return_type %}
|
{% if '[' in data.return_type %}
|
||||||
typedef struct __attribute__((__packed__)) { {{ data.return_type | type_to_c('x') }}; } {{ this_prefix_lc }}_t;
|
typedef struct __attribute__((__packed__)) { {{ data.return_type | type_to_c('x') }}; } {{ this_prefix_lc }}_t;
|
||||||
{%- else -%}
|
{% else %}
|
||||||
typedef {{ data.return_type | type_to_c(this_prefix_lc+'_t') }};
|
typedef {{ data.return_type | type_to_c(this_prefix_lc+'_t') }};
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
|
|
||||||
{%- endif %}
|
{% endif %}
|
||||||
{{ export_route_types(this_prefix_lc, data) }}
|
{{ export_route_types(this_prefix_lc, data) }}
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
{%- endmacro -%}
|
{% endmacro %}
|
||||||
|
|
||||||
{{ export_route_types('xap_route', xap) }}
|
{{ export_route_types('xap_route', xap) }}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Capabilities IDs
|
// Capabilities IDs
|
||||||
|
|
||||||
{% macro export_route_ids(prefix, container) -%}
|
{% macro export_route_ids(prefix, container) %}
|
||||||
{%- if 'routes' in container -%}
|
{% if 'routes' in container %}
|
||||||
{% for route, data in container.routes | dictsort -%}
|
{% for route, data in container.routes | dictsort %}
|
||||||
{%- set this_prefix_uc = (prefix + '_' + data.define) | upper -%}
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
{%- set this_prefix_lc = this_prefix_uc | lower -%}
|
{% set this_prefix_lc = this_prefix_uc | lower %}
|
||||||
#define {{ this_prefix_uc }} {{ route }}
|
#define {{ this_prefix_uc }} {{ route }}
|
||||||
{{ export_route_ids(this_prefix_uc, data) }}
|
{{ export_route_ids(this_prefix_uc, data) }}
|
||||||
{%- endfor -%}
|
{% endfor %}
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
{%- endmacro -%}
|
{% endmacro %}
|
||||||
|
|
||||||
{{ export_route_ids('XAP_ROUTE', xap) }}
|
{{ export_route_ids('XAP_ROUTE', xap) }}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Capabilities Masks
|
// Capabilities Masks
|
||||||
|
|
||||||
{% macro export_route_masks(prefix, container, preprocessor_condition) -%}
|
{% macro export_route_masks(prefix, container, preprocessor_condition) %}
|
||||||
{%- if 'routes' in container -%}
|
{% if 'routes' in container %}
|
||||||
{% for route, data in container.routes | dictsort -%}
|
{% for route, data in container.routes | dictsort %}
|
||||||
{%- set this_prefix_uc = (prefix + '_' + data.define) | upper -%}
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
{%- set this_prefix_lc = this_prefix_uc | lower -%}
|
{% set this_prefix_lc = this_prefix_uc | lower %}
|
||||||
{% if 'enable_if_preprocessor' in data %}
|
{% if 'enable_if_preprocessor' in data %}
|
||||||
{% if preprocessor_condition == 'TRUE' %}
|
{% if preprocessor_condition == 'TRUE' %}
|
||||||
{%- set condition = "(" + data.enable_if_preprocessor + ")" -%}
|
{% set condition = "(" + data.enable_if_preprocessor + ")" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{%- set condition = "(" + preprocessor_condition + " && (" + data.enable_if_preprocessor + "))" -%}
|
{% set condition = "(" + preprocessor_condition + " && (" + data.enable_if_preprocessor + "))" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{%- set condition = preprocessor_condition -%}
|
{% set condition = preprocessor_condition %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if condition == 'TRUE' %}
|
{% if condition == 'TRUE' %}
|
||||||
#define {{ this_prefix_uc }}_MASK (UINT32_C(1) << ({{ this_prefix_uc }}))
|
#define {{ this_prefix_uc }}_MASK (UINT32_C(1) << ({{ this_prefix_uc }}))
|
||||||
@ -139,28 +140,28 @@ typedef {{ data.return_type | type_to_c(this_prefix_lc+'_t') }};
|
|||||||
#endif // ({{ condition }})
|
#endif // ({{ condition }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ export_route_masks(this_prefix_uc, data, condition) }}
|
{{ export_route_masks(this_prefix_uc, data, condition) }}
|
||||||
{%- endfor -%}
|
{% endfor %}
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
{%- endmacro -%}
|
{% endmacro %}
|
||||||
|
|
||||||
{{ export_route_masks('XAP_ROUTE', xap, 'TRUE') }}
|
{{ export_route_masks('XAP_ROUTE', xap, 'TRUE') }}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Capabilities Values
|
// Capabilities Values
|
||||||
|
|
||||||
{% macro export_route_capabilities(prefix, container) -%}
|
{% macro export_route_capabilities(prefix, container) %}
|
||||||
{%- if 'routes' in container -%}
|
{% if 'routes' in container %}
|
||||||
#define {{ prefix }}_CAPABILITIES (0 \
|
#define {{ prefix }}_CAPABILITIES (0 \
|
||||||
{% for route, data in container.routes | dictsort -%}
|
{% for route, data in container.routes | dictsort %}
|
||||||
{%- set this_prefix_uc = (prefix + '_' + data.define) | upper -%}
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
| ({{ this_prefix_uc }}_MASK) \
|
| ({{ this_prefix_uc }}_MASK) \
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
)
|
)
|
||||||
{% for route, data in container.routes | dictsort -%}
|
{% for route, data in container.routes | dictsort %}
|
||||||
{%- set this_prefix_uc = (prefix + '_' + data.define) | upper -%}
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
{{ export_route_capabilities(this_prefix_uc, data) }}
|
{{ export_route_capabilities(this_prefix_uc, data) }}
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
{%- endif -%}
|
{% endif %}
|
||||||
{%- endmacro -%}
|
{% endmacro %}
|
||||||
|
|
||||||
{{ export_route_capabilities('XAP_ROUTE', xap) }}
|
{{ export_route_capabilities('XAP_ROUTE', xap) }}
|
||||||
|
@ -4,6 +4,32 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Full XAP {{ xap.version }} definitions
|
// Full XAP {{ xap.version }} definitions
|
||||||
|
|
||||||
|
{% for message_id,data in xap.broadcast_messages.messages | dictsort %}
|
||||||
|
{% if 'return_type' in data %}
|
||||||
|
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}({{ data.return_type | type_to_c('value') }}) { xap_broadcast({{ message_id }}, &value, sizeof(value)); }
|
||||||
|
{% else %}
|
||||||
|
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}(const void *data, size_t length) { xap_broadcast({{ message_id }}, data, length); }
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% macro append_routing_table(prefix, container, route_stack) %}
|
||||||
|
{% set this_route_stack = route_stack.copy() %}
|
||||||
|
{{ this_route_stack.append(container) }}
|
||||||
|
{% set stack_names = this_route_stack | map(attribute='name') | join(', ') %}
|
||||||
|
Stack names: {{ stack_names }}
|
||||||
|
{% if 'routes' in container %}
|
||||||
|
{% for route, data in container.routes | dictsort %}
|
||||||
|
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
|
||||||
|
{% set this_prefix_lc = this_prefix_uc | lower %}
|
||||||
|
{{ append_routing_table(this_prefix_lc, data, this_route_stack) }}
|
||||||
|
Inner route prefix for {{ prefix }}: {{ this_prefix_lc }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
Prefix: {{ prefix }}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{{ append_routing_table("xap_route", xap, []) }}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{{ xap | tojson(4) }}
|
{{ xap | tojson(indent=4) }}
|
||||||
#endif
|
#endif
|
@ -33,13 +33,14 @@ Supported devices:
|
|||||||
## Quantum Painter Configuration :id=quantum-painter-config
|
## Quantum Painter Configuration :id=quantum-painter-config
|
||||||
|
|
||||||
| Option | Default | Purpose |
|
| Option | Default | Purpose |
|
||||||
|-----------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
|
| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
|
||||||
| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
|
| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
|
||||||
| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
|
| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
|
||||||
| `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. |
|
| `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. |
|
||||||
| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | 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. |
|
| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | 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. |
|
||||||
| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
|
| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
|
||||||
|
| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. |
|
||||||
| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
|
| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
|
||||||
|
|
||||||
Drivers have their own set of configurable options, and are described in their respective sections.
|
Drivers have their own set of configurable options, and are described in their respective sections.
|
||||||
@ -63,7 +64,7 @@ options:
|
|||||||
-d, --no-deltas Disables the use of delta frames when encoding animations.
|
-d, --no-deltas Disables the use of delta frames when encoding animations.
|
||||||
-r, --no-rle Disables the use of RLE when encoding images.
|
-r, --no-rle Disables the use of RLE when encoding images.
|
||||||
-f FORMAT, --format FORMAT
|
-f FORMAT, --format FORMAT
|
||||||
Output format, valid types: pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
|
Output format, valid types: rgb888, rgb565, pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
|
||||||
-o OUTPUT, --output OUTPUT
|
-o OUTPUT, --output OUTPUT
|
||||||
Specify output directory. Defaults to same directory as input.
|
Specify output directory. Defaults to same directory as input.
|
||||||
-i INPUT, --input INPUT
|
-i INPUT, --input INPUT
|
||||||
@ -78,7 +79,9 @@ The `OUTPUT` argument needs to be a directory, and will default to the same dire
|
|||||||
The `FORMAT` argument can be any of the following:
|
The `FORMAT` argument can be any of the following:
|
||||||
|
|
||||||
| Format | Meaning |
|
| Format | Meaning |
|
||||||
|-----------|-----------------------------------------------------------------------|
|
|-----------|-------------------------------------------------------------------------------------------|
|
||||||
|
| `rgb888` | 16,777,216 colors in 8-8-8 RGB format (requires `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS`) |
|
||||||
|
| `rgb565` | 65,536 colors in 5-6-5 RGB format (requires `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS`) |
|
||||||
| `pal256` | 256-color palette (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) |
|
| `pal256` | 256-color palette (requires `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`) |
|
||||||
| `pal16` | 16-color palette |
|
| `pal16` | 16-color palette |
|
||||||
| `pal4` | 4-color palette |
|
| `pal4` | 4-color palette |
|
||||||
@ -154,7 +157,7 @@ options:
|
|||||||
-w, --raw Writes out the QFF file as raw data instead of c/h combo.
|
-w, --raw Writes out the QFF file as raw data instead of c/h combo.
|
||||||
-r, --no-rle Disable the use of RLE to minimise converted image size.
|
-r, --no-rle Disable the use of RLE to minimise converted image size.
|
||||||
-f FORMAT, --format FORMAT
|
-f FORMAT, --format FORMAT
|
||||||
Output format, valid types: pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
|
Output format, valid types: rgb565, pal256, pal16, pal4, pal2, mono256, mono16, mono4, mono2
|
||||||
-u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS
|
-u UNICODE_GLYPHS, --unicode-glyphs UNICODE_GLYPHS
|
||||||
Also generate the specified unicode glyphs.
|
Also generate the specified unicode glyphs.
|
||||||
-n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified.
|
-n, --no-ascii Disables output of the full ASCII character set (0x20..0x7E), exporting only the glyphs specified.
|
||||||
@ -215,6 +218,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define GC9A01_NUM_DEVICES 3
|
#define GC9A01_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with GC9A01
|
||||||
|
|
||||||
#### ** ILI9163 **
|
#### ** ILI9163 **
|
||||||
|
|
||||||
Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`:
|
Enabling support for the ILI9163 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||||
@ -239,6 +244,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define ILI9163_NUM_DEVICES 3
|
#define ILI9163_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with ILI9163
|
||||||
|
|
||||||
#### ** ILI9341 **
|
#### ** ILI9341 **
|
||||||
|
|
||||||
Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`:
|
Enabling support for the ILI9341 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||||
@ -263,6 +270,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define ILI9341_NUM_DEVICES 3
|
#define ILI9341_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with ILI9341
|
||||||
|
|
||||||
#### ** ILI9488 **
|
#### ** ILI9488 **
|
||||||
|
|
||||||
Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`:
|
Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||||
@ -287,6 +296,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define ILI9488_NUM_DEVICES 3
|
#define ILI9488_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb888 is compatible with ILI9488
|
||||||
|
|
||||||
#### ** SSD1351 **
|
#### ** SSD1351 **
|
||||||
|
|
||||||
Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
|
Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||||
@ -311,6 +322,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define SSD1351_NUM_DEVICES 3
|
#define SSD1351_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with SSD1351
|
||||||
|
|
||||||
#### ** ST7735 **
|
#### ** ST7735 **
|
||||||
|
|
||||||
Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`:
|
Enabling support for the ST7735 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||||
@ -335,6 +348,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define ST7735_NUM_DEVICES 3
|
#define ST7735_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with ST7735
|
||||||
|
|
||||||
!> 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.
|
!> 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.
|
||||||
|
|
||||||
#### ** ST7789 **
|
#### ** ST7789 **
|
||||||
@ -361,6 +376,8 @@ The maximum number of displays can be configured by changing the following in yo
|
|||||||
#define ST7789_NUM_DEVICES 3
|
#define ST7789_NUM_DEVICES 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Native color format rgb565 is compatible with ST7789
|
||||||
|
|
||||||
!> 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.
|
!> 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.
|
||||||
|
|
||||||
<!-- tabs:end -->
|
<!-- tabs:end -->
|
||||||
|
@ -104,6 +104,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t gc9a01_driver_vtable = {
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -164,6 +164,12 @@ static bool qp_rgb565_surface_append_pixels_rgb565(painter_device_t device, uint
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Append data to the target location
|
||||||
|
static bool qp_rgb565_surface_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) {
|
||||||
|
target_buffer[pixdata_offset] = pixdata_byte;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const struct painter_driver_vtable_t rgb565_surface_driver_vtable = {
|
const struct painter_driver_vtable_t rgb565_surface_driver_vtable = {
|
||||||
.init = qp_rgb565_surface_init,
|
.init = qp_rgb565_surface_init,
|
||||||
.power = qp_rgb565_surface_power,
|
.power = qp_rgb565_surface_power,
|
||||||
@ -173,6 +179,7 @@ const struct painter_driver_vtable_t rgb565_surface_driver_vtable = {
|
|||||||
.viewport = qp_rgb565_surface_viewport,
|
.viewport = qp_rgb565_surface_viewport,
|
||||||
.palette_convert = qp_rgb565_surface_palette_convert_rgb565_swapped,
|
.palette_convert = qp_rgb565_surface_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_rgb565_surface_append_pixels_rgb565,
|
.append_pixels = qp_rgb565_surface_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_rgb565_surface_append_pixdata,
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -69,6 +69,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9163_driver_vtable =
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -76,6 +76,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9341_driver_vtable =
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -69,6 +69,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9488_driver_vtable =
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb888,
|
.palette_convert = qp_tft_panel_palette_convert_rgb888,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb888,
|
.append_pixels = qp_tft_panel_append_pixels_rgb888,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -73,6 +73,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ssd1351_driver_vtable =
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 1,
|
.num_window_bytes = 1,
|
||||||
.swap_window_coords = true,
|
.swap_window_coords = true,
|
||||||
|
@ -93,6 +93,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t st7735_driver_vtable = {
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -92,6 +92,7 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t st7789_driver_vtable = {
|
|||||||
.viewport = qp_tft_panel_viewport,
|
.viewport = qp_tft_panel_viewport,
|
||||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||||
|
.append_pixdata = qp_tft_panel_append_pixdata,
|
||||||
},
|
},
|
||||||
.num_window_bytes = 2,
|
.num_window_bytes = 2,
|
||||||
.swap_window_coords = false,
|
.swap_window_coords = false,
|
||||||
|
@ -126,3 +126,8 @@ bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool qp_tft_panel_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) {
|
||||||
|
target_buffer[pixdata_offset] = pixdata_byte;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -59,3 +59,5 @@ bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palett
|
|||||||
|
|
||||||
bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||||
bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||||
|
|
||||||
|
bool qp_tft_panel_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte);
|
||||||
|
@ -29,7 +29,7 @@ def xap_generate_qmk_inc(cli):
|
|||||||
generate_inline(cli.args.output, cli.args.keyboard, cli.args.keymap)
|
generate_inline(cli.args.output, cli.args.keyboard, cli.args.keymap)
|
||||||
|
|
||||||
defs = merge_xap_defs(cli.args.keyboard, cli.args.keymap)
|
defs = merge_xap_defs(cli.args.keyboard, cli.args.keymap)
|
||||||
with open(normpath(str(cli.args.output.resolve()) + '.generated.j2'), 'w', encoding='utf-8') as out_file:
|
with open(normpath(str(cli.args.output.resolve()) + '.generated.j2.c'), 'w', encoding='utf-8') as out_file:
|
||||||
r = render_xap_output('firmware', 'xap_generated.inl.j2', defs, keyboard=cli.args.keyboard, keymap=cli.args.keymap)
|
r = render_xap_output('firmware', 'xap_generated.inl.j2', defs, keyboard=cli.args.keyboard, keymap=cli.args.keymap)
|
||||||
while r.find('\n\n\n') != -1:
|
while r.find('\n\n\n') != -1:
|
||||||
r = r.replace('\n\n\n', '\n\n')
|
r = r.replace('\n\n\n', '\n\n')
|
||||||
|
@ -7,6 +7,20 @@ from PIL import Image, ImageOps
|
|||||||
|
|
||||||
# The list of valid formats Quantum Painter supports
|
# The list of valid formats Quantum Painter supports
|
||||||
valid_formats = {
|
valid_formats = {
|
||||||
|
'rgb888': {
|
||||||
|
'image_format': 'IMAGE_FORMAT_RGB888',
|
||||||
|
'bpp': 24,
|
||||||
|
'has_palette': False,
|
||||||
|
'num_colors': 16777216,
|
||||||
|
'image_format_byte': 0x09, # see qp_internal_formats.h
|
||||||
|
},
|
||||||
|
'rgb565': {
|
||||||
|
'image_format': 'IMAGE_FORMAT_RGB565',
|
||||||
|
'bpp': 16,
|
||||||
|
'has_palette': False,
|
||||||
|
'num_colors': 65536,
|
||||||
|
'image_format_byte': 0x08, # see qp_internal_formats.h
|
||||||
|
},
|
||||||
'pal256': {
|
'pal256': {
|
||||||
'image_format': 'IMAGE_FORMAT_PALETTE',
|
'image_format': 'IMAGE_FORMAT_PALETTE',
|
||||||
'bpp': 8,
|
'bpp': 8,
|
||||||
@ -144,19 +158,33 @@ def convert_requested_format(im, format):
|
|||||||
ncolors = format["num_colors"]
|
ncolors = format["num_colors"]
|
||||||
image_format = format["image_format"]
|
image_format = format["image_format"]
|
||||||
|
|
||||||
|
# Work out where we're getting the bytes from
|
||||||
|
if image_format == 'IMAGE_FORMAT_GRAYSCALE':
|
||||||
# Ensure we have a valid number of colors for the palette
|
# Ensure we have a valid number of colors for the palette
|
||||||
if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0):
|
if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0):
|
||||||
raise ValueError("Number of colors must be 2, 4, 16, or 256.")
|
raise ValueError("Number of colors must be 2, 4, 16, or 256.")
|
||||||
|
|
||||||
# Work out where we're getting the bytes from
|
|
||||||
if image_format == 'IMAGE_FORMAT_GRAYSCALE':
|
|
||||||
# If mono, convert input to grayscale, then to RGB, then grab the raw bytes corresponding to the intensity of the red channel
|
# If mono, convert input to grayscale, then to RGB, then grab the raw bytes corresponding to the intensity of the red channel
|
||||||
im = ImageOps.grayscale(im)
|
im = ImageOps.grayscale(im)
|
||||||
im = im.convert("RGB")
|
im = im.convert("RGB")
|
||||||
elif image_format == 'IMAGE_FORMAT_PALETTE':
|
elif image_format == 'IMAGE_FORMAT_PALETTE':
|
||||||
|
# Ensure we have a valid number of colors for the palette
|
||||||
|
if ncolors <= 0 or ncolors > 256 or (ncolors & (ncolors - 1) != 0):
|
||||||
|
raise ValueError("Number of colors must be 2, 4, 16, or 256.")
|
||||||
# If color, convert input to RGB, palettize based on the supplied number of colors, then get the raw palette bytes
|
# If color, convert input to RGB, palettize based on the supplied number of colors, then get the raw palette bytes
|
||||||
im = im.convert("RGB")
|
im = im.convert("RGB")
|
||||||
im = im.convert("P", palette=Image.ADAPTIVE, colors=ncolors)
|
im = im.convert("P", palette=Image.ADAPTIVE, colors=ncolors)
|
||||||
|
elif image_format == 'IMAGE_FORMAT_RGB565':
|
||||||
|
# Ensure we have a valid number of colors for the palette
|
||||||
|
if ncolors != 65536:
|
||||||
|
raise ValueError("Number of colors must be 65536.")
|
||||||
|
# If color, convert input to RGB
|
||||||
|
im = im.convert("RGB")
|
||||||
|
elif image_format == 'IMAGE_FORMAT_RGB888':
|
||||||
|
# Ensure we have a valid number of colors for the palette
|
||||||
|
if ncolors != 1677216:
|
||||||
|
raise ValueError("Number of colors must be 16777216.")
|
||||||
|
# If color, convert input to RGB
|
||||||
|
im = im.convert("RGB")
|
||||||
|
|
||||||
return im
|
return im
|
||||||
|
|
||||||
@ -170,8 +198,12 @@ def convert_image_bytes(im, format):
|
|||||||
image_format = format["image_format"]
|
image_format = format["image_format"]
|
||||||
shifter = int(math.log2(ncolors))
|
shifter = int(math.log2(ncolors))
|
||||||
pixels_per_byte = int(8 / math.log2(ncolors))
|
pixels_per_byte = int(8 / math.log2(ncolors))
|
||||||
|
bytes_per_pixel = math.ceil(math.log2(ncolors) / 8)
|
||||||
(width, height) = im.size
|
(width, height) = im.size
|
||||||
|
if (pixels_per_byte != 0):
|
||||||
expected_byte_count = ((width * height) + (pixels_per_byte - 1)) // pixels_per_byte
|
expected_byte_count = ((width * height) + (pixels_per_byte - 1)) // pixels_per_byte
|
||||||
|
else:
|
||||||
|
expected_byte_count = width * height * bytes_per_pixel
|
||||||
|
|
||||||
if image_format == 'IMAGE_FORMAT_GRAYSCALE':
|
if image_format == 'IMAGE_FORMAT_GRAYSCALE':
|
||||||
# Take the red channel
|
# Take the red channel
|
||||||
@ -212,6 +244,44 @@ def convert_image_bytes(im, format):
|
|||||||
byte = byte | ((image_bytes[byte_offset] & (ncolors - 1)) << int(n * shifter))
|
byte = byte | ((image_bytes[byte_offset] & (ncolors - 1)) << int(n * shifter))
|
||||||
bytearray.append(byte)
|
bytearray.append(byte)
|
||||||
|
|
||||||
|
if image_format == 'IMAGE_FORMAT_RGB565':
|
||||||
|
# Take the red, green, and blue channels
|
||||||
|
image_bytes_red = im.tobytes("raw", "R")
|
||||||
|
image_bytes_green = im.tobytes("raw", "G")
|
||||||
|
image_bytes_blue = im.tobytes("raw", "B")
|
||||||
|
image_pixels_len = len(image_bytes_red)
|
||||||
|
|
||||||
|
# No palette
|
||||||
|
palette = None
|
||||||
|
|
||||||
|
bytearray = []
|
||||||
|
for x in range(image_pixels_len):
|
||||||
|
# 5 bits of red, 3 MSb of green
|
||||||
|
byte = ((image_bytes_red[x] >> 3 & 0x1F) << 3) + (image_bytes_green[x] >> 5 & 0x07)
|
||||||
|
bytearray.append(byte)
|
||||||
|
# 3 LSb of green, 5 bits of blue
|
||||||
|
byte = ((image_bytes_green[x] >> 2 & 0x07) << 5) + (image_bytes_blue[x] >> 3 & 0x1F)
|
||||||
|
bytearray.append(byte)
|
||||||
|
|
||||||
|
if image_format == 'IMAGE_FORMAT_RGB888':
|
||||||
|
# Take the red, green, and blue channels
|
||||||
|
image_bytes_red = im.tobytes("raw", "R")
|
||||||
|
image_bytes_green = im.tobytes("raw", "G")
|
||||||
|
image_bytes_blue = im.tobytes("raw", "B")
|
||||||
|
image_pixels_len = len(image_bytes_red)
|
||||||
|
|
||||||
|
# No palette
|
||||||
|
palette = None
|
||||||
|
|
||||||
|
bytearray = []
|
||||||
|
for x in range(image_pixels_len):
|
||||||
|
byte = image_bytes_red[x]
|
||||||
|
bytearray.append(byte)
|
||||||
|
byte = image_bytes_green[x]
|
||||||
|
bytearray.append(byte)
|
||||||
|
byte = image_bytes_blue[x]
|
||||||
|
bytearray.append(byte)
|
||||||
|
|
||||||
if len(bytearray) != expected_byte_count:
|
if len(bytearray) != expected_byte_count:
|
||||||
raise Exception(f"Wrong byte count, was {len(bytearray)}, expected {expected_byte_count}")
|
raise Exception(f"Wrong byte count, was {len(bytearray)}, expected {expected_byte_count}")
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ def load_lighting_spec(feature, version='latest'):
|
|||||||
|
|
||||||
def _get_jinja2_env(data_templates_xap_subdir: str):
|
def _get_jinja2_env(data_templates_xap_subdir: str):
|
||||||
templates_dir = os.path.join(qmk.constants.QMK_FIRMWARE, 'data', 'templates', 'xap', data_templates_xap_subdir)
|
templates_dir = os.path.join(qmk.constants.QMK_FIRMWARE, 'data', 'templates', 'xap', data_templates_xap_subdir)
|
||||||
j2 = Environment(loader=FileSystemLoader(templates_dir), autoescape=select_autoescape())
|
j2 = Environment(loader=FileSystemLoader(templates_dir), autoescape=select_autoescape(), lstrip_blocks=True, trim_blocks=True)
|
||||||
return j2
|
return j2
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,11 +38,13 @@ bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette)
|
|||||||
[PALETTE_2BPP] = {.bpp = 2, .has_palette = true},
|
[PALETTE_2BPP] = {.bpp = 2, .has_palette = true},
|
||||||
[PALETTE_4BPP] = {.bpp = 4, .has_palette = true},
|
[PALETTE_4BPP] = {.bpp = 4, .has_palette = true},
|
||||||
[PALETTE_8BPP] = {.bpp = 8, .has_palette = true},
|
[PALETTE_8BPP] = {.bpp = 8, .has_palette = true},
|
||||||
|
[RGB565_16BPP] = {.bpp = 16, .has_palette = false},
|
||||||
|
[RGB888_24BPP] = {.bpp = 24, .has_palette = false},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
// Copy out the required info
|
// Copy out the required info
|
||||||
if (format > PALETTE_8BPP) {
|
if (format > RGB888_24BPP) {
|
||||||
qp_dprintf("Failed to parse frame_descriptor, invalid format 0x%02X\n", (int)format);
|
qp_dprintf("Failed to parse frame_descriptor, invalid format 0x%02X\n", (int)format);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// Internal driver validation
|
// Internal driver validation
|
||||||
|
|
||||||
static bool validate_driver_vtable(struct painter_driver_t *driver) {
|
static bool validate_driver_vtable(struct painter_driver_t *driver) {
|
||||||
return (driver->driver_vtable && driver->driver_vtable->init && driver->driver_vtable->power && driver->driver_vtable->clear && driver->driver_vtable->viewport && driver->driver_vtable->pixdata && driver->driver_vtable->palette_convert && driver->driver_vtable->append_pixels) ? true : false;
|
return (driver->driver_vtable && driver->driver_vtable->init && driver->driver_vtable->power && driver->driver_vtable->clear && driver->driver_vtable->viewport && driver->driver_vtable->pixdata && driver->driver_vtable->palette_convert && driver->driver_vtable->append_pixels && driver->driver_vtable->append_pixdata) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validate_comms_vtable(struct painter_driver_t *driver) {
|
static bool validate_comms_vtable(struct painter_driver_t *driver) {
|
||||||
|
@ -64,6 +64,14 @@
|
|||||||
# define QUANTUM_PAINTER_SUPPORTS_256_PALETTE FALSE
|
# define QUANTUM_PAINTER_SUPPORTS_256_PALETTE FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS
|
||||||
|
/**
|
||||||
|
* @def This controls whether the native color range is supported. This avoids the use of palettes but each image
|
||||||
|
* requires more storage space.
|
||||||
|
*/
|
||||||
|
# define QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS FALSE
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Quantum Painter types
|
// Quantum Painter types
|
||||||
|
|
||||||
|
@ -30,9 +30,11 @@ bool qp_internal_fillrect_helper_impl(painter_device_t device, uint16_t l, uint1
|
|||||||
// Convert from input pixel data + palette to equivalent pixels
|
// Convert from input pixel data + palette to equivalent pixels
|
||||||
typedef int16_t (*qp_internal_byte_input_callback)(void* cb_arg);
|
typedef int16_t (*qp_internal_byte_input_callback)(void* cb_arg);
|
||||||
typedef bool (*qp_internal_pixel_output_callback)(qp_pixel_t* palette, uint8_t index, void* cb_arg);
|
typedef bool (*qp_internal_pixel_output_callback)(qp_pixel_t* palette, uint8_t index, void* cb_arg);
|
||||||
|
typedef bool (*qp_internal_byte_output_callback)(uint8_t byte, void* cb_arg);
|
||||||
bool qp_internal_decode_palette(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_pixel_t* palette, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
bool qp_internal_decode_palette(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_pixel_t* palette, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
||||||
bool qp_internal_decode_grayscale(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
bool qp_internal_decode_grayscale(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
||||||
bool qp_internal_decode_recolor(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_pixel_t fg_hsv888, qp_pixel_t bg_hsv888, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
bool qp_internal_decode_recolor(painter_device_t device, uint32_t pixel_count, uint8_t bits_per_pixel, qp_internal_byte_input_callback input_callback, void* input_arg, qp_pixel_t fg_hsv888, qp_pixel_t bg_hsv888, qp_internal_pixel_output_callback output_callback, void* output_arg);
|
||||||
|
bool qp_internal_send_bytes(painter_device_t device, uint32_t byte_count, qp_internal_byte_input_callback input_callback, void* input_arg, qp_internal_byte_output_callback output_callback, void* output_arg);
|
||||||
|
|
||||||
// Global variable used for interpolated pixel lookup table.
|
// Global variable used for interpolated pixel lookup table.
|
||||||
#if QUANTUM_PAINTER_SUPPORTS_256_PALETTE
|
#if QUANTUM_PAINTER_SUPPORTS_256_PALETTE
|
||||||
@ -82,4 +84,12 @@ struct qp_internal_pixel_output_state {
|
|||||||
|
|
||||||
bool qp_internal_pixel_appender(qp_pixel_t* palette, uint8_t index, void* cb_arg);
|
bool qp_internal_pixel_appender(qp_pixel_t* palette, uint8_t index, void* cb_arg);
|
||||||
|
|
||||||
|
struct qp_internal_byte_output_state {
|
||||||
|
painter_device_t device;
|
||||||
|
uint32_t byte_write_pos;
|
||||||
|
uint32_t max_bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool qp_internal_byte_appender(uint8_t byteval, void* cb_arg);
|
||||||
|
|
||||||
qp_internal_byte_input_callback qp_internal_prepare_input_state(struct qp_internal_byte_input_state* input_state, painter_compression_t compression);
|
qp_internal_byte_input_callback qp_internal_prepare_input_state(struct qp_internal_byte_input_state* input_state, painter_compression_t compression);
|
||||||
|
@ -12,18 +12,19 @@ static const qp_pixel_t qp_pixel_white = {.hsv888 = {.h = 0, .s = 0, .v = 255}};
|
|||||||
static const qp_pixel_t qp_pixel_black = {.hsv888 = {.h = 0, .s = 0, .v = 0}};
|
static const qp_pixel_t qp_pixel_black = {.hsv888 = {.h = 0, .s = 0, .v = 0}};
|
||||||
|
|
||||||
bool qp_internal_bpp_capable(uint8_t bits_per_pixel) {
|
bool qp_internal_bpp_capable(uint8_t bits_per_pixel) {
|
||||||
#if !(QUANTUM_PAINTER_SUPPORTS_256_PALETTE)
|
#if !(QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS)
|
||||||
|
# if !(QUANTUM_PAINTER_SUPPORTS_256_PALETTE)
|
||||||
if (bits_per_pixel > 4) {
|
if (bits_per_pixel > 4) {
|
||||||
qp_dprintf("qp_internal_decode_palette: image bpp greater than 4\n");
|
qp_dprintf("qp_internal_decode_palette: image bpp greater than 4\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
if (bits_per_pixel > 8) {
|
if (bits_per_pixel > 8) {
|
||||||
qp_dprintf("qp_internal_decode_palette: image bpp greater than 8\n");
|
qp_dprintf("qp_internal_decode_palette: image bpp greater than 8\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ bool qp_internal_decode_palette(painter_device_t device, uint32_t pixel_count, u
|
|||||||
const uint8_t pixels_per_byte = 8 / bits_per_pixel;
|
const uint8_t pixels_per_byte = 8 / bits_per_pixel;
|
||||||
uint32_t remaining_pixels = pixel_count; // don't try to derive from byte_count, we may not use an entire byte
|
uint32_t remaining_pixels = pixel_count; // don't try to derive from byte_count, we may not use an entire byte
|
||||||
while (remaining_pixels > 0) {
|
while (remaining_pixels > 0) {
|
||||||
uint8_t byteval = input_callback(input_arg);
|
int16_t byteval = input_callback(input_arg);
|
||||||
if (byteval < 0) {
|
if (byteval < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -64,6 +65,21 @@ bool qp_internal_decode_recolor(painter_device_t device, uint32_t pixel_count, u
|
|||||||
return qp_internal_decode_palette(device, pixel_count, bits_per_pixel, input_callback, input_arg, qp_internal_global_pixel_lookup_table, output_callback, output_arg);
|
return qp_internal_decode_palette(device, pixel_count, bits_per_pixel, input_callback, input_arg, qp_internal_global_pixel_lookup_table, output_callback, output_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool qp_internal_send_bytes(painter_device_t device, uint32_t byte_count, qp_internal_byte_input_callback input_callback, void* input_arg, qp_internal_byte_output_callback output_callback, void* output_arg) {
|
||||||
|
uint32_t remaining_bytes = byte_count;
|
||||||
|
while (remaining_bytes > 0) {
|
||||||
|
int16_t byteval = input_callback(input_arg);
|
||||||
|
if (byteval < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!output_callback(byteval, output_arg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
remaining_bytes -= 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Progressive pull of bytes, push of pixels
|
// Progressive pull of bytes, push of pixels
|
||||||
|
|
||||||
@ -128,6 +144,26 @@ bool qp_internal_pixel_appender(qp_pixel_t* palette, uint8_t index, void* cb_arg
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool qp_internal_byte_appender(uint8_t byteval, void* cb_arg) {
|
||||||
|
struct qp_internal_byte_output_state* state = (struct qp_internal_byte_output_state*)cb_arg;
|
||||||
|
struct painter_driver_t* driver = (struct painter_driver_t*)state->device;
|
||||||
|
|
||||||
|
if (!driver->driver_vtable->append_pixdata(state->device, qp_internal_global_pixdata_buffer, state->byte_write_pos++, byteval)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've hit the transmit limit, send out the entire buffer and reset the write position
|
||||||
|
if (state->byte_write_pos == state->max_bytes) {
|
||||||
|
struct painter_driver_t* driver = (struct painter_driver_t*)state->device;
|
||||||
|
if (!driver->driver_vtable->pixdata(state->device, qp_internal_global_pixdata_buffer, state->byte_write_pos * 8 / driver->native_bits_per_pixel)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
state->byte_write_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
qp_internal_byte_input_callback qp_internal_prepare_input_state(struct qp_internal_byte_input_state* input_state, painter_compression_t compression) {
|
qp_internal_byte_input_callback qp_internal_prepare_input_state(struct qp_internal_byte_input_state* input_state, painter_compression_t compression) {
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case IMAGE_UNCOMPRESSED:
|
case IMAGE_UNCOMPRESSED:
|
||||||
|
@ -151,7 +151,7 @@ static bool qp_drawimage_prepare_frame_for_stream_read(painter_device_t device,
|
|||||||
qp_internal_invalidate_palette();
|
qp_internal_invalidate_palette();
|
||||||
|
|
||||||
if (!qp_internal_bpp_capable(info->bpp)) {
|
if (!qp_internal_bpp_capable(info->bpp)) {
|
||||||
qp_dprintf("qp_drawimage_recolor: fail (image bpp too high (%d), check QUANTUM_PAINTER_SUPPORTS_256_PALETTE)\n", (int)info->bpp);
|
qp_dprintf("qp_drawimage_recolor: fail (image bpp too high (%d), check QUANTUM_PAINTER_SUPPORTS_256_PALETTE or QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS)\n", (int)info->bpp);
|
||||||
qp_comms_stop(device);
|
qp_comms_stop(device);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -167,9 +167,11 @@ static bool qp_drawimage_prepare_frame_for_stream_read(painter_device_t device,
|
|||||||
|
|
||||||
needs_pixconvert = true;
|
needs_pixconvert = true;
|
||||||
} else {
|
} else {
|
||||||
|
if (info->bpp <= 8) {
|
||||||
// Interpolate from fg/bg
|
// Interpolate from fg/bg
|
||||||
needs_pixconvert = qp_internal_interpolate_palette(fg_hsv888, bg_hsv888, palette_entries);
|
needs_pixconvert = qp_internal_interpolate_palette(fg_hsv888, bg_hsv888, palette_entries);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (needs_pixconvert) {
|
if (needs_pixconvert) {
|
||||||
// Convert the palette to native format
|
// Convert the palette to native format
|
||||||
@ -260,16 +262,29 @@ static bool qp_drawimage_recolor_impl(painter_device_t device, uint16_t x, uint1
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
if (frame_info->bpp <= 8) {
|
||||||
// Set up the output state
|
// Set up the output state
|
||||||
struct qp_internal_pixel_output_state output_state = {.device = device, .pixel_write_pos = 0, .max_pixels = qp_internal_num_pixels_in_buffer(device)};
|
struct qp_internal_pixel_output_state output_state = {.device = device, .pixel_write_pos = 0, .max_pixels = qp_internal_num_pixels_in_buffer(device)};
|
||||||
|
|
||||||
// Decode the pixel data and stream to the display
|
// Decode the pixel data and stream to the display
|
||||||
bool ret = qp_internal_decode_palette(device, pixel_count, frame_info->bpp, input_callback, &input_state, qp_internal_global_pixel_lookup_table, qp_internal_pixel_appender, &output_state);
|
ret = qp_internal_decode_palette(device, pixel_count, frame_info->bpp, input_callback, &input_state, qp_internal_global_pixel_lookup_table, qp_internal_pixel_appender, &output_state);
|
||||||
|
|
||||||
// Any leftovers need transmission as well.
|
// Any leftovers need transmission as well.
|
||||||
if (ret && output_state.pixel_write_pos > 0) {
|
if (ret && output_state.pixel_write_pos > 0) {
|
||||||
ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.pixel_write_pos);
|
ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.pixel_write_pos);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Set up the output state
|
||||||
|
struct qp_internal_byte_output_state output_state = {.device = device, .byte_write_pos = 0, .max_bytes = qp_internal_num_pixels_in_buffer(device) * driver->native_bits_per_pixel / 8};
|
||||||
|
|
||||||
|
// Stream the raw pixel data to the display
|
||||||
|
uint32_t byte_count = pixel_count * frame_info->bpp / 8;
|
||||||
|
ret = qp_internal_send_bytes(device, byte_count, input_callback, &input_state, qp_internal_byte_appender, &output_state);
|
||||||
|
// Any leftovers need transmission as well.
|
||||||
|
if (ret && output_state.byte_write_pos > 0) {
|
||||||
|
ret &= driver->driver_vtable->pixdata(device, qp_internal_global_pixdata_buffer, output_state.byte_write_pos * 8 / driver->native_bits_per_pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qp_dprintf("qp_drawimage_recolor: %s\n", ret ? "ok" : "fail");
|
qp_dprintf("qp_drawimage_recolor: %s\n", ret ? "ok" : "fail");
|
||||||
qp_comms_stop(device);
|
qp_comms_stop(device);
|
||||||
|
@ -100,7 +100,7 @@ static painter_font_handle_t qp_load_font_internal(bool (*stream_factory)(qff_fo
|
|||||||
qff_read_font_descriptor(&font->stream, &font->base.line_height, &font->has_ascii_table, &font->num_unicode_glyphs, &font->bpp, &font->has_palette, &font->compression_scheme, NULL);
|
qff_read_font_descriptor(&font->stream, &font->base.line_height, &font->has_ascii_table, &font->num_unicode_glyphs, &font->bpp, &font->has_palette, &font->compression_scheme, NULL);
|
||||||
|
|
||||||
if (!qp_internal_bpp_capable(font->bpp)) {
|
if (!qp_internal_bpp_capable(font->bpp)) {
|
||||||
qp_dprintf("qp_load_font: fail (image bpp too high (%d), check QUANTUM_PAINTER_SUPPORTS_256_PALETTE)\n", (int)font->bpp);
|
qp_dprintf("qp_load_font: fail (image bpp too high (%d), check QUANTUM_PAINTER_SUPPORTS_256_PALETTE or QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS)\n", (int)font->bpp);
|
||||||
qp_close_font((painter_font_handle_t)font);
|
qp_close_font((painter_font_handle_t)font);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ typedef bool (*painter_driver_viewport_func)(painter_device_t device, uint16_t l
|
|||||||
typedef bool (*painter_driver_pixdata_func)(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
|
typedef bool (*painter_driver_pixdata_func)(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
|
||||||
typedef bool (*painter_driver_convert_palette_func)(painter_device_t device, int16_t palette_size, qp_pixel_t *palette);
|
typedef bool (*painter_driver_convert_palette_func)(painter_device_t device, int16_t palette_size, qp_pixel_t *palette);
|
||||||
typedef bool (*painter_driver_append_pixels)(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
typedef bool (*painter_driver_append_pixels)(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||||
|
typedef bool (*painter_driver_append_pixdata)(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte);
|
||||||
|
|
||||||
// Driver vtable definition
|
// Driver vtable definition
|
||||||
struct painter_driver_vtable_t {
|
struct painter_driver_vtable_t {
|
||||||
@ -27,6 +28,7 @@ struct painter_driver_vtable_t {
|
|||||||
painter_driver_pixdata_func pixdata;
|
painter_driver_pixdata_func pixdata;
|
||||||
painter_driver_convert_palette_func palette_convert;
|
painter_driver_convert_palette_func palette_convert;
|
||||||
painter_driver_append_pixels append_pixels;
|
painter_driver_append_pixels append_pixels;
|
||||||
|
painter_driver_append_pixdata append_pixdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -44,6 +44,8 @@ typedef enum qp_image_format_t {
|
|||||||
PALETTE_2BPP = 0x05,
|
PALETTE_2BPP = 0x05,
|
||||||
PALETTE_4BPP = 0x06,
|
PALETTE_4BPP = 0x06,
|
||||||
PALETTE_8BPP = 0x07,
|
PALETTE_8BPP = 0x07,
|
||||||
|
RGB565_16BPP = 0x08,
|
||||||
|
RGB888_24BPP = 0x09,
|
||||||
} qp_image_format_t;
|
} qp_image_format_t;
|
||||||
|
|
||||||
typedef enum painter_compression_t { IMAGE_UNCOMPRESSED, IMAGE_COMPRESSED_RLE } painter_compression_t;
|
typedef enum painter_compression_t { IMAGE_UNCOMPRESSED, IMAGE_COMPRESSED_RLE } painter_compression_t;
|
||||||
|
Loading…
Reference in New Issue
Block a user