mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-28 13:36:27 +08:00
feat(NemaGFX): add vector draw task support (#8938)
This commit is contained in:
@@ -75,6 +75,36 @@ provided implementations by setting :c:macro:`LV_USE_NEMA_HAL` to a value other
|
|||||||
:c:macro:`LV_NEMA_HAL_CUSTOM`.
|
:c:macro:`LV_NEMA_HAL_CUSTOM`.
|
||||||
|
|
||||||
|
|
||||||
|
Vector Graphics
|
||||||
|
***************
|
||||||
|
|
||||||
|
The NeoChrom VG driver in LVGL can render vector graphics Widgets using NeoChrom VG's
|
||||||
|
hardware support for vector graphics drawing. You can display SVG files in your application.
|
||||||
|
See the SVG examples for usage.
|
||||||
|
|
||||||
|
To use vector graphics with NeoChrom, you should enable the following configs in ``lv_conf.h``.
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
LV_USE_NEMA_GFX 1
|
||||||
|
LV_USE_NEMA_VG 1
|
||||||
|
LV_USE_VECTOR_GRAPHIC 1
|
||||||
|
LV_USE_MATRIX 1
|
||||||
|
LV_USE_FLOAT 1
|
||||||
|
|
||||||
|
To use the SVG widget, additionally enable ``LV_USE_SVG``.
|
||||||
|
|
||||||
|
If there is RAM available, SVG performance can be increased by enabling the image cache,
|
||||||
|
``LV_CACHE_DEF_SIZE``.
|
||||||
|
``LV_CACHE_DEF_SIZE`` is a cache size in bytes. If it is large enough for your SVGs,
|
||||||
|
it will cache decoded SVG data so it does not need to be parsed every refresh, significantly
|
||||||
|
reducing SVG redraw time.
|
||||||
|
|
||||||
|
``LV_USE_DEMO_VECTOR_GRAPHIC`` is a demo you can enable which draws some vector graphics shapes.
|
||||||
|
Gradient and image fills are not supported yet, as well as dashed strokes. These are
|
||||||
|
missing from the demo when it is run with the NeoChrom driver.
|
||||||
|
|
||||||
|
|
||||||
TSC Images
|
TSC Images
|
||||||
**********
|
**********
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<svg width="12cm" height="4cm" viewBox="0 0 1200 400">
|
||||||
|
<circle cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10"/></svg>
|
||||||
|
After Width: | Height: | Size: 139 B |
@@ -1,6 +1,17 @@
|
|||||||
Load and render SVG data
|
Load and render SVG data
|
||||||
---------------------------------------
|
------------------------
|
||||||
|
|
||||||
.. lv_example:: libs/svg/lv_example_svg_1
|
.. lv_example:: libs/svg/lv_example_svg_1
|
||||||
:language: c
|
:language: c
|
||||||
|
|
||||||
|
Load and render SVG data from a file
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. lv_example:: libs/svg/lv_example_svg_2
|
||||||
|
:language: c
|
||||||
|
|
||||||
|
Load and render SVG data in a draw event
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. lv_example:: libs/svg/lv_example_svg_3
|
||||||
|
:language: c
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ extern "C" {
|
|||||||
* GLOBAL PROTOTYPES
|
* GLOBAL PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
void lv_example_svg_1(void);
|
void lv_example_svg_1(void);
|
||||||
|
void lv_example_svg_2(void);
|
||||||
|
void lv_example_svg_3(void);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an SVG data
|
* Load an SVG from data
|
||||||
*/
|
*/
|
||||||
static void event_cb(lv_event_t * e)
|
|
||||||
{
|
|
||||||
static char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
|
||||||
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
|
||||||
|
|
||||||
lv_layer_t * layer = lv_event_get_layer(e);
|
|
||||||
lv_svg_node_t * svg = lv_svg_load_data(svg_data, sizeof(svg_data) / sizeof(char));
|
|
||||||
lv_draw_svg(layer, svg);
|
|
||||||
lv_svg_node_delete(svg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lv_example_svg_1(void)
|
void lv_example_svg_1(void)
|
||||||
{
|
{
|
||||||
lv_obj_add_event_cb(lv_screen_active(), event_cb, LV_EVENT_DRAW_MAIN, NULL);
|
static const char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
||||||
|
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
||||||
|
|
||||||
|
static lv_image_dsc_t svg_dsc;
|
||||||
|
svg_dsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||||
|
svg_dsc.header.w = 450;
|
||||||
|
svg_dsc.header.h = 150;
|
||||||
|
svg_dsc.data_size = sizeof(svg_data) - 1;
|
||||||
|
svg_dsc.data = (const uint8_t *) svg_data;
|
||||||
|
|
||||||
|
lv_obj_t * svg = lv_image_create(lv_screen_active());
|
||||||
|
lv_image_set_src(svg, &svg_dsc);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#include "../../lv_examples.h"
|
||||||
|
#if LV_BUILD_EXAMPLES
|
||||||
|
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an SVG from a file
|
||||||
|
*/
|
||||||
|
void lv_example_svg_2(void)
|
||||||
|
{
|
||||||
|
lv_obj_t * svg = lv_image_create(lv_screen_active());
|
||||||
|
lv_image_set_src(svg, "A:lvgl/examples/assets/circle.svg");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
void lv_example_svg_2(void)
|
||||||
|
{
|
||||||
|
/*TODO
|
||||||
|
*fallback for online examples*/
|
||||||
|
|
||||||
|
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||||
|
lv_label_set_text(label, "SVG is not enabled");
|
||||||
|
lv_obj_center(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include "../../lv_examples.h"
|
||||||
|
#if LV_BUILD_EXAMPLES
|
||||||
|
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw SVG data in a draw event
|
||||||
|
*/
|
||||||
|
static void event_cb(lv_event_t * e)
|
||||||
|
{
|
||||||
|
static const char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
||||||
|
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
||||||
|
|
||||||
|
lv_layer_t * layer = lv_event_get_layer(e);
|
||||||
|
lv_svg_node_t * svg = lv_svg_load_data(svg_data, sizeof(svg_data) / sizeof(char));
|
||||||
|
lv_draw_svg(layer, svg);
|
||||||
|
lv_svg_node_delete(svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_example_svg_3(void)
|
||||||
|
{
|
||||||
|
lv_obj_add_event_cb(lv_screen_active(), event_cb, LV_EVENT_DRAW_MAIN, NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
void lv_example_svg_3(void)
|
||||||
|
{
|
||||||
|
/*TODO
|
||||||
|
*fallback for online examples*/
|
||||||
|
|
||||||
|
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||||
|
lv_label_set_text(label, "SVG is not enabled");
|
||||||
|
lv_obj_center(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#if LV_USE_VECTOR_GRAPHIC
|
#if LV_USE_VECTOR_GRAPHIC
|
||||||
|
|
||||||
#if !((LV_USE_DRAW_SW && LV_USE_THORVG) || LV_USE_DRAW_VG_LITE)
|
#if !((LV_USE_DRAW_SW && LV_USE_THORVG) || LV_USE_DRAW_VG_LITE || (LV_USE_NEMA_GFX && LV_USE_NEMA_VG))
|
||||||
#error "LV_USE_VECTOR_GRAPHIC requires either (LV_USE_DRAW_SW and LV_USE_THORVG) or LV_USE_DRAW_VG_LITE"
|
#error "LV_USE_VECTOR_GRAPHIC requires (LV_USE_DRAW_SW and LV_USE_THORVG) or LV_USE_DRAW_VG_LITE or (LV_USE_NEMA_GFX and LV_USE_NEMA_VG)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../misc/lv_ll.h"
|
#include "../misc/lv_ll.h"
|
||||||
|
|||||||
@@ -243,12 +243,18 @@ static int32_t nema_gfx_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * ta
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||||
|
case LV_DRAW_TASK_TYPE_VECTOR: {
|
||||||
|
if(task->preference_score > 80) {
|
||||||
|
task->preference_score = 80;
|
||||||
|
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
||||||
#if LV_USE_VECTOR_GRAPHIC
|
|
||||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -328,6 +334,11 @@ static void nema_gfx_execute_drawing(lv_draw_nema_gfx_unit_t * u)
|
|||||||
case LV_DRAW_TASK_TYPE_BORDER:
|
case LV_DRAW_TASK_TYPE_BORDER:
|
||||||
lv_draw_nema_gfx_border(t, t->draw_dsc, &t->area);
|
lv_draw_nema_gfx_border(t, t->draw_dsc, &t->area);
|
||||||
break;
|
break;
|
||||||
|
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||||
|
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||||
|
lv_draw_nema_gfx_vector(t, t->draw_dsc, &t->area);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,11 @@ void lv_draw_nema_gfx_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * ds
|
|||||||
void lv_draw_nema_gfx_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc,
|
void lv_draw_nema_gfx_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc,
|
||||||
const lv_area_t * coords);
|
const lv_area_t * coords);
|
||||||
|
|
||||||
|
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||||
|
void lv_draw_nema_gfx_vector(lv_draw_task_t * t, const lv_draw_vector_dsc_t * dsc,
|
||||||
|
const lv_area_t * coords);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_draw_nema_gfx_vector.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#include "lv_draw_nema_gfx.h"
|
||||||
|
#if LV_USE_NEMA_GFX && LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||||
|
|
||||||
|
#include "lv_nema_gfx_path.h"
|
||||||
|
#include "../lv_draw_vector_private.h"
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lv_draw_nema_gfx_unit_t * u;
|
||||||
|
float rel_translate_x;
|
||||||
|
float rel_translate_y;
|
||||||
|
} ctx_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_path_ctx_t * dsc);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void lv_draw_nema_gfx_vector(lv_draw_task_t * t, const lv_draw_vector_dsc_t * dsc,
|
||||||
|
const lv_area_t * coords)
|
||||||
|
{
|
||||||
|
ctx_t c;
|
||||||
|
c.u = (lv_draw_nema_gfx_unit_t *) t->draw_unit;
|
||||||
|
|
||||||
|
lv_layer_t * layer = t->target_layer;
|
||||||
|
lv_area_t rel_clip_area;
|
||||||
|
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||||
|
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||||
|
|
||||||
|
c.rel_translate_x = -layer->buf_area.x1;
|
||||||
|
c.rel_translate_y = -layer->buf_area.y1;
|
||||||
|
|
||||||
|
nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
|
||||||
|
lv_area_get_height(&rel_clip_area));
|
||||||
|
|
||||||
|
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||||
|
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||||
|
|
||||||
|
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||||
|
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||||
|
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||||
|
|
||||||
|
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||||
|
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||||
|
|
||||||
|
nema_vg_set_blend(NEMA_BL_SRC_OVER | NEMA_BLOP_SRC_PREMULT);
|
||||||
|
|
||||||
|
lv_vector_for_each_destroy_tasks(dsc->task_list, task_draw_cb, &c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_path_ctx_t * dsc)
|
||||||
|
{
|
||||||
|
ctx_t * c = ctx;
|
||||||
|
lv_draw_nema_gfx_unit_t * u = c->u;
|
||||||
|
|
||||||
|
if(!path) return;
|
||||||
|
|
||||||
|
nema_vg_path_clear(u->path);
|
||||||
|
nema_vg_paint_clear(u->paint);
|
||||||
|
|
||||||
|
nema_vg_paint_set_type(u->paint, NEMA_VG_PAINT_COLOR);
|
||||||
|
|
||||||
|
lv_matrix_t matrix = dsc->matrix;
|
||||||
|
matrix.m[0][2] += c->rel_translate_x;
|
||||||
|
matrix.m[1][2] += c->rel_translate_y;
|
||||||
|
nema_vg_path_set_matrix(c->u->path, (void *) &matrix);
|
||||||
|
|
||||||
|
/* the path ops array needs to be translated to nema's opcodes */
|
||||||
|
lv_vector_path_op_t * ops = lv_array_front(&path->ops);
|
||||||
|
uint32_t op_count = lv_array_size(&path->ops);
|
||||||
|
uint8_t * nema_ops = lv_malloc(op_count * sizeof(*nema_ops));
|
||||||
|
LV_ASSERT_MALLOC(nema_ops);
|
||||||
|
for(uint32_t i = 0; i < op_count; i++) {
|
||||||
|
nema_ops[i] = ops[i] == LV_VECTOR_PATH_OP_MOVE_TO ? NEMA_VG_PRIM_MOVE :
|
||||||
|
ops[i] == LV_VECTOR_PATH_OP_LINE_TO ? NEMA_VG_PRIM_LINE :
|
||||||
|
ops[i] == LV_VECTOR_PATH_OP_QUAD_TO ? NEMA_VG_PRIM_BEZIER_QUAD :
|
||||||
|
ops[i] == LV_VECTOR_PATH_OP_CUBIC_TO ? NEMA_VG_PRIM_BEZIER_CUBIC :
|
||||||
|
/*LV_VECTOR_PATH_OP_CLOSE*/ NEMA_VG_PRIM_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the path points array is in the right format for nema to use as-is */
|
||||||
|
uint32_t point_count = lv_array_size(&path->points);
|
||||||
|
float * points = lv_array_front(&path->points);
|
||||||
|
|
||||||
|
nema_vg_path_set_shape(u->path, op_count, nema_ops, point_count, points);
|
||||||
|
|
||||||
|
nema_vg_set_quality(path->quality == LV_VECTOR_PATH_QUALITY_LOW ? NEMA_VG_QUALITY_FASTER :
|
||||||
|
path->quality == LV_VECTOR_PATH_QUALITY_MEDIUM ? NEMA_VG_QUALITY_BETTER :
|
||||||
|
/*LV_VECTOR_PATH_QUALITY_HIGH*/ NEMA_VG_QUALITY_MAXIMUM);
|
||||||
|
|
||||||
|
if(dsc->fill_dsc.opa) {
|
||||||
|
nema_vg_set_fill_rule(dsc->fill_dsc.fill_rule == LV_VECTOR_FILL_NONZERO ? NEMA_VG_FILL_NON_ZERO :
|
||||||
|
/*LV_VECTOR_FILL_EVENODD*/ NEMA_VG_FILL_EVEN_ODD);
|
||||||
|
|
||||||
|
uint32_t nema_dsc_color = nema_rgba(dsc->fill_dsc.color.red, dsc->fill_dsc.color.green,
|
||||||
|
dsc->fill_dsc.color.blue, dsc->fill_dsc.color.alpha);
|
||||||
|
nema_vg_paint_set_paint_color(u->paint, nema_dsc_color);
|
||||||
|
|
||||||
|
nema_vg_draw_path(u->path, u->paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dsc->stroke_dsc.opa) {
|
||||||
|
nema_vg_set_fill_rule(NEMA_VG_STROKE);
|
||||||
|
nema_vg_stroke_set_width(dsc->stroke_dsc.width);
|
||||||
|
uint8_t cap = dsc->stroke_dsc.cap == LV_VECTOR_STROKE_CAP_BUTT ? NEMA_VG_CAP_BUTT :
|
||||||
|
dsc->stroke_dsc.cap == LV_VECTOR_STROKE_CAP_SQUARE ? NEMA_VG_CAP_SQUARE :
|
||||||
|
/*LV_VECTOR_STROKE_CAP_ROUND*/ NEMA_VG_CAP_ROUND;
|
||||||
|
nema_vg_stroke_set_cap_style(cap, cap);
|
||||||
|
uint8_t join = dsc->stroke_dsc.join == LV_VECTOR_STROKE_JOIN_MITER ? NEMA_VG_JOIN_MITER :
|
||||||
|
dsc->stroke_dsc.join == LV_VECTOR_STROKE_JOIN_BEVEL ? NEMA_VG_JOIN_BEVEL :
|
||||||
|
/*LV_VECTOR_STROKE_JOIN_ROUND*/ NEMA_VG_JOIN_ROUND;
|
||||||
|
nema_vg_stroke_set_join_style(join);
|
||||||
|
nema_vg_stroke_set_miter_limit(dsc->stroke_dsc.miter_limit);
|
||||||
|
|
||||||
|
uint32_t nema_dsc_color = nema_rgba(dsc->stroke_dsc.color.red, dsc->stroke_dsc.color.green,
|
||||||
|
dsc->stroke_dsc.color.blue, dsc->stroke_dsc.color.alpha);
|
||||||
|
nema_vg_paint_set_paint_color(u->paint, nema_dsc_color);
|
||||||
|
|
||||||
|
nema_vg_draw_path(u->path, u->paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
nema_cl_submit(&c->u->cl);
|
||||||
|
nema_cl_wait(&u->cl);
|
||||||
|
|
||||||
|
lv_free(nema_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*LV_USE_NEMA_GFX && LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG*/
|
||||||
Reference in New Issue
Block a user