feat(draw): add vg-lite draw unit (#5010)

Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
_VIFEXTech
2023-12-18 21:17:42 +08:00
committed by GitHub
parent b172c64a8c
commit 9fc6801860
29 changed files with 5155 additions and 0 deletions

13
Kconfig
View File

@@ -357,6 +357,19 @@ menu "LVGL configuration"
config LV_USE_DRAW_PXP config LV_USE_DRAW_PXP
bool "Use NXP's PXP on iMX RTxxx platforms." bool "Use NXP's PXP on iMX RTxxx platforms."
config LV_USE_DRAW_VG_LITE
bool "Use VG-Lite GPU."
config LV_VG_LITE_USE_GPU_INIT
bool "Enbale VG-Lite custom external 'gpu_init()' function."
default n
depends on LV_USE_DRAW_VG_LITE
config LV_VG_LITE_USE_ASSERT
bool "Enable VG-Lite assert."
default n
depends on LV_USE_DRAW_VG_LITE
config LV_USE_GPU_SDL config LV_USE_GPU_SDL
bool "Use SDL renderer API" bool "Use SDL renderer API"
default n default n

View File

@@ -128,6 +128,17 @@
/* Draw using cached SDL textures*/ /* Draw using cached SDL textures*/
#define LV_USE_DRAW_SDL 0 #define LV_USE_DRAW_SDL 0
/* Use VG-Lite GPU. */
#define LV_USE_DRAW_VG_LITE 0
#if LV_USE_DRAW_VG_LITE
/* Enbale VG-Lite custom external 'gpu_init()' function */
#define LV_VG_LITE_USE_GPU_INIT 0
/* Enable VG-Lite assert. */
#define LV_VG_LITE_USE_ASSERT 0
#endif
/*================= /*=================
* OPERATING SYSTEM * OPERATING SYSTEM
*=================*/ *=================*/

View File

@@ -419,6 +419,8 @@ static void draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc,
if(g.bpp == LV_IMGFONT_BPP) dsc->format = LV_DRAW_LETTER_BITMAP_FORMAT_IMAGE; if(g.bpp == LV_IMGFONT_BPP) dsc->format = LV_DRAW_LETTER_BITMAP_FORMAT_IMAGE;
else dsc->format = LV_DRAW_LETTER_BITMAP_FORMAT_A8; else dsc->format = LV_DRAW_LETTER_BITMAP_FORMAT_A8;
dsc->g = &g;
cb(draw_unit, dsc, NULL, NULL); cb(draw_unit, dsc, NULL, NULL);
LV_PROFILER_END; LV_PROFILER_END;
} }

View File

@@ -87,6 +87,7 @@ typedef struct {
lv_draw_glyph_bitmap_format_t format; lv_draw_glyph_bitmap_format_t format;
const lv_area_t * letter_coords; const lv_area_t * letter_coords;
const lv_area_t * bg_coords; const lv_area_t * bg_coords;
const lv_font_glyph_dsc_t * g;
lv_color_t color; lv_color_t color;
lv_opa_t opa; lv_opa_t opa;
} lv_draw_glyph_dsc_t; } lv_draw_glyph_dsc_t;

View File

@@ -0,0 +1,197 @@
/**
* @file lv_draw_buf_vg_lite.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
#include <stdlib.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void * buf_malloc(size_t size, lv_color_format_t color_format);
static void buf_free(void * buf);
static void * buf_align(void * buf, lv_color_format_t color_format);
static void invalidate_cache(void * buf, uint32_t stride, lv_color_format_t color_format, const lv_area_t * area);
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format);
static void * buf_go_to_xy(const void * buf, uint32_t stride, lv_color_format_t color_format, int32_t x,
int32_t y);
static void buf_clear(void * buf, uint32_t w, uint32_t h, lv_color_format_t color_format, const lv_area_t * a);
static void buf_copy(void * dest_buf, uint32_t dest_w, uint32_t dest_h, const lv_area_t * dest_area_to_copy,
void * src_buf, uint32_t src_w, uint32_t src_h, const lv_area_t * src_area_to_copy,
lv_color_format_t color_format);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_buf_vg_lite_init_handlers(void)
{
lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers();
handlers->buf_malloc_cb = buf_malloc;
handlers->buf_free_cb = buf_free;
handlers->align_pointer_cb = buf_align;
handlers->invalidate_cache_cb = invalidate_cache;
handlers->width_to_stride_cb = width_to_stride;
handlers->go_to_xy_cb = buf_go_to_xy;
handlers->buf_clear_cb = buf_clear;
handlers->buf_copy_cb = buf_copy;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void * buf_malloc(size_t size_bytes, lv_color_format_t color_format)
{
LV_UNUSED(color_format);
size_bytes = LV_VG_LITE_ALIGN(size_bytes, LV_VG_LITE_BUF_ALIGN);
return aligned_alloc(LV_VG_LITE_BUF_ALIGN, size_bytes);
}
static void buf_free(void * buf)
{
free(buf);
}
static void * buf_align(void * buf, lv_color_format_t color_format)
{
LV_UNUSED(color_format);
return (void *)LV_VG_LITE_ALIGN((lv_uintptr_t)buf, LV_VG_LITE_BUF_ALIGN);
}
static void invalidate_cache(void * buf, uint32_t stride, lv_color_format_t color_format, const lv_area_t * area)
{
}
static uint32_t width_to_stride(uint32_t w, lv_color_format_t color_format)
{
return lv_vg_lite_width_to_stride(w, lv_vg_lite_vg_fmt(color_format));
}
static void * buf_go_to_xy(const void * buf, uint32_t stride, lv_color_format_t color_format, int32_t x,
int32_t y)
{
const uint8_t * buf_tmp = buf;
buf_tmp += stride * y;
buf_tmp += x * lv_color_format_get_size(color_format);
return (void *)buf_tmp;
}
static void buf_clear(void * buf, uint32_t w, uint32_t h, lv_color_format_t color_format, const lv_area_t * a)
{
#if 0
if(LV_VG_LITE_IS_ALIGNED(buf, LV_VG_LITE_BUF_ALIGN)) {
/* finish outstanding buffers */
LV_VG_LITE_CHECK_ERROR(vg_lite_finish());
vg_lite_buffer_t dest_buf;
LV_ASSERT(lv_vg_lite_buffer_init(&dest_buf, buf, w, h, lv_vg_lite_vg_fmt(color_format), false));
LV_VG_LITE_ASSERT_DEST_BUFFER(&dest_buf);
vg_lite_rectangle_t rect;
lv_vg_lite_rect(&rect, a);
LV_VG_LITE_CHECK_ERROR(vg_lite_clear(&dest_buf, &rect, 0));
LV_VG_LITE_CHECK_ERROR(vg_lite_finish());
return;
}
#endif
uint8_t px_size = lv_color_format_get_size(color_format);
uint32_t stride = lv_draw_buf_width_to_stride(w, color_format);
uint8_t * bufc = buf;
/*Got the first pixel of each buffer*/
bufc += stride * a->y1;
bufc += a->x1 * px_size;
uint32_t line_length = lv_area_get_width(a) * px_size;
int32_t y;
for(y = a->y1; y <= a->y2; y++) {
lv_memzero(bufc, line_length);
bufc += stride;
}
}
static void buf_copy(void * dest_buf, uint32_t dest_w, uint32_t dest_h, const lv_area_t * dest_area_to_copy,
void * src_buf, uint32_t src_w, uint32_t src_h, const lv_area_t * src_area_to_copy,
lv_color_format_t color_format)
{
#if 0
if(LV_VG_LITE_IS_ALIGNED(dest_buf, LV_VG_LITE_BUF_ALIGN)
&& LV_VG_LITE_IS_ALIGNED(src_buf, LV_VG_LITE_BUF_ALIGN)) {
vg_lite_buffer_t dest;
LV_ASSERT(lv_vg_lite_buffer_init(&dest, dest_buf, dest_w, dest_h, lv_vg_lite_vg_fmt(color_format), false));
LV_VG_LITE_ASSERT_DEST_BUFFER(&dest);
vg_lite_buffer_t src;
LV_ASSERT(lv_vg_lite_buffer_init(&src, src_buf, src_w, src_h, lv_vg_lite_vg_fmt(color_format), false));
LV_VG_LITE_ASSERT_SRC_BUFFER(&src);
vg_lite_rectangle_t src_rect;
lv_vg_lite_rect(&src_rect, src_area_to_copy);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
LV_VG_LITE_CHECK_ERROR(vg_lite_blit_rect(&dest, &src,
&src_rect,
&matrix,
VG_LITE_BLEND_NONE, 0,
VG_LITE_FILTER_POINT));
LV_VG_LITE_CHECK_ERROR(vg_lite_finish());
return;
}
#endif
uint8_t px_size = lv_color_format_get_size(color_format);
uint8_t * dest_bufc = dest_buf;
uint8_t * src_bufc = src_buf;
uint32_t dest_stride = lv_draw_buf_width_to_stride(dest_w, color_format);
uint32_t src_stride = lv_draw_buf_width_to_stride(src_w, color_format);
/*Got the first pixel of each buffer*/
dest_bufc += dest_stride * dest_area_to_copy->y1;
dest_bufc += dest_area_to_copy->x1 * px_size;
src_bufc += src_stride * src_area_to_copy->y1;
src_bufc += src_area_to_copy->x1 * px_size;
uint32_t line_length = lv_area_get_width(dest_area_to_copy) * px_size;
int32_t y;
for(y = dest_area_to_copy->y1; y <= dest_area_to_copy->y2; y++) {
lv_memcpy(dest_bufc, src_bufc, line_length);
dest_bufc += dest_stride;
src_bufc += src_stride;
}
}
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,241 @@
/**
* @file lv_vg_lite_draw.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "../lv_draw.h"
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
#include "lv_vg_lite_decoder.h"
/*********************
* DEFINES
*********************/
#define VG_LITE_DRAW_UNIT_ID 2
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static int32_t draw_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
static int32_t draw_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
static int32_t draw_delete(lv_draw_unit_t * draw_unit);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_init(void)
{
#if LV_VG_LITE_USE_GPU_INIT
extern void gpu_init(void);
static bool inited = false;
if(!inited) {
gpu_init();
inited = true;
}
#endif
lv_vg_lite_dump_info();
lv_draw_buf_vg_lite_init_handlers();
lv_draw_vg_lite_unit_t * unit = lv_draw_create_unit(sizeof(lv_draw_vg_lite_unit_t));
unit->base_unit.dispatch_cb = draw_dispatch;
unit->base_unit.evaluate_cb = draw_evaluate;
unit->base_unit.delete_cb = draw_delete;
lv_vg_lite_path_init(unit);
lv_vg_lite_decoder_init();
}
void lv_draw_vg_lite_deinit(void)
{
}
/**********************
* STATIC FUNCTIONS
**********************/
static void draw_execute(lv_draw_vg_lite_unit_t * u)
{
lv_draw_task_t * t = u->task_act;
lv_draw_unit_t * draw_unit = (lv_draw_unit_t *)u;
lv_layer_t * layer = u->base_unit.target_layer;
lv_vg_lite_buffer_init(
&u->target_buffer,
layer->buf,
lv_area_get_width(&layer->buf_area),
lv_area_get_height(&layer->buf_area),
lv_vg_lite_vg_fmt(layer->color_format),
false);
vg_lite_identity(&u->global_matrix);
vg_lite_translate(-layer->buf_area.x1, -layer->buf_area.y1, &u->global_matrix);
switch(t->type) {
case LV_DRAW_TASK_TYPE_LABEL:
lv_draw_vg_lite_label(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_FILL:
lv_draw_vg_lite_fill(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_BORDER:
lv_draw_vg_lite_border(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
lv_draw_vg_lite_box_shadow(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_IMAGE:
lv_draw_vg_lite_img(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_ARC:
lv_draw_vg_lite_arc(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_LINE:
lv_draw_vg_lite_line(draw_unit, t->draw_dsc);
break;
case LV_DRAW_TASK_TYPE_LAYER:
lv_draw_vg_lite_layer(draw_unit, t->draw_dsc, &t->area);
break;
case LV_DRAW_TASK_TYPE_TRIANGLE:
lv_draw_vg_lite_triangle(draw_unit, t->draw_dsc);
break;
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
lv_draw_vg_lite_mask_rect(draw_unit, t->draw_dsc, &t->area);
break;
#if LV_USE_VECTOR_GRAPHIC
case LV_DRAW_TASK_TYPE_VECTOR:
lv_draw_vg_lite_vector(draw_unit, t->draw_dsc);
break;
#endif
default:
break;
}
#if LV_USE_PARALLEL_DRAW_DEBUG
/* Layers manage it for themselves. */
if(t->type != LV_DRAW_TASK_TYPE_LAYER) {
}
#endif
LV_VG_LITE_CHECK_ERROR(vg_lite_finish());
}
static int32_t draw_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer)
{
lv_draw_vg_lite_unit_t * draw_vg_lite_unit = (lv_draw_vg_lite_unit_t *)draw_unit;
/* Return immediately if it's busy with draw task. */
if(draw_vg_lite_unit->task_act) {
return 0;
}
/* Return if target buffer format is not supported. */
if(!lv_vg_lite_is_dest_cf_supported(layer->color_format)) {
return -1;
}
/* Try to get an ready to draw. */
lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, VG_LITE_DRAW_UNIT_ID);
/* Return 0 is no selection, some tasks can be supported by other units. */
if(!t || t->preferred_draw_unit_id != VG_LITE_DRAW_UNIT_ID) {
return -1;
}
void * buf = lv_draw_layer_alloc_buf(layer);
if(!buf) {
return -1;
}
t->state = LV_DRAW_TASK_STATE_IN_PROGRESS;
draw_vg_lite_unit->base_unit.target_layer = layer;
draw_vg_lite_unit->base_unit.clip_area = &t->clip_area;
draw_vg_lite_unit->task_act = t;
draw_execute(draw_vg_lite_unit);
draw_vg_lite_unit->task_act->state = LV_DRAW_TASK_STATE_READY;
draw_vg_lite_unit->task_act = NULL;
/* The draw unit is free now. Request a new dispatching as it can get a new task. */
lv_draw_dispatch_request();
return 1;
}
static int32_t draw_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
{
LV_UNUSED(draw_unit);
switch(task->type) {
#if LV_USE_FREETYPE && LV_FREETYPE_CACHE_TYPE == LV_FREETYPE_CACHE_TYPE_OUTLINE
case LV_DRAW_TASK_TYPE_LABEL: {
const lv_draw_label_dsc_t * label_dsc = task->draw_dsc;
if(lv_freetype_is_outline_font(label_dsc->font)) {
task->preference_score = 0;
task->preferred_draw_unit_id = VG_LITE_DRAW_UNIT_ID;
return 1;
}
return 0;
}
#endif
case LV_DRAW_TASK_TYPE_FILL:
case LV_DRAW_TASK_TYPE_BORDER:
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
case LV_DRAW_TASK_TYPE_IMAGE:
case LV_DRAW_TASK_TYPE_LAYER:
case LV_DRAW_TASK_TYPE_LINE:
case LV_DRAW_TASK_TYPE_ARC:
case LV_DRAW_TASK_TYPE_TRIANGLE:
// case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
// case LV_DRAW_TASK_TYPE_MASK_BITMAP:
#if LV_USE_VECTOR_GRAPHIC
case LV_DRAW_TASK_TYPE_VECTOR:
#endif
task->preference_score = 80;
task->preferred_draw_unit_id = VG_LITE_DRAW_UNIT_ID;
return 1;
default:
break;
}
return 0;
}
static int32_t draw_delete(lv_draw_unit_t * draw_unit)
{
lv_draw_vg_lite_unit_t * unit = (lv_draw_vg_lite_unit_t *)draw_unit;
lv_vg_lite_path_deinit(unit);
lv_vg_lite_decoder_deinit();
return 1;
}
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,84 @@
/**
* @file lv_vg_lite_draw.h
*
*/
#ifndef LV_VG_LITE_DRAW_H
#define LV_VG_LITE_DRAW_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_DRAW_VG_LITE
#include "../lv_draw.h"
#include "../../draw/lv_draw_vector.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_draw_buf_vg_lite_init_handlers(void);
void lv_draw_vg_lite_init(void);
void lv_draw_vg_lite_deinit(void);
void lv_draw_vg_lite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_box_shadow(lv_draw_unit_t * draw_unit, const lv_draw_box_shadow_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
void lv_draw_vg_lite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc);
void lv_draw_vg_lite_triangle(lv_draw_unit_t * draw_unit, const lv_draw_triangle_dsc_t * dsc);
void lv_draw_vg_lite_mask_rect(lv_draw_unit_t * draw_unit, const lv_draw_mask_rect_dsc_t * dsc,
const lv_area_t * coords);
#if LV_USE_VECTOR_GRAPHIC
void lv_draw_vg_lite_vector(lv_draw_unit_t * draw_unit, const lv_draw_vector_task_dsc_t * dsc);
#endif
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_DRAW_H*/

View File

@@ -0,0 +1,200 @@
/**
* @file lv_draw_vg_lite_arc.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_math.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
#include <math.h>
/*********************
* DEFINES
*********************/
#define PI 3.1415926535897932384626433832795
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define radians(deg) ((deg) * DEG_TO_RAD)
#define degrees(rad) ((rad) * RAD_TO_DEG)
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN)
return;
if(dsc->width <= 0)
return;
if(dsc->start_angle == dsc->end_angle)
return;
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
/*Fully clipped, nothing to do*/
return;
}
float start_angle = dsc->start_angle;
float end_angle = dsc->end_angle;
float sweep_angle = end_angle - start_angle;
while(sweep_angle < 0) {
sweep_angle += 360;
}
while(sweep_angle > 360) {
sweep_angle -= 360;
}
/*If the angles are the same then there is nothing to draw*/
if(math_zero(sweep_angle)) {
return;
}
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_FP32);
lv_vg_lite_path_set_quality(path, VG_LITE_HIGH);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
float radius_out = dsc->radius;
float radius_in = dsc->radius - dsc->width;
float half_width = dsc->width * 0.5f;
float radius_center = radius_out - half_width;
float cx = dsc->center.x;
float cy = dsc->center.y;
vg_lite_fill_t fill = VG_LITE_FILL_NON_ZERO;
if(math_equal(sweep_angle, 360)) {
lv_vg_lite_path_append_circle(path, cx, cy, radius_out, radius_out);
lv_vg_lite_path_append_circle(path, cx, cy, radius_in, radius_in);
fill = VG_LITE_FILL_EVEN_ODD;
}
else {
/* radius_out start point */
float start_angle_rad = MATH_RADIANS(start_angle);
float start_x = radius_out * MATH_COSF(start_angle_rad) + cx;
float start_y = radius_out * MATH_SINF(start_angle_rad) + cy;
/* radius_in start point */
float end_angle_rad = MATH_RADIANS(end_angle);
float end_x = radius_in * MATH_COSF(end_angle_rad) + cx;
float end_y = radius_in * MATH_SINF(end_angle_rad) + cy;
/* radius_out arc */
lv_vg_lite_path_append_arc(path,
cx, cy,
radius_out,
start_angle,
sweep_angle,
false);
/* line to radius_in */
lv_vg_lite_path_line_to(path, end_x, end_y);
/* radius_in arc */
lv_vg_lite_path_append_arc(path,
cx, cy,
radius_in,
end_angle,
-sweep_angle,
false);
/* close arc */
lv_vg_lite_path_line_to(path, start_x, start_y);
lv_vg_lite_path_close(path);
/* draw round */
if(dsc->rounded && half_width > 0) {
float rcx1 = cx + radius_center * MATH_COSF(end_angle_rad);
float rcy1 = cy + radius_center * MATH_SINF(end_angle_rad);
lv_vg_lite_path_append_circle(path, rcx1, rcy1, half_width, half_width);
float rcx2 = cx + radius_center * MATH_COSF(start_angle_rad);
float rcy2 = cy + radius_center * MATH_SINF(start_angle_rad);
lv_vg_lite_path_append_circle(path, rcx2, rcy2, half_width, half_width);
}
}
lv_vg_lite_path_end(path);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_lite_path,
fill,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color));
if(dsc->img_src) {
vg_lite_buffer_t src_buf;
lv_image_decoder_dsc_t decoder_dsc;
if(lv_vg_lite_buffer_open_image(&src_buf, &decoder_dsc, dsc->img_src)) {
vg_lite_matrix_t path_matrix;
vg_lite_identity(&path_matrix);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
&u->target_buffer,
vg_lite_path,
fill,
&path_matrix,
&src_buf,
&matrix,
VG_LITE_BLEND_SRC_OVER,
VG_LITE_PATTERN_COLOR,
0,
color,
VG_LITE_FILTER_BI_LINEAR));
lv_image_decoder_close(&decoder_dsc);
}
}
lv_vg_lite_path_drop(u, path);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,115 @@
/**
* @file lv_draw_vg_lite_border.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_utils.h"
#include "lv_vg_lite_path.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
if(dsc->side == LV_BORDER_SIDE_NONE)
return;
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
/*Fully clipped, nothing to do*/
return;
}
int32_t w = lv_area_get_width(coords);
int32_t h = lv_area_get_height(coords);
int32_t r_out = dsc->radius;
if(r_out) {
int32_t r_short = LV_MIN(w, h) / 2;
r_out = LV_MIN(r_out, r_short);
}
int32_t border_w = dsc->width;
int32_t r_in = LV_MAX(0, r_out - border_w);
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_S16);
lv_vg_lite_path_set_quality(path, dsc->radius == 0 ? VG_LITE_LOW : VG_LITE_HIGH);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
/* outer rect */
lv_vg_lite_path_append_rect(path,
coords->x1, coords->y1,
w, h,
r_out, r_out);
/* inner rect */
lv_vg_lite_path_append_rect(path,
coords->x1 + border_w, coords->y1 + border_w,
w - border_w * 2, h - border_w * 2,
r_in, r_in);
lv_vg_lite_path_end(path);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color));
lv_vg_lite_path_drop(u, path);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,97 @@
/**
* @file lv_draw_vg_lite_box_shadow.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_box_shadow(lv_draw_unit_t * draw_unit, const lv_draw_box_shadow_dsc_t * dsc,
const lv_area_t * coords)
{
/*Calculate the rectangle which is blurred to get the shadow in `shadow_area`*/
lv_area_t core_area;
core_area.x1 = coords->x1 + dsc->ofs_x - dsc->spread;
core_area.x2 = coords->x2 + dsc->ofs_x + dsc->spread;
core_area.y1 = coords->y1 + dsc->ofs_y - dsc->spread;
core_area.y2 = coords->y2 + dsc->ofs_y + dsc->spread;
/*Calculate the bounding box of the shadow*/
lv_area_t shadow_area;
shadow_area.x1 = core_area.x1 - dsc->width / 2 - 1;
shadow_area.x2 = core_area.x2 + dsc->width / 2 + 1;
shadow_area.y1 = core_area.y1 - dsc->width / 2 - 1;
shadow_area.y2 = core_area.y2 + dsc->width / 2 + 1;
lv_opa_t opa = dsc->opa;
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
/*Get clipped draw area which is the real draw area.
*It is always the same or inside `shadow_area`*/
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &shadow_area, draw_unit->clip_area)) return;
lv_draw_border_dsc_t border_dsc;
lv_draw_border_dsc_init(&border_dsc);
border_dsc.width = 3;
border_dsc.color = dsc->color;
border_dsc.radius = dsc->radius;
lv_area_move(&draw_area, dsc->ofs_x, dsc->ofs_y);
draw_area = core_area;
int32_t half_w = dsc->width / 2;
for(int32_t w = 0; w < half_w; w++) {
border_dsc.opa = lv_map(w, 0, half_w, dsc->opa / 4, LV_OPA_0);
border_dsc.radius++;
lv_area_increase(&draw_area, 1, 1);
lv_draw_vg_lite_border(draw_unit, &border_dsc, &draw_area);
/* fill center */
if(dsc->ofs_x || dsc->ofs_y) {
lv_draw_fill_dsc_t fill_dsc;
lv_draw_fill_dsc_init(&fill_dsc);
fill_dsc.radius = dsc->radius;
fill_dsc.opa = dsc->opa;
fill_dsc.color = dsc->color;
lv_draw_vg_lite_fill(draw_unit, &fill_dsc, &core_area);
}
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,111 @@
/**
* @file lv_draw_vg_lite_fill.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
/*********************
* DEFINES
*********************/
#if LV_GRADIENT_MAX_STOPS > VLC_MAX_GRADIENT_STOPS
#error "LV_GRADIENT_MAX_STOPS must be equal or less than VLC_MAX_GRADIENT_STOPS"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN) {
return;
}
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) {
/*Fully clipped, nothing to do*/
return;
}
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
int32_t w = lv_area_get_width(coords);
int32_t h = lv_area_get_height(coords);
int32_t r = dsc->radius;
if(r) {
int32_t r_short = LV_MIN(w, h) / 2;
r = LV_MIN(r, r_short);
}
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_S16);
lv_vg_lite_path_set_quality(path, dsc->radius == 0 ? VG_LITE_LOW : VG_LITE_HIGH);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
lv_vg_lite_path_append_rect(path, coords->x1, coords->y1, w, h, r, r);
lv_vg_lite_path_end(path);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
if(dsc->grad.dir != LV_GRAD_DIR_NONE) {
lv_vg_lite_draw_linear_grad(
&u->target_buffer,
vg_lite_path,
coords,
&dsc->grad,
&matrix,
VG_LITE_FILL_EVEN_ODD,
VG_LITE_BLEND_SRC_OVER);
}
else { /* normal fill */
vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color));
}
lv_vg_lite_path_drop(u, path);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,155 @@
/**
* @file lv_draw_vg_lite_img.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_decoder.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN) {
return;
}
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
/* The coordinates passed in by coords are not transformed,
* so the transformed area needs to be calculated once.
*/
lv_area_t image_tf_area;
_lv_image_buf_get_transformed_area(
&image_tf_area,
lv_area_get_width(coords),
lv_area_get_height(coords),
dsc->rotation,
dsc->scale_x,
dsc->scale_y,
&dsc->pivot);
lv_area_move(&image_tf_area, coords->x1, coords->y1);
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, &image_tf_area, draw_unit->clip_area)) {
/*Fully clipped, nothing to do*/
return;
}
vg_lite_buffer_t src_buf;
lv_image_decoder_dsc_t decoder_dsc;
if(!lv_vg_lite_buffer_open_image(&src_buf, &decoder_dsc, dsc->src)) {
return;
}
/* image opa */
lv_opa_t opa = dsc->opa;
vg_lite_color_t color = 0;
if(opa < LV_OPA_MAX) {
lv_memset(&color, opa, sizeof(color));
src_buf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
}
bool has_recolor = dsc->recolor_opa >= LV_OPA_MIN;
bool has_trasform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE);
vg_lite_filter_t filter = has_trasform ? VG_LITE_FILTER_BI_LINEAR : VG_LITE_FILTER_POINT;
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
lv_vg_lite_image_matrix(&matrix, coords->x1, coords->y1, dsc);
LV_VG_LITE_ASSERT_SRC_BUFFER(&src_buf);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
/* If clipping is not required, blit directly */
if(_lv_area_is_in(&image_tf_area, draw_unit->clip_area, false) && !has_recolor) {
/* The image area is the coordinates relative to the image itself */
lv_area_t src_area = *coords;
lv_area_move(&src_area, -coords->x1, -coords->y1);
/* rect is used to crop the pixel-aligned padding area */
vg_lite_rectangle_t rect;
lv_vg_lite_rect(&rect, &src_area);
LV_VG_LITE_CHECK_ERROR(vg_lite_blit_rect(
&u->target_buffer,
&src_buf,
&rect,
&matrix,
lv_vg_lite_blend_mode(dsc->blend_mode),
color,
filter));
}
else {
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_S16);
lv_vg_lite_path_append_rect(
path,
clip_area.x1, clip_area.y1,
lv_area_get_width(&clip_area), lv_area_get_height(&clip_area),
0, 0);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
lv_vg_lite_path_end(path);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
vg_lite_matrix_t path_matrix;
vg_lite_identity(&path_matrix);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&path_matrix,
&src_buf,
&matrix,
lv_vg_lite_blend_mode(dsc->blend_mode),
VG_LITE_PATTERN_COLOR,
lv_vg_lite_color(dsc->recolor, dsc->recolor_opa, true),
color,
filter));
lv_vg_lite_path_drop(u, path);
}
lv_image_decoder_close(&decoder_dsc);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,313 @@
/**
* @file lv_draw_vg_lite_label.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#include "../../libs/freetype/lv_freetype.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
#include "lv_vg_lite_path.h"
#include "lv_draw_vg_lite_type.h"
/*********************
* DEFINES
*********************/
#define PATH_QUALITY VG_LITE_MEDIUM
#define PATH_DATA_COORD_FORMAT VG_LITE_S16
#define PATH_REF_SIZE 128
#define FT_F26DOT6_SHIFT 6
/** After converting the font reference size, it is also necessary to scale the 26dot6 data
* in the path to the real physical size
*/
#define FT_F26DOT6_TO_PATH_SCALE(x) (LV_FREETYPE_F26DOT6_TO_FLOAT(x) / (1 << FT_F26DOT6_SHIFT))
#define SUPPORT_OUTLINE_FONT (LV_USE_FREETYPE && LV_FREETYPE_CACHE_TYPE == LV_FREETYPE_CACHE_TYPE_OUTLINE)
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void draw_letter_cb(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc,
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area);
static void draw_letter_bitmap(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_dsc_t * dsc);
#if SUPPORT_OUTLINE_FONT
static void freetype_outline_event_cb(lv_event_t * e);
static void draw_letter_outline(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_dsc_t * dsc);
#endif
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc,
const lv_area_t * coords)
{
if(dsc->opa <= LV_OPA_MIN) return;
#if SUPPORT_OUTLINE_FONT
static bool is_init = false;
if(!is_init) {
lv_freetype_outline_set_ref_size(PATH_REF_SIZE);
lv_freetype_outline_add_event(freetype_outline_event_cb, LV_EVENT_ALL, draw_unit);
is_init = true;
}
#endif /*SUPPORT_OUTLINE_FONT*/
lv_draw_label_iterate_letters(draw_unit, dsc, coords, draw_letter_cb);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void draw_letter_cb(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc,
lv_draw_fill_dsc_t * fill_draw_dsc, const lv_area_t * fill_area)
{
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
if(glyph_draw_dsc) {
if(glyph_draw_dsc->bitmap == NULL) {
#if LV_USE_FONT_PLACEHOLDER
/* Draw a placeholder rectangle*/
lv_draw_border_dsc_t border_draw_dsc;
lv_draw_border_dsc_init(&border_draw_dsc);
border_draw_dsc.opa = glyph_draw_dsc->opa;
border_draw_dsc.color = glyph_draw_dsc->color;
border_draw_dsc.width = 1;
lv_draw_vg_lite_border(draw_unit, &border_draw_dsc, glyph_draw_dsc->bg_coords);
#endif
}
else if(glyph_draw_dsc->format == LV_DRAW_LETTER_BITMAP_FORMAT_A8
|| glyph_draw_dsc->format == LV_DRAW_LETTER_BITMAP_FORMAT_IMAGE) {
#if SUPPORT_OUTLINE_FONT
if(lv_freetype_is_outline_font(glyph_draw_dsc->g->resolved_font)) {
draw_letter_outline(u, glyph_draw_dsc);
}
else
#endif /*SUPPORT_OUTLINE_FONT*/
{
draw_letter_bitmap(u, glyph_draw_dsc);
}
}
}
if(fill_draw_dsc && fill_area) {
lv_draw_vg_lite_fill(draw_unit, fill_draw_dsc, fill_area);
}
}
static void draw_letter_bitmap(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_dsc_t * dsc)
{
lv_area_t clip_area;
if(!_lv_area_intersect(&clip_area, u->base_unit.clip_area, dsc->letter_coords)) {
return;
}
lv_area_t image_area = *dsc->letter_coords;
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
vg_lite_translate(image_area.x1, image_area.y1, &matrix);
vg_lite_buffer_t src_buf;
lv_vg_lite_buffer_init(
&src_buf,
dsc->bitmap,
lv_area_get_width(&image_area),
lv_area_get_height(&image_area),
VG_LITE_A8,
false);
vg_lite_color_t color;
color = lv_vg_lite_color(dsc->color, dsc->opa, true);
LV_VG_LITE_ASSERT_SRC_BUFFER(&src_buf);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
/* If clipping is not required, blit directly */
if(_lv_area_is_in(&image_area, u->base_unit.clip_area, false)) {
/* The image area is the coordinates relative to the image itself */
lv_area_t src_area = image_area;
lv_area_move(&src_area, -image_area.x1, -image_area.y1);
/* rect is used to crop the pixel-aligned padding area */
vg_lite_rectangle_t rect;
lv_vg_lite_rect(&rect, &src_area);
LV_VG_LITE_CHECK_ERROR(vg_lite_blit_rect(
&u->target_buffer,
&src_buf,
&rect,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color,
VG_LITE_FILTER_LINEAR));
}
else {
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_S16);
lv_vg_lite_path_append_rect(
path,
clip_area.x1, clip_area.y1,
lv_area_get_width(&clip_area), lv_area_get_height(&clip_area),
0, 0);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
lv_vg_lite_path_end(path);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
vg_lite_matrix_t path_matrix;
vg_lite_identity(&path_matrix);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&path_matrix,
&src_buf,
&matrix,
VG_LITE_BLEND_SRC_OVER,
VG_LITE_PATTERN_COLOR,
color,
color,
VG_LITE_FILTER_LINEAR));
lv_vg_lite_path_drop(u, path);
}
}
#if SUPPORT_OUTLINE_FONT
static void draw_letter_outline(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_dsc_t * dsc)
{
/* get clip area */
lv_area_t path_clip_area;
if(!_lv_area_intersect(&path_clip_area, u->base_unit.clip_area, dsc->letter_coords)) {
return;
}
/* vg-lite bounding_box will crop the pixels on the edge, so +1px is needed here */
path_clip_area.x2++;
path_clip_area.y2++;
lv_vg_lite_path_t * outline = (lv_vg_lite_path_t *)dsc->bitmap;
lv_point_t pos = {dsc->letter_coords->x1, dsc->letter_coords->y1};
/* calc convert matrix */
float scale = FT_F26DOT6_TO_PATH_SCALE(lv_freetype_outline_get_scale(dsc->g->resolved_font));
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
/* convert to vg-lite coordinate */
vg_lite_translate(pos.x - dsc->g->ofs_x, pos.y + dsc->g->box_h + dsc->g->ofs_y, &matrix);
/* scale size */
vg_lite_scale(scale, scale, &matrix);
/* Cartesian coordinates to LCD coordinates */
lv_vg_lite_matrix_flip_y(&matrix);
/* calc inverse matrix */
vg_lite_matrix_t result;
if(!lv_vg_lite_matrix_inverse(&result, &matrix)) {
LV_LOG_ERROR("no inverse matrix");
return;
}
lv_point_precise_t p1 = { path_clip_area.x1, path_clip_area.y1 };
lv_point_precise_t p1_res = lv_vg_lite_matrix_transform_point(&result, &p1);
lv_point_precise_t p2 = { path_clip_area.x2, path_clip_area.y2 };
lv_point_precise_t p2_res = lv_vg_lite_matrix_transform_point(&result, &p2);
/* Since the font uses Cartesian coordinates, the y coordinates need to be reversed */
lv_vg_lite_path_set_bonding_box(outline, p1_res.x, p2_res.y, p2_res.x, p1_res.y);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(outline);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer, vg_lite_path, VG_LITE_FILL_NON_ZERO,
&matrix, VG_LITE_BLEND_SRC_OVER, lv_vg_lite_color(dsc->color, dsc->opa, true)));
}
static void vg_lite_outline_push(const lv_freetype_outline_event_param_t * param)
{
lv_vg_lite_path_t * outline = param->outline;
LV_ASSERT_NULL(outline);
lv_freetype_outline_type_t type = param->type;
switch(type) {
case LV_FREETYPE_OUTLINE_END:
lv_vg_lite_path_end(outline);
break;
case LV_FREETYPE_OUTLINE_MOVE_TO:
lv_vg_lite_path_move_to(outline, param->to.x, param->to.y);
break;
case LV_FREETYPE_OUTLINE_LINE_TO:
lv_vg_lite_path_line_to(outline, param->to.x, param->to.y);
break;
case LV_FREETYPE_OUTLINE_CUBIC_TO:
lv_vg_lite_path_cubic_to(outline, param->control1.x, param->control1.y,
param->control2.x, param->control2.y,
param->to.x, param->to.y);
break;
case LV_FREETYPE_OUTLINE_CONIC_TO:
lv_vg_lite_path_quad_to(outline, param->control1.x, param->control1.y,
param->to.x, param->to.y);
break;
default:
LV_LOG_ERROR("unknown point type: %d", type);
LV_ASSERT(false);
break;
}
}
static void freetype_outline_event_cb(lv_event_t * e)
{
lv_event_code_t code = lv_event_get_code(e);
lv_freetype_outline_event_param_t * param = lv_event_get_param(e);
switch(code) {
case LV_EVENT_CREATE:
param->outline = lv_vg_lite_path_create(PATH_DATA_COORD_FORMAT);
break;
case LV_EVENT_DELETE:
lv_vg_lite_path_destroy(param->outline);
break;
case LV_EVENT_INSERT:
vg_lite_outline_push(param);
break;
default:
LV_LOG_WARN("unknown event code: %d", code);
break;
}
}
#endif /*SUPPORT_OUTLINE_FONT*/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,72 @@
/**
* @file lv_draw_vg_lite_layer.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
#include "lv_draw_vg_lite_type.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords)
{
lv_layer_t * layer = (lv_layer_t *)draw_dsc->src;
/*It can happen that nothing was draw on a layer and therefore its buffer is not allocated.
*In this case just return. */
if(layer->buf == NULL)
return;
lv_image_dsc_t img_dsc;
lv_memzero(&img_dsc, sizeof(lv_image_dsc_t));
img_dsc.header.w = lv_area_get_width(&layer->buf_area);
img_dsc.header.h = lv_area_get_height(&layer->buf_area);
img_dsc.header.cf = layer->color_format;
img_dsc.header.always_zero = 0;
img_dsc.data = layer->buf;
lv_draw_image_dsc_t new_draw_dsc = *draw_dsc;
new_draw_dsc.src = &img_dsc;
lv_draw_vg_lite_img(draw_unit, &new_draw_dsc, coords);
lv_cache_lock();
lv_cache_invalidate_by_src(&img_dsc, LV_CACHE_SRC_TYPE_POINTER);
lv_cache_unlock();
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,211 @@
/**
* @file lv_draw_vg_lite_line.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_math.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
/*********************
* DEFINES
*********************/
#define SQ(x) ((x) * (x))
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc)
{
if(dsc->opa <= LV_OPA_MIN)
return;
if(dsc->width == 0)
return;
float p1_x = dsc->p1.x;
float p1_y = dsc->p1.y;
float p2_x = dsc->p2.x;
float p2_y = dsc->p2.y;
if(p1_x == p2_x && p1_y == p2_y)
return;
float half_w = dsc->width * 0.5f;
lv_area_t rel_clip_area;
rel_clip_area.x1 = LV_MIN(p1_x, p2_x) - half_w;
rel_clip_area.x2 = LV_MAX(p1_x, p2_x) + half_w;
rel_clip_area.y1 = LV_MIN(p1_y, p2_y) - half_w;
rel_clip_area.y2 = LV_MAX(p1_y, p2_y) + half_w;
if(!_lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_unit->clip_area)) {
return; /*Fully clipped, nothing to do*/
}
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
int32_t dash_width = dsc->dash_width;
int32_t dash_gap = dsc->dash_gap;
int32_t dash_l = dash_width + dash_gap;
float dx = p2_x - p1_x;
float dy = p2_y - p1_y;
float inv_dl = math_fast_inv_sqrtf(SQ(dx) + SQ(dy));
float w_dx = dsc->width * dy * inv_dl;
float w_dy = dsc->width * dx * inv_dl;
float w2_dx = w_dx / 2;
float w2_dy = w_dy / 2;
int32_t ndash = 0;
if(dash_width && dash_l * inv_dl < 1.0f) {
ndash = (1.0f / inv_dl + dash_l - 1) / dash_l;
}
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_FP32);
lv_vg_lite_path_set_quality(path, VG_LITE_MEDIUM);
lv_vg_lite_path_set_bonding_box_area(path, &rel_clip_area);
/* head point */
float head_start_x = p1_x + w2_dx;
float head_start_y = p1_y - w2_dy;
float head_end_x = p1_x - w2_dx;
float head_end_y = p1_y + w2_dy;
/* tali point */
float tali_start_x = p2_x - w2_dx;
float tali_start_y = p2_y + w2_dy;
float tali_end_x = p2_x + w2_dx;
float tali_end_y = p2_y - w2_dy;
/*
head_start tali_end
*-----------------*
/| |\
/ | | \
arc_c *( *p1 p2* )* arc_c
\ | | /
\| |/
*-----------------*
head_end tali_start
*/
/* move to start point */
lv_vg_lite_path_move_to(path, head_start_x, head_start_y);
/* draw line head */
if(dsc->round_start) {
float arc_cx = p1_x - w2_dy;
float arc_cy = p1_y - w2_dx;
/* start 90deg arc */
lv_vg_lite_path_append_arc_right_angle(path,
head_start_x, head_start_y,
p1_x, p1_y,
arc_cx, arc_cy);
/* end 90deg arc */
lv_vg_lite_path_append_arc_right_angle(path,
arc_cx, arc_cy,
p1_x, p1_y,
head_end_x, head_end_y);
}
else {
lv_vg_lite_path_line_to(path, head_end_x, head_end_y);
}
/* draw line body */
lv_vg_lite_path_line_to(path, tali_start_x, tali_start_y);
/* draw line tail */
if(dsc->round_end) {
float arc_cx = p2_x + w2_dy;
float arc_cy = p2_y + w2_dx;
lv_vg_lite_path_append_arc_right_angle(path,
tali_start_x, tali_start_y,
p2_x, p2_y,
arc_cx, arc_cy);
lv_vg_lite_path_append_arc_right_angle(path,
arc_cx, arc_cy,
p2_x, p2_y,
tali_end_x, tali_end_y);
}
else {
lv_vg_lite_path_line_to(path, tali_end_x, tali_end_y);
}
/* close draw line body */
lv_vg_lite_path_line_to(path, head_start_x, head_start_y);
for(int32_t i = 0; i < ndash; i++) {
float start_x = p1_x - w2_dx + dx * (i * dash_l + dash_width) * inv_dl;
float start_y = p1_y + w2_dy + dy * (i * dash_l + dash_width) * inv_dl;
lv_vg_lite_path_move_to(path, start_x, start_y);
lv_vg_lite_path_line_to(path,
p1_x + w2_dx + dx * (i * dash_l + dash_width) * inv_dl,
p1_y - w2_dy + dy * (i * dash_l + dash_width) * inv_dl);
lv_vg_lite_path_line_to(path,
p1_x + w2_dx + dx * (i + 1) * dash_l * inv_dl,
p1_y - w2_dy + dy * (i + 1) * dash_l * inv_dl);
lv_vg_lite_path_line_to(path,
p1_x - w2_dx + dx * (i + 1) * dash_l * inv_dl,
p1_y + w2_dy + dy * (i + 1) * dash_l * inv_dl);
lv_vg_lite_path_line_to(path, start_x, start_y);
}
lv_vg_lite_path_end(path);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color));
lv_vg_lite_path_drop(u, path);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,94 @@
/**
* @file lv_draw_vg_lite_rect.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
#include "lv_draw_vg_lite_type.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_mask_rect(lv_draw_unit_t * draw_unit, const lv_draw_mask_rect_dsc_t * dsc,
const lv_area_t * coords)
{
LV_UNUSED(coords);
lv_area_t draw_area;
if(!_lv_area_intersect(&draw_area, &dsc->area, draw_unit->clip_area)) {
return;
}
lv_draw_sw_mask_radius_param_t param;
lv_draw_sw_mask_radius_init(&param, &dsc->area, dsc->radius, false);
void * masks[2] = {0};
masks[0] = &param;
uint32_t area_w = lv_area_get_width(&draw_area);
lv_opa_t * mask_buf = lv_malloc(area_w);
int32_t y;
for(y = draw_area.y1; y <= draw_area.y2; y++) {
lv_memset(mask_buf, 0xff, area_w);
lv_draw_sw_mask_res_t res = lv_draw_sw_mask_apply(masks, mask_buf, draw_area.x1, y, area_w);
if(res == LV_DRAW_SW_MASK_RES_FULL_COVER) continue;
lv_layer_t * target_layer = draw_unit->target_layer;
lv_color32_t * c32_buf = lv_draw_layer_go_to_xy(target_layer, draw_area.x1 - target_layer->buf_area.x1,
y - target_layer->buf_area.y1);
if(res == LV_DRAW_SW_MASK_RES_TRANSP) {
uint32_t i;
for(i = 0; i < area_w; i++) {
c32_buf[i].alpha = 0x00;
}
}
else {
uint32_t i;
for(i = 0; i < area_w; i++) {
if(mask_buf[i] != LV_OPA_COVER) {
c32_buf[i].alpha = LV_OPA_MIX2(c32_buf[i].alpha, mask_buf[i]);
}
}
}
}
lv_free(mask_buf);
lv_draw_sw_mask_free_param(&param);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,104 @@
/**
* @file lv_draw_vg_lite_triangle.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
#include "lv_vg_lite_path.h"
#include "lv_draw_vg_lite_type.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_triangle(lv_draw_unit_t * draw_unit, const lv_draw_triangle_dsc_t * dsc)
{
if(dsc->bg_opa <= LV_OPA_MIN) return;
lv_area_t tri_area;
tri_area.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
tri_area.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
tri_area.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x);
tri_area.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y);
bool is_common;
lv_area_t clip_area;
is_common = _lv_area_intersect(&clip_area, &tri_area, draw_unit->clip_area);
if(!is_common) return;
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)draw_unit;
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_FP32);
lv_vg_lite_path_set_bonding_box_area(path, &clip_area);
lv_vg_lite_path_move_to(path, dsc->p[0].x, dsc->p[0].y);
lv_vg_lite_path_line_to(path, dsc->p[1].x, dsc->p[1].y);
lv_vg_lite_path_line_to(path, dsc->p[2].x, dsc->p[2].y);
lv_vg_lite_path_close(path);
lv_vg_lite_path_end(path);
vg_lite_path_t * vg_lite_path = lv_vg_lite_path_get_path(path);
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
LV_VG_LITE_ASSERT_PATH(vg_lite_path);
vg_lite_matrix_t matrix;
vg_lite_identity(&matrix);
lv_vg_lite_matrix_multiply(&matrix, &u->global_matrix);
if(dsc->bg_grad.dir != LV_GRAD_DIR_NONE) {
lv_vg_lite_draw_linear_grad(
&u->target_buffer,
vg_lite_path,
&tri_area,
&dsc->bg_grad,
&matrix,
VG_LITE_FILL_EVEN_ODD,
VG_LITE_BLEND_SRC_OVER);
}
else { /* normal fill */
vg_lite_color_t color = lv_vg_lite_color(dsc->bg_color, dsc->bg_opa, true);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_lite_path,
VG_LITE_FILL_EVEN_ODD,
&matrix,
VG_LITE_BLEND_SRC_OVER,
color));
}
lv_vg_lite_path_drop(u, path);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif

View File

@@ -0,0 +1,55 @@
/**
* @file lv_draw_vg_lite_type.h
*
*/
#ifndef LV_DRAW_VG_LITE_TYPE_H
#define LV_DRAW_VG_LITE_TYPE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_DRAW_VG_LITE
#include "../lv_draw.h"
#include <vg_lite.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_draw_vg_lite_unit_t {
lv_draw_unit_t base_unit;
struct _lv_draw_task_t * task_act;
vg_lite_buffer_t target_buffer;
vg_lite_matrix_t global_matrix;
lv_ll_t path_free_ll;
int path_max_cnt;
} lv_draw_vg_lite_unit_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_DRAW_H*/

View File

@@ -0,0 +1,317 @@
/**
* @file lv_draw_vg_lite_vector.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_vg_lite.h"
#if LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc);
static void lv_matrix_to_vg(vg_lite_matrix_t * desy, const lv_matrix_t * src);
static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src);
static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend);
static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule);
static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_vg_lite_vector(lv_draw_unit_t * draw_unit, const lv_draw_vector_task_dsc_t * dsc)
{
if(dsc->task_list == NULL)
return;
lv_layer_t * layer = dsc->base.layer;
if(layer->buf == NULL)
return;
_lv_vector_for_each_destroy_tasks(dsc->task_list, task_draw_cb, draw_unit);
}
/**********************
* STATIC FUNCTIONS
**********************/
static vg_lite_color_t lv_color32_to_vg(lv_color32_t color, lv_opa_t opa)
{
uint8_t a = LV_OPA_MIX2(color.alpha, opa);
if(a < LV_OPA_MAX) {
color.red = LV_UDIV255(color.red * opa);
color.green = LV_UDIV255(color.green * opa);
color.blue = LV_UDIV255(color.blue * opa);
}
return (uint32_t)a << 24 | (uint32_t)color.blue << 16 | (uint32_t)color.green << 8 | color.red;
}
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc)
{
lv_draw_vg_lite_unit_t * u = ctx;
LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
/* clear area */
if(!path) {
/* clear color needs to ignore fill_dsc.opa */
vg_lite_color_t c = lv_color32_to_vg(dsc->fill_dsc.color, LV_OPA_COVER);
vg_lite_rectangle_t rect;
lv_vg_lite_rect(&rect, &dsc->scissor_area);
LV_VG_LITE_CHECK_ERROR(vg_lite_clear(&u->target_buffer, &rect, c));
return;
}
/* set scissor area */
lv_vg_lite_set_scissor_area(&dsc->scissor_area);
/* convert color */
vg_lite_color_t vg_color = lv_color32_to_vg(dsc->fill_dsc.color, dsc->fill_dsc.opa);
/* transform matrix */
vg_lite_matrix_t matrix;
lv_matrix_to_vg(&matrix, &dsc->matrix);
/* convert path */
lv_vg_lite_path_t * lv_vg_path = lv_vg_lite_path_get(u, VG_LITE_FP32);
lv_path_to_vg(lv_vg_path, path);
vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(lv_vg_path);
LV_VG_LITE_ASSERT_PATH(vg_path);
/* convert blend mode and fill rule */
vg_lite_blend_t blend = lv_blend_to_vg(dsc->blend_mode);
vg_lite_fill_t fill = lv_fill_to_vg(dsc->fill_dsc.fill_rule);
/* get path bounds */
float min_x, min_y, max_x, max_y;
lv_vg_lite_path_get_bonding_box(lv_vg_path, &min_x, &min_y, &max_x, &max_y);
switch(dsc->fill_dsc.style) {
case LV_VECTOR_DRAW_STYLE_SOLID: {
/* normal draw shape */
LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
&u->target_buffer,
vg_path,
fill,
&matrix,
blend,
vg_color));
}
break;
case LV_VECTOR_DRAW_STYLE_PATTERN: {
/* draw image */
vg_lite_buffer_t image_buffer;
lv_image_decoder_dsc_t decoder_dsc;
if(lv_vg_lite_buffer_open_image(&image_buffer, &decoder_dsc, dsc->fill_dsc.img_dsc.src)) {
lv_matrix_t m = dsc->matrix;
lv_matrix_translate(&m, min_x, min_y);
lv_matrix_multiply(&m, &dsc->fill_dsc.matrix);
vg_lite_matrix_t src_matrix;
lv_matrix_to_vg(&src_matrix, &m);
vg_lite_matrix_t path_matrix;
vg_lite_identity(&path_matrix);
vg_lite_color_t recolor = lv_vg_lite_color(dsc->fill_dsc.img_dsc.recolor, dsc->fill_dsc.img_dsc.recolor_opa, true);
LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
&u->target_buffer,
vg_path,
fill,
&path_matrix,
&image_buffer,
&src_matrix,
blend,
VG_LITE_PATTERN_COLOR,
recolor,
vg_color,
VG_LITE_FILTER_BI_LINEAR));
lv_image_decoder_close(&decoder_dsc);
}
}
break;
case LV_VECTOR_DRAW_STYLE_GRADIENT: {
/* draw gradient */
lv_area_t grad_area;
lv_area_set(&grad_area, min_x, min_y, max_x, max_y);
lv_vector_gradient_style_t style = dsc->fill_dsc.gradient.style;
vg_lite_gradient_spreadmode_t spreadmode = lv_spread_to_vg(dsc->fill_dsc.gradient.spread);
LV_UNUSED(spreadmode);
if(style == LV_VECTOR_GRADIENT_STYLE_LINEAR) {
lv_vg_lite_draw_linear_grad(
&u->target_buffer,
vg_path,
&grad_area,
&dsc->fill_dsc.gradient.grad,
&matrix,
fill,
blend);
}
else if(style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
if(vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) {
/* TODO: radial gradient */
}
else {
LV_LOG_WARN("radial gradient is not supported");
}
}
}
break;
default:
LV_LOG_WARN("unknown style: %d", dsc->fill_dsc.style);
break;
}
/* drop path */
lv_vg_lite_path_drop(u, lv_vg_path);
/* disable scissor */
lv_vg_lite_disable_scissor();
}
static void lv_matrix_to_vg(vg_lite_matrix_t * dest, const lv_matrix_t * src)
{
lv_memcpy(dest, src, sizeof(lv_matrix_t));
}
static vg_lite_quality_t lv_quality_to_vg(lv_vector_path_quality_t quality)
{
switch(quality) {
case LV_VECTOR_PATH_QUALITY_LOW:
return VG_LITE_LOW;
case LV_VECTOR_PATH_QUALITY_MEDIUM:
return VG_LITE_MEDIUM;
case LV_VECTOR_PATH_QUALITY_HIGH:
return VG_LITE_HIGH;
default:
return VG_LITE_MEDIUM;
}
}
static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src)
{
lv_vg_lite_path_set_quality(dest, lv_quality_to_vg(src->quality));
uint32_t pidx = 0;
for(uint32_t i = 0; i < src->ops.size; i++) {
lv_vector_path_op_t * op = LV_ARRAY_GET(&src->ops, i, uint8_t);
switch(*op) {
case LV_VECTOR_PATH_OP_MOVE_TO: {
lv_fpoint_t * pt = LV_ARRAY_GET(&src->points, pidx, lv_fpoint_t);
lv_vg_lite_path_move_to(dest, pt->x, pt->y);
pidx += 1;
}
break;
case LV_VECTOR_PATH_OP_LINE_TO: {
lv_fpoint_t * pt = LV_ARRAY_GET(&src->points, pidx, lv_fpoint_t);
lv_vg_lite_path_line_to(dest, pt->x, pt->y);
pidx += 1;
}
break;
case LV_VECTOR_PATH_OP_QUAD_TO: {
lv_fpoint_t * pt1 = LV_ARRAY_GET(&src->points, pidx, lv_fpoint_t);
lv_fpoint_t * pt2 = LV_ARRAY_GET(&src->points, pidx + 1, lv_fpoint_t);
lv_vg_lite_path_quad_to(dest, pt1->x, pt1->y, pt2->x, pt2->y);
pidx += 2;
}
break;
case LV_VECTOR_PATH_OP_CUBIC_TO: {
lv_fpoint_t * pt1 = LV_ARRAY_GET(&src->points, pidx, lv_fpoint_t);
lv_fpoint_t * pt2 = LV_ARRAY_GET(&src->points, pidx + 1, lv_fpoint_t);
lv_fpoint_t * pt3 = LV_ARRAY_GET(&src->points, pidx + 2, lv_fpoint_t);
lv_vg_lite_path_cubic_to(dest, pt1->x, pt1->y, pt2->x, pt2->y, pt3->x, pt3->y);
pidx += 3;
}
break;
case LV_VECTOR_PATH_OP_CLOSE: {
lv_vg_lite_path_close(dest);
}
break;
}
}
lv_vg_lite_path_end(dest);
lv_vg_lite_path_update_bonding_box(dest);
}
static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend)
{
switch(blend) {
case LV_VECTOR_BLEND_SRC_OVER:
return VG_LITE_BLEND_SRC_OVER;
case LV_VECTOR_BLEND_SCREEN:
return VG_LITE_BLEND_SCREEN;
case LV_VECTOR_BLEND_MULTIPLY:
return VG_LITE_BLEND_MULTIPLY;
case LV_VECTOR_BLEND_NONE:
return VG_LITE_BLEND_NONE;
case LV_VECTOR_BLEND_ADDITIVE:
return VG_LITE_BLEND_ADDITIVE;
case LV_VECTOR_BLEND_SRC_IN:
return VG_LITE_BLEND_SRC_IN;
case LV_VECTOR_BLEND_DST_OVER:
return VG_LITE_BLEND_DST_OVER;
case LV_VECTOR_BLEND_DST_IN:
return VG_LITE_BLEND_DST_IN;
case LV_VECTOR_BLEND_SUBTRACTIVE:
return VG_LITE_BLEND_SUBTRACT;
default:
return VG_LITE_BLEND_SRC_OVER;
}
}
static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule)
{
switch(fill_rule) {
case LV_VECTOR_FILL_NONZERO:
return VG_LITE_FILL_NON_ZERO;
case LV_VECTOR_FILL_EVENODD:
return VG_LITE_FILL_EVEN_ODD;
default:
return VG_LITE_FILL_NON_ZERO;
}
}
static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread)
{
switch(spread) {
case LV_VECTOR_GRADIENT_SPREAD_PAD:
return VG_LITE_GRADIENT_SPREAD_PAD;
case LV_VECTOR_GRADIENT_SPREAD_REPEAT:
return VG_LITE_GRADIENT_SPREAD_REPEAT;
case LV_VECTOR_GRADIENT_SPREAD_REFLECT:
return VG_LITE_GRADIENT_SPREAD_REFLECT;
default:
return VG_LITE_GRADIENT_SPREAD_FILL;
}
}
#endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/

View File

@@ -0,0 +1,550 @@
/**
* @file lv_vg_lite_decoder.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vg_lite_decoder.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_vg_lite_utils.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
#pragma pack(1)
typedef struct {
lv_color16_t c;
uint8_t alpha;
} lv_color16_alpha_t;
#pragma pack()
/**********************
* STATIC PROTOTYPES
**********************/
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header);
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args);
static void decode_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
static void image_try_self_pre_mul(lv_image_decoder_dsc_t * dsc);
static void image_color32_pre_mul(lv_color32_t * img_data, uint32_t px_size);
static void image_color16_pre_mul(lv_color16_alpha_t * img_data, uint32_t px_size);
static void image_copy(uint8_t * dest, const uint8_t * src,
size_t dest_stride, size_t src_stride,
uint32_t height);
static void image_invalidate_cache(void * buf, uint32_t stride,
uint32_t width, uint32_t height,
lv_color_format_t cf);
static void cache_invalidate_cb(lv_cache_entry_t * entry);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_vg_lite_decoder_init(void)
{
lv_image_decoder_t * decoder = lv_image_decoder_create();
lv_image_decoder_set_info_cb(decoder, decoder_info);
lv_image_decoder_set_open_cb(decoder, decoder_open);
lv_image_decoder_set_close_cb(decoder, decode_close);
decoder->cache_data_type = lv_cache_register_data_type();
}
void lv_vg_lite_decoder_deinit(void)
{
lv_image_decoder_t * dec = NULL;
while((dec = lv_image_decoder_get_next(dec)) != NULL) {
if(dec->info_cb == decoder_info) {
lv_image_decoder_delete(dec);
break;
}
}
}
lv_result_t lv_vg_lite_decoder_post_process(lv_image_decoder_dsc_t * dsc)
{
lv_color_format_t color_format = dsc->header.cf;
lv_result_t res = LV_RESULT_OK;
/* Only support this color format */
switch(color_format) {
case LV_COLOR_FORMAT_ARGB8888:
case LV_COLOR_FORMAT_XRGB8888:
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_RGB888:
case LV_COLOR_FORMAT_RGB565:
break;
default:
return LV_RESULT_OK;
}
lv_cache_entry_t * entry = dsc->cache_entry;
if(!entry) {
LV_LOG_WARN("No detected cache entry, src_type: %d, src: %p",
dsc->src_type, dsc->src);
return LV_RESULT_INVALID;
}
lv_cache_lock();
/* Check if the image is aligned */
if(!(entry->process_state & LV_VG_LITE_IMAGE_FLAG_ALIGNED)) {
int32_t image_w = dsc->header.w;
int32_t image_h = dsc->header.h;
uint32_t width_byte = image_w * lv_color_format_get_size(color_format);
uint32_t stride = lv_draw_buf_width_to_stride(image_w, color_format);
const uint8_t * ori_image = lv_cache_get_data(entry);
/* Check stride alignment requirements */
bool is_aligned = (stride == width_byte)
&& (ori_image == lv_draw_buf_align((void *)ori_image, color_format));
if(!is_aligned) {
/* alloc new image */
size_t size_bytes = stride * dsc->header.h;
uint8_t * new_image = lv_draw_buf_malloc(size_bytes, color_format);
if(!new_image) {
LV_LOG_ERROR("alloc %zu failed, cf = %d", size_bytes, color_format);
res = LV_RESULT_INVALID;
goto alloc_failed;
}
/* Replace the image data pointer */
entry->data = new_image;
dsc->img_data = new_image;
/* Copy image data */
image_copy(new_image, ori_image, stride, width_byte, image_h);
/* invalidate D-Cache */
image_invalidate_cache(new_image, stride, image_w, image_h, color_format);
/* free memory for old image */
lv_draw_buf_free((void *)ori_image);
}
else {
LV_LOG_INFO("no need to realign stride: %" LV_PRIu32, stride);
}
entry->process_state |= LV_VG_LITE_IMAGE_FLAG_ALIGNED;
}
/* Since image_try_self_pre_mul requires width alignment,
* premul alpha is placed after the image width alignment process.
*/
image_try_self_pre_mul(dsc);
alloc_failed:
lv_cache_unlock();
return res;
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_result_t try_cache(lv_image_decoder_dsc_t * dsc)
{
lv_cache_lock();
if(dsc->src_type == LV_IMAGE_SRC_FILE) {
const char * fn = dsc->src;
lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, fn, LV_CACHE_SRC_TYPE_PATH);
if(cache) {
dsc->img_data = lv_cache_get_data(cache);
dsc->cache_entry = cache; /*Save the cache to release it in decoder_close*/
lv_cache_unlock();
return LV_RESULT_OK;
}
}
if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
lv_cache_entry_t * cache = lv_cache_find_by_src(NULL, dsc->src, LV_CACHE_SRC_TYPE_POINTER);
if(cache) {
dsc->img_data = lv_cache_get_data(cache);
dsc->cache_entry = cache;
lv_cache_unlock();
return LV_RESULT_OK;
}
}
lv_cache_unlock();
return LV_RESULT_INVALID;
}
static void image_color32_pre_mul(lv_color32_t * img_data, uint32_t px_size)
{
while(px_size--) {
img_data->red = LV_UDIV255(img_data->red * img_data->alpha);
img_data->green = LV_UDIV255(img_data->green * img_data->alpha);
img_data->blue = LV_UDIV255(img_data->blue * img_data->alpha);
img_data++;
}
}
static void image_color16_pre_mul(lv_color16_alpha_t * img_data, uint32_t px_size)
{
while(px_size--) {
img_data->c.red = LV_UDIV255(img_data->c.red * img_data->alpha);
img_data->c.green = LV_UDIV255(img_data->c.green * img_data->alpha);
img_data->c.blue = LV_UDIV255(img_data->c.blue * img_data->alpha);
img_data++;
}
}
static void image_try_self_pre_mul(lv_image_decoder_dsc_t * dsc)
{
/* !!! WARNING !!!
* self-premultiplied images
* should be width-aligned and in modifiable RAM
*/
if(lv_vg_lite_support_blend_normal()) {
return;
}
if(dsc->cache_entry->process_state & LV_VG_LITE_IMAGE_FLAG_PRE_MUL) {
return;
}
lv_color_format_t cf = dsc->header.cf;
if(!lv_color_format_has_alpha(cf)) {
return;
}
int32_t image_w = dsc->header.w;
int32_t image_h = dsc->header.h;
uint32_t stride = lv_draw_buf_width_to_stride(image_w, cf);
uint32_t aligned_w = lv_vg_lite_width_align(image_w);
size_t px_size = aligned_w * image_h;
if(cf == LV_COLOR_FORMAT_ARGB8888) {
image_color32_pre_mul((lv_color32_t *)dsc->img_data, px_size);
}
else if(cf == LV_COLOR_FORMAT_RGB565A8) {
image_color16_pre_mul((lv_color16_alpha_t *)dsc->img_data, px_size);
}
else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
lv_color32_t * palette = (lv_color32_t *)dsc->img_data;
uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
image_color32_pre_mul(palette, palette_size);
}
else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
/* do nothing */
}
else {
LV_LOG_WARN("unsupported cf: %d", cf);
}
image_invalidate_cache((void *)dsc->img_data, stride, image_w, image_h, cf);
dsc->cache_entry->process_state |= LV_VG_LITE_IMAGE_FLAG_PRE_MUL;
}
static void image_copy(uint8_t * dest, const uint8_t * src,
size_t dest_stride, size_t src_stride,
uint32_t height)
{
for(uint32_t y = 0; y < height; y++) {
lv_memcpy(dest, src, src_stride);
src += src_stride;
dest += dest_stride;
}
}
static void image_invalidate_cache(void * buf, uint32_t stride,
uint32_t width, uint32_t height,
lv_color_format_t cf)
{
width = lv_vg_lite_width_align(width);
lv_area_t image_area;
lv_area_set(&image_area, 0, 0, width - 1, height - 1);
lv_draw_buf_invalidate_cache(buf, stride, cf, &image_area);
}
static lv_result_t decoder_info(lv_image_decoder_t * decoder, const void * src, lv_image_header_t * header)
{
return lv_bin_decoder_info(decoder, src, header);
}
static lv_result_t decoder_open_variable(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
lv_color_format_t cf = dsc->header.cf;
int32_t width = dsc->header.w;
int32_t height = dsc->header.h;
/* native stride */
uint32_t width_byte;
width_byte = width * lv_color_format_get_bpp(cf);
width_byte = (width_byte + 7) >> 3; /*Round up*/
bool support_blend_normal = lv_vg_lite_support_blend_normal();
uint32_t start = lv_tick_get();
/*In case of uncompressed formats the image stored in the ROM/RAM.
*So simply give its pointer*/
const uint8_t * image_data = ((lv_image_dsc_t *)dsc->src)->data;
bool has_alpha = lv_color_format_has_alpha(cf);
bool is_indexed = LV_COLOR_FORMAT_IS_INDEXED(cf);
bool is_addr_aligned = (image_data == lv_draw_buf_align((void *)image_data, cf)) ? true : false;
uint32_t stride = lv_draw_buf_width_to_stride(width, cf);
bool is_stride_aligned = (stride == width_byte) ? true : false;
/* When the following conditions are met,
* there is no need to copy image resource preprocessing.
*/
if(is_addr_aligned
&& is_stride_aligned
&& !is_indexed
&& (!has_alpha || (has_alpha && support_blend_normal))) {
/*add cache*/
lv_cache_lock();
lv_cache_entry_t * cache = lv_cache_add(image_data, 0, decoder->cache_data_type, 1);
cache->process_state = LV_VG_LITE_IMAGE_FLAG_ALIGNED;
cache->weight = lv_tick_elaps(start);
cache->src_type = LV_CACHE_SRC_TYPE_POINTER;
cache->src = dsc->src;
dsc->cache_entry = cache;
dsc->img_data = lv_cache_get_data(cache);
lv_cache_unlock();
return LV_RESULT_OK;
}
uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
uint32_t palette_size_bytes = palette_size * sizeof(lv_color32_t);
/* Since the palette and index image are next to each other,
* the palette size needs to be aligned to ensure that the image is aligned.
*/
uint32_t palette_size_bytes_aligned = LV_VG_LITE_ALIGN(palette_size_bytes, LV_VG_LITE_BUF_ALIGN);
size_t image_size = height * stride + palette_size_bytes_aligned;
void * image_buf = lv_draw_buf_malloc(image_size, cf);
if(image_buf == NULL) {
LV_LOG_ERROR("alloc %zu failed, cf = %d", image_size, cf);
return LV_RESULT_INVALID;
}
const uint8_t * src = image_data;
uint8_t * dest = image_buf;
/* copy palette */
if(palette_size_bytes) {
lv_memcpy(dest, src, palette_size_bytes);
src += palette_size_bytes;
/* move to align size */
dest += palette_size_bytes_aligned;
}
image_copy(dest, src, stride, width_byte, height);
lv_cache_lock();
lv_cache_entry_t * cache = lv_cache_add(image_buf, 0, decoder->cache_data_type, image_size);
dsc->img_data = lv_cache_get_data(cache);
dsc->cache_entry = cache;
/* premul alpha */
image_try_self_pre_mul(dsc);
/* invalidate D-Cache */
image_invalidate_cache(image_buf, stride, width, height, cf);
cache->process_state |= LV_VG_LITE_IMAGE_FLAG_ALLOCED | LV_VG_LITE_IMAGE_FLAG_ALIGNED;
cache->weight = lv_tick_elaps(start);
cache->src_type = LV_CACHE_SRC_TYPE_POINTER;
cache->src = dsc->src;
lv_cache_unlock();
LV_LOG_INFO("image %p (W%" LV_PRId32 " x H%" LV_PRId32 ", buffer: %p, cf: %d) decode finish %" LV_PRIu32 "ms",
image_data, width, height, image_buf, cf, cache->weight);
return LV_RESULT_OK;
}
static lv_result_t decoder_open_file(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
lv_color_format_t cf = dsc->header.cf;
int32_t width = dsc->header.w;
int32_t height = dsc->header.h;
const char * path = dsc->src;
uint32_t start = lv_tick_get();
lv_fs_file_t file;
lv_fs_res_t res = lv_fs_open(&file, path, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
LV_LOG_ERROR("open %s failed", path);
return LV_RESULT_INVALID;
}
/* skip image header bytes */
res = lv_fs_seek(&file, sizeof(lv_image_header_t), LV_FS_SEEK_SET);
if(res != LV_FS_RES_OK) {
LV_LOG_ERROR("seek %s lv_image_header_t failed", path);
lv_fs_close(&file);
return LV_RESULT_INVALID;
}
/* native stride */
uint32_t width_byte;
width_byte = width * lv_color_format_get_bpp(cf);
width_byte = (width_byte + 7) >> 3; /*Round up*/
bool support_blend_normal = lv_vg_lite_support_blend_normal();
uint32_t stride = lv_draw_buf_width_to_stride(width, cf);
uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
uint32_t palette_size_bytes = palette_size * sizeof(lv_color32_t);
/* Since the palette and index image are next to each other,
* the palette size needs to be aligned to ensure that the image is aligned.
*/
uint32_t palette_size_bytes_aligned = LV_VG_LITE_ALIGN(palette_size_bytes, LV_VG_LITE_BUF_ALIGN);
size_t image_size = height * stride + palette_size_bytes_aligned;
void * image_buf = lv_draw_buf_malloc(image_size, cf);
if(image_buf == NULL) {
LV_LOG_ERROR("alloc %zu failed, cf = %d", image_size, cf);
goto failed;
}
uint8_t * dest = image_buf;
/* copy palette */
if(palette_size_bytes) {
uint32_t br;
/* read palette */
res = lv_fs_read(&file, dest, palette_size_bytes, &br);
if(res != LV_FS_RES_OK || br != palette_size_bytes) {
LV_LOG_ERROR("read %s (palette: %" LV_PRIu32 ", br: %" LV_PRIu32 ") failed",
path, palette_size_bytes, br);
goto failed;
}
if(!support_blend_normal) {
image_color32_pre_mul((lv_color32_t *)image_buf, palette_size);
}
/* move to index image map */
dest += palette_size_bytes_aligned;
}
for(uint32_t y = 0; y < height; y++) {
uint32_t br;
res = lv_fs_read(&file, dest, width_byte, &br);
if(res != LV_FS_RES_OK || br != width_byte) {
LV_LOG_ERROR("read %s (y: %" LV_PRIu32 ", width_byte: %" LV_PRIu32 ", br: %" LV_PRIu32 ") failed",
path, y, width_byte, br);
goto failed;
}
dest += stride;
}
lv_fs_close(&file);
lv_cache_lock();
lv_cache_entry_t * cache = lv_cache_add(image_buf, 0, decoder->cache_data_type, image_size);
dsc->cache_entry = cache;
dsc->img_data = lv_cache_get_data(cache);
/* premul alpha */
image_try_self_pre_mul(dsc);
/* invalidate D-Cache */
image_invalidate_cache(image_buf, stride, width, height, cf);
cache->process_state |= LV_VG_LITE_IMAGE_FLAG_ALLOCED | LV_VG_LITE_IMAGE_FLAG_ALIGNED;
cache->weight = lv_tick_elaps(start);
cache->invalidate_cb = cache_invalidate_cb;
cache->src = lv_strdup(dsc->src);
cache->src_type = LV_CACHE_SRC_TYPE_PATH;
lv_cache_unlock();
LV_LOG_INFO("image %s (W%" LV_PRId32 " x H%" LV_PRId32 ", buffer: %p cf: %d) decode finish %" LV_PRIu32 "ms",
path, width, height, image_buf, cf, cache->weight);
return LV_RESULT_OK;
failed:
lv_fs_close(&file);
if(image_buf) {
LV_LOG_INFO("free image_buf: %p", image_buf);
lv_draw_buf_free(image_buf);
}
return LV_RESULT_INVALID;
}
static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
const lv_image_decoder_args_t * args)
{
LV_UNUSED(args); /*Unused*/
/*Check the cache first*/
if(try_cache(dsc) == LV_RESULT_OK) {
return LV_RESULT_OK;
}
switch(dsc->src_type) {
case LV_IMAGE_SRC_VARIABLE:
return decoder_open_variable(decoder, dsc);
case LV_IMAGE_SRC_FILE:
return decoder_open_file(decoder, dsc);
}
return LV_RESULT_INVALID;
}
static void decode_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
{
LV_UNUSED(decoder); /*Unused*/
lv_cache_lock();
lv_cache_release(dsc->cache_entry);
lv_cache_unlock();
}
static void cache_invalidate_cb(lv_cache_entry_t * entry)
{
if(entry->src_type == LV_CACHE_SRC_TYPE_PATH) lv_free((void *)entry->src);
lv_draw_buf_free((void *)entry->data);
}
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,49 @@
/**
* @file lv_vg_lite_decoder.h
*
*/
#ifndef LV_VG_LITE_DECODER_H
#define LV_VG_LITE_DECODER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_image_decoder.h"
#if LV_USE_DRAW_VG_LITE
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_vg_lite_decoder_init(void);
void lv_vg_lite_decoder_deinit(void);
lv_result_t lv_vg_lite_decoder_post_process(lv_image_decoder_dsc_t * dsc);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_DECODER_H*/

View File

@@ -0,0 +1,60 @@
/**
* @file lv_vg_lite_math.h
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vg_lite_math.h"
#if LV_USE_DRAW_VG_LITE
#include <stdint.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
float math_fast_inv_sqrtf(float number)
{
int32_t i;
float x2, y;
const float threehalfs = 1.5f;
x2 = number * 0.5f;
y = number;
i = *(int32_t *)&y; /* evil floating point bit level hacking */
i = 0x5f3759df - (i >> 1); /* what the fuck? */
y = *(float *)&i;
y = y * (threehalfs - (x2 * y * y)); /* 1st iteration */
return y;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,75 @@
/**
* @file lv_vg_lite_math.h
*
*/
#ifndef LV_VG_LITE_MATH_H
#define LV_VG_LITE_MATH_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_DRAW_VG_LITE
#include <math.h>
#include <stdbool.h>
#include <float.h>
/*********************
* DEFINES
*********************/
#define MATH_PI 3.14159265358979323846f
#define MATH_HALF_PI 1.57079632679489661923f
#define MATH_TWO_PI 6.28318530717958647692f
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define MATH_TANF(x) tanf(x)
#define MATH_SINF(x) sinf(x)
#define MATH_COSF(x) cosf(x)
#define MATH_ASINF(x) asinf(x)
#define MATH_FABSF(x) fabsf(x)
#define MATH_SQRTF(x) sqrtf(x)
#define MATH_RADIANS(deg) ((deg) * DEG_TO_RAD)
#define MATD_DEGRESS(rad) ((rad) * RAD_TO_DEG)
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
static inline bool math_zero(float a)
{
return (MATH_FABSF(a) < FLT_EPSILON);
}
static inline bool math_equal(float a, float b)
{
return math_zero(a - b);
}
float math_fast_inv_sqrtf(float number);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_MATH_H*/

View File

@@ -0,0 +1,606 @@
/**
* @file lv_vg_lite_path.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vg_lite_path.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_math.h"
#include <float.h>
/*********************
* DEFINES
*********************/
#define PATH_KAPPA 0.552284f
#define PATH_MAX_CNT 32
/* Magic number from https://spencermortensen.com/articles/bezier-circle/ */
#define PATH_ARC_MAGIC 0.55191502449351f
#define SIGN(x) (math_zero(x) ? 0 : ((x) > 0 ? 1 : -1))
#define VLC_OP_ARG_LEN(OP, LEN) \
case VLC_OP_##OP: \
return (LEN)
/**********************
* TYPEDEFS
**********************/
struct _lv_vg_lite_path_t {
vg_lite_path_t base;
size_t mem_size;
uint8_t format_len;
};
typedef struct _lv_vg_lite_path_t * lv_vg_lite_path_ref_t;
typedef struct {
float min_x;
float min_y;
float max_x;
float max_y;
} lv_vg_lite_path_bounds_t;
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_vg_lite_path_init(struct _lv_draw_vg_lite_unit_t * unit)
{
LV_ASSERT_NULL(unit);
_lv_ll_init(&unit->path_free_ll, sizeof(lv_vg_lite_path_ref_t));
}
void lv_vg_lite_path_deinit(struct _lv_draw_vg_lite_unit_t * unit)
{
LV_ASSERT_NULL(unit);
lv_ll_t * ll_p = &unit->path_free_ll;
lv_vg_lite_path_ref_t * path_ref;
_LV_LL_READ(ll_p, path_ref) {
lv_vg_lite_path_destroy(*path_ref);
}
_lv_ll_clear(ll_p);
}
lv_vg_lite_path_t * lv_vg_lite_path_create(vg_lite_format_t data_format)
{
lv_vg_lite_path_t * path = lv_malloc_zeroed(sizeof(lv_vg_lite_path_t));
LV_ASSERT_MALLOC(path);
path->format_len = lv_vg_lite_path_format_len(data_format);
LV_ASSERT(vg_lite_init_path(
&path->base,
data_format,
VG_LITE_MEDIUM,
0,
NULL,
0, 0, 0, 0)
== VG_LITE_SUCCESS);
return path;
}
void lv_vg_lite_path_destroy(lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(path);
if(path->base.path != NULL) {
lv_free(path->base.path);
path->base.path = NULL;
}
lv_free(path);
}
lv_vg_lite_path_t * lv_vg_lite_path_get(struct _lv_draw_vg_lite_unit_t * unit, vg_lite_format_t data_format)
{
LV_ASSERT_NULL(unit);
unit->path_max_cnt++;
LV_ASSERT(unit->path_max_cnt < PATH_MAX_CNT);
lv_ll_t * ll_p = &unit->path_free_ll;
lv_vg_lite_path_ref_t * path_ref = _lv_ll_get_head(ll_p);
if(path_ref) {
lv_vg_lite_path_t * path = *path_ref;
lv_vg_lite_path_reset(path, data_format);
_lv_ll_remove(ll_p, path_ref);
lv_free(path_ref);
return path;
}
return lv_vg_lite_path_create(data_format);
}
void lv_vg_lite_path_drop(struct _lv_draw_vg_lite_unit_t * unit, lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(unit);
LV_ASSERT_NULL(path);
unit->path_max_cnt--;
LV_ASSERT(unit->path_max_cnt >= 0);
lv_ll_t * ll_p = &unit->path_free_ll;
uint32_t len = _lv_ll_get_len(ll_p);
if(len >= PATH_MAX_CNT) {
lv_vg_lite_path_ref_t * tail = _lv_ll_get_tail(ll_p);
lv_vg_lite_path_destroy(*tail);
_lv_ll_remove(ll_p, tail);
lv_free(tail);
}
lv_vg_lite_path_ref_t * head = _lv_ll_ins_head(ll_p);
LV_ASSERT_MALLOC(head);
*head = path;
}
void lv_vg_lite_path_reset(lv_vg_lite_path_t * path, vg_lite_format_t data_format)
{
LV_ASSERT_NULL(path);
lv_memzero(path->base.path, path->mem_size);
path->base.path_length = 0;
path->base.format = data_format;
path->base.quality = VG_LITE_MEDIUM;
path->format_len = lv_vg_lite_path_format_len(data_format);
}
vg_lite_path_t * lv_vg_lite_path_get_path(lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(path);
return &path->base;
}
void lv_vg_lite_path_set_bonding_box(lv_vg_lite_path_t * path,
float min_x, float min_y,
float max_x, float max_y)
{
LV_ASSERT_NULL(path);
path->base.bounding_box[0] = min_x;
path->base.bounding_box[1] = min_y;
path->base.bounding_box[2] = max_x;
path->base.bounding_box[3] = max_y;
}
void lv_vg_lite_path_set_bonding_box_area(lv_vg_lite_path_t * path, const lv_area_t * area)
{
LV_ASSERT_NULL(path);
LV_ASSERT_NULL(area);
lv_vg_lite_path_set_bonding_box(path, area->x1, area->y1, area->x2 + 1, area->y2 + 1);
}
void lv_vg_lite_path_get_bonding_box(lv_vg_lite_path_t * path,
float * min_x, float * min_y,
float * max_x, float * max_y)
{
LV_ASSERT_NULL(path);
if(min_x) *min_x = path->base.bounding_box[0];
if(min_y) *min_y = path->base.bounding_box[1];
if(max_x) *max_x = path->base.bounding_box[2];
if(max_y) *max_y = path->base.bounding_box[3];
}
static void path_bounds_iter_cb(void * user_data, uint8_t op_code, const float * data, uint32_t len)
{
if(len == 0) {
return;
}
typedef struct {
float x;
float y;
} point_t;
const int pt_len = sizeof(point_t) / sizeof(float);
LV_ASSERT(len % pt_len == 0);
const point_t * pt = (point_t *)data;
len /= pt_len;
lv_vg_lite_path_bounds_t * bounds = user_data;
for(uint32_t i = 0; i < len; i++) {
if(pt[i].x < bounds->min_x) bounds->min_x = pt[i].x;
if(pt[i].y < bounds->min_y) bounds->min_y = pt[i].y;
if(pt[i].x > bounds->max_x) bounds->max_x = pt[i].x;
if(pt[i].y > bounds->max_y) bounds->max_y = pt[i].y;
}
}
bool lv_vg_lite_path_update_bonding_box(lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(path);
if(!path->format_len) {
return false;
}
lv_vg_lite_path_bounds_t bounds;
/* init bounds */
bounds.min_x = __FLT_MAX__;
bounds.min_y = __FLT_MAX__;
bounds.max_x = __FLT_MIN__;
bounds.max_y = __FLT_MIN__;
/* calc bounds */
lv_vg_lite_path_for_each_data(lv_vg_lite_path_get_path(path), path_bounds_iter_cb, &bounds);
/* set bounds */
lv_vg_lite_path_set_bonding_box(path, bounds.min_x, bounds.min_y, bounds.max_x, bounds.max_y);
return true;
}
void lv_vg_lite_path_set_quality(lv_vg_lite_path_t * path, vg_lite_quality_t quality)
{
LV_ASSERT_NULL(path);
path->base.quality = quality;
}
static void lv_vg_lite_path_append_data(lv_vg_lite_path_t * path, const void * data, size_t len)
{
LV_ASSERT_NULL(path);
LV_ASSERT_NULL(data);
if(path->base.path_length + len > path->mem_size) {
if(path->mem_size == 0) {
path->mem_size = len;
}
else {
path->mem_size *= 2;
}
path->base.path = lv_realloc(path->base.path, path->mem_size);
LV_ASSERT_MALLOC(path->base.path);
}
lv_memcpy((uint8_t *)path->base.path + path->base.path_length, data, len);
path->base.path_length += len;
}
static void lv_vg_lite_path_append_op(lv_vg_lite_path_t * path, uint32_t op)
{
lv_vg_lite_path_append_data(path, &op, path->format_len);
}
static void lv_vg_lite_path_append_point(lv_vg_lite_path_t * path, float x, float y)
{
if(path->base.format == VG_LITE_FP32) {
lv_vg_lite_path_append_data(path, &x, sizeof(x));
lv_vg_lite_path_append_data(path, &y, sizeof(y));
return;
}
int32_t ix = (int32_t)(x);
int32_t iy = (int32_t)(y);
lv_vg_lite_path_append_data(path, &ix, path->format_len);
lv_vg_lite_path_append_data(path, &iy, path->format_len);
}
void lv_vg_lite_path_move_to(lv_vg_lite_path_t * path,
float x, float y)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_MOVE);
lv_vg_lite_path_append_point(path, x, y);
}
void lv_vg_lite_path_line_to(lv_vg_lite_path_t * path,
float x, float y)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_LINE);
lv_vg_lite_path_append_point(path, x, y);
}
void lv_vg_lite_path_quad_to(lv_vg_lite_path_t * path,
float cx, float cy,
float x, float y)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_QUAD);
lv_vg_lite_path_append_point(path, cx, cy);
lv_vg_lite_path_append_point(path, x, y);
}
void lv_vg_lite_path_cubic_to(lv_vg_lite_path_t * path,
float cx1, float cy1,
float cx2, float cy2,
float x, float y)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_CUBIC);
lv_vg_lite_path_append_point(path, cx1, cy1);
lv_vg_lite_path_append_point(path, cx2, cy2);
lv_vg_lite_path_append_point(path, x, y);
}
void lv_vg_lite_path_close(lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_CLOSE);
}
void lv_vg_lite_path_end(lv_vg_lite_path_t * path)
{
LV_ASSERT_NULL(path);
lv_vg_lite_path_append_op(path, VLC_OP_END);
}
void lv_vg_lite_path_append_rect(
lv_vg_lite_path_t * path,
float x, float y,
float w, float h,
float rx, float ry)
{
const float half_w = w * 0.5f;
const float half_h = h * 0.5f;
/*clamping cornerRadius by minimum size*/
if(rx > half_w)
rx = half_w;
if(ry > half_h)
ry = half_h;
/*rectangle*/
if(rx == 0 && ry == 0) {
lv_vg_lite_path_move_to(path, x, y);
lv_vg_lite_path_line_to(path, x + w, y);
lv_vg_lite_path_line_to(path, x + w, y + h);
lv_vg_lite_path_line_to(path, x, y + h);
lv_vg_lite_path_close(path);
return;
}
/*circle*/
if(math_equal(rx, half_w) && math_equal(ry, half_h)) {
return lv_vg_lite_path_append_circle(path, x + (w * 0.5f), y + (h * 0.5f), rx, ry);
}
/*rounded rectangle*/
float hrx = rx * 0.5f;
float hry = ry * 0.5f;
lv_vg_lite_path_move_to(path, x + rx, y);
lv_vg_lite_path_line_to(path, x + w - rx, y);
lv_vg_lite_path_cubic_to(path, x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
lv_vg_lite_path_line_to(path, x + w, y + h - ry);
lv_vg_lite_path_cubic_to(path, x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
lv_vg_lite_path_line_to(path, x + rx, y + h);
lv_vg_lite_path_cubic_to(path, x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
lv_vg_lite_path_line_to(path, x, y + ry);
lv_vg_lite_path_cubic_to(path, x, y + ry - hry, x + rx - hrx, y, x + rx, y);
lv_vg_lite_path_close(path);
}
void lv_vg_lite_path_append_circle(
lv_vg_lite_path_t * path,
float cx, float cy,
float rx, float ry)
{
/* https://learn.microsoft.com/zh-cn/xamarin/xamarin-forms/user-interface/graphics/skiasharp/curves/beziers */
float rx_kappa = rx * PATH_KAPPA;
float ry_kappa = ry * PATH_KAPPA;
lv_vg_lite_path_move_to(path, cx, cy - ry);
lv_vg_lite_path_cubic_to(path, cx + rx_kappa, cy - ry, cx + rx, cy - ry_kappa, cx + rx, cy);
lv_vg_lite_path_cubic_to(path, cx + rx, cy + ry_kappa, cx + rx_kappa, cy + ry, cx, cy + ry);
lv_vg_lite_path_cubic_to(path, cx - rx_kappa, cy + ry, cx - rx, cy + ry_kappa, cx - rx, cy);
lv_vg_lite_path_cubic_to(path, cx - rx, cy - ry_kappa, cx - rx_kappa, cy - ry, cx, cy - ry);
lv_vg_lite_path_close(path);
}
void lv_vg_lite_path_append_arc_right_angle(lv_vg_lite_path_t * path,
float start_x, float start_y,
float center_x, float center_y,
float end_x, float end_y)
{
float dx1 = center_x - start_x;
float dy1 = center_y - start_y;
float dx2 = end_x - center_x;
float dy2 = end_y - center_y;
float c = SIGN(dx1 * dy2 - dx2 * dy1) * PATH_ARC_MAGIC;
lv_vg_lite_path_cubic_to(path,
start_x - c * dy1, start_y + c * dx1,
end_x - c * dy2, end_y + c * dx2,
end_x, end_y);
}
void lv_vg_lite_path_append_arc(lv_vg_lite_path_t * path,
float cx, float cy,
float radius,
float start_angle,
float sweep,
bool pie)
{
/* just circle */
if(sweep >= 360.0f || sweep <= -360.0f) {
return lv_vg_lite_path_append_circle(path, cx, cy, radius, radius);
}
start_angle = (start_angle * MATH_PI) / 180.0f;
sweep = sweep * MATH_PI / 180.0f;
int n_curves = ceil(MATH_FABSF(sweep / MATH_HALF_PI));
int sweep_sign = (sweep < 0 ? -1 : 1);
float fract = fmodf(sweep, MATH_HALF_PI);
fract = (math_zero(fract)) ? MATH_HALF_PI * sweep_sign : fract;
/* Start from here */
float start_x = radius * MATH_COSF(start_angle);
float start_y = radius * MATH_SINF(start_angle);
if(pie) {
lv_vg_lite_path_move_to(path, cx, cy);
lv_vg_lite_path_line_to(path, start_x + cx, start_y + cy);
}
else {
lv_vg_lite_path_move_to(path, start_x + cx, start_y + cy);
}
for(int i = 0; i < n_curves; ++i) {
float end_angle = start_angle + ((i != n_curves - 1) ? MATH_HALF_PI * sweep_sign : fract);
float end_x = radius * MATH_COSF(end_angle);
float end_y = radius * MATH_SINF(end_angle);
/* variables needed to calculate bezier control points */
/** get bezier control points using article:
* (http://itc.ktu.lt/index.php/ITC/article/view/11812/6479)
*/
float ax = start_x;
float ay = start_y;
float bx = end_x;
float by = end_y;
float q1 = ax * ax + ay * ay;
float q2 = ax * bx + ay * by + q1;
float k2 = (4.0f / 3.0f) * ((MATH_SQRTF(2 * q1 * q2) - q2) / (ax * by - ay * bx));
/* Next start point is the current end point */
start_x = end_x;
start_y = end_y;
end_x += cx;
end_y += cy;
float ctrl1_x = ax - k2 * ay + cx;
float ctrl1_y = ay + k2 * ax + cy;
float ctrl2_x = bx + k2 * by + cx;
float ctrl2_y = by - k2 * bx + cy;
lv_vg_lite_path_cubic_to(path, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, end_x, end_y);
start_angle = end_angle;
}
if(pie) {
lv_vg_lite_path_close(path);
}
}
uint8_t lv_vg_lite_vlc_op_arg_len(uint8_t vlc_op)
{
switch(vlc_op) {
VLC_OP_ARG_LEN(END, 0);
VLC_OP_ARG_LEN(CLOSE, 0);
VLC_OP_ARG_LEN(MOVE, 2);
VLC_OP_ARG_LEN(MOVE_REL, 2);
VLC_OP_ARG_LEN(LINE, 2);
VLC_OP_ARG_LEN(LINE_REL, 2);
VLC_OP_ARG_LEN(QUAD, 4);
VLC_OP_ARG_LEN(QUAD_REL, 4);
VLC_OP_ARG_LEN(CUBIC, 6);
VLC_OP_ARG_LEN(CUBIC_REL, 6);
VLC_OP_ARG_LEN(SCCWARC, 5);
VLC_OP_ARG_LEN(SCCWARC_REL, 5);
VLC_OP_ARG_LEN(SCWARC, 5);
VLC_OP_ARG_LEN(SCWARC_REL, 5);
VLC_OP_ARG_LEN(LCCWARC, 5);
VLC_OP_ARG_LEN(LCCWARC_REL, 5);
VLC_OP_ARG_LEN(LCWARC, 5);
VLC_OP_ARG_LEN(LCWARC_REL, 5);
default:
break;
}
LV_LOG_ERROR("UNKNOW_VLC_OP: 0x%x", vlc_op);
LV_ASSERT(false);
return 0;
}
uint8_t lv_vg_lite_path_format_len(vg_lite_format_t format)
{
switch(format) {
case VG_LITE_S8:
return 1;
case VG_LITE_S16:
return 2;
case VG_LITE_S32:
return 4;
case VG_LITE_FP32:
return 4;
default:
break;
}
LV_LOG_ERROR("UNKNOW_FORMAT: %d", format);
LV_ASSERT(false);
return 0;
}
void lv_vg_lite_path_for_each_data(const vg_lite_path_t * path, lv_vg_lite_path_iter_cb_t cb, void * user_data)
{
LV_ASSERT_NULL(path);
LV_ASSERT_NULL(cb);
uint8_t fmt_len = lv_vg_lite_path_format_len(path->format);
uint8_t * cur = path->path;
uint8_t * end = cur + path->path_length;
float tmp_data[8];
while(cur < end) {
/* get op code */
uint8_t op_code = VLC_GET_OP_CODE(cur);
/* get arguments length */
uint8_t arg_len = lv_vg_lite_vlc_op_arg_len(op_code);
/* skip op code */
cur += fmt_len;
/* print arguments */
for(uint8_t i = 0; i < arg_len; i++) {
switch(path->format) {
case VG_LITE_S8:
tmp_data[i] = *((int8_t *)cur);
break;
case VG_LITE_S16:
tmp_data[i] = *((int16_t *)cur);
break;
case VG_LITE_S32:
tmp_data[i] = *((int32_t *)cur);
break;
case VG_LITE_FP32:
tmp_data[i] = *((float *)cur);
break;
default:
LV_LOG_ERROR("UNKNOW_FORMAT(%d)", path->format);
LV_ASSERT(false);
break;
}
cur += fmt_len;
}
cb(user_data, op_code, tmp_data, arg_len);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,124 @@
/**
* @file lv_vg_lite_path.h
*
*/
#ifndef LV_VG_LITE_PATH_H
#define LV_VG_LITE_PATH_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_vg_lite_utils.h"
#if LV_USE_DRAW_VG_LITE
/*********************
* DEFINES
*********************/
typedef struct _lv_vg_lite_path_t lv_vg_lite_path_t;
struct _lv_draw_vg_lite_unit_t;
typedef void (*lv_vg_lite_path_iter_cb_t)(void * user_data, uint8_t op_code, const float * data, uint32_t len);
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_vg_lite_path_init(struct _lv_draw_vg_lite_unit_t * unit);
void lv_vg_lite_path_deinit(struct _lv_draw_vg_lite_unit_t * unit);
lv_vg_lite_path_t * lv_vg_lite_path_create(vg_lite_format_t data_format);
void lv_vg_lite_path_destroy(lv_vg_lite_path_t * path);
lv_vg_lite_path_t * lv_vg_lite_path_get(struct _lv_draw_vg_lite_unit_t * unit, vg_lite_format_t data_format);
void lv_vg_lite_path_drop(struct _lv_draw_vg_lite_unit_t * unit, lv_vg_lite_path_t * path);
void lv_vg_lite_path_reset(lv_vg_lite_path_t * path, vg_lite_format_t data_format);
void lv_vg_lite_path_set_bonding_box_area(lv_vg_lite_path_t * path, const lv_area_t * area);
void lv_vg_lite_path_set_bonding_box(lv_vg_lite_path_t * path,
float min_x, float min_y,
float max_x, float max_y);
void lv_vg_lite_path_get_bonding_box(lv_vg_lite_path_t * path,
float * min_x, float * min_y,
float * max_x, float * max_y);
bool lv_vg_lite_path_update_bonding_box(lv_vg_lite_path_t * path);
void lv_vg_lite_path_set_quality(lv_vg_lite_path_t * path, vg_lite_quality_t quality);
vg_lite_path_t * lv_vg_lite_path_get_path(lv_vg_lite_path_t * path);
void lv_vg_lite_path_move_to(lv_vg_lite_path_t * path,
float x, float y);
void lv_vg_lite_path_line_to(lv_vg_lite_path_t * path,
float x, float y);
void lv_vg_lite_path_quad_to(lv_vg_lite_path_t * path,
float cx, float cy,
float x, float y);
void lv_vg_lite_path_cubic_to(lv_vg_lite_path_t * path,
float cx1, float cy1,
float cx2, float cy2,
float x, float y);
void lv_vg_lite_path_close(lv_vg_lite_path_t * path);
void lv_vg_lite_path_end(lv_vg_lite_path_t * path);
void lv_vg_lite_path_append_rect(lv_vg_lite_path_t * path,
float x, float y,
float w, float h,
float rx, float ry);
void lv_vg_lite_path_append_circle(lv_vg_lite_path_t * path,
float cx, float cy,
float rx, float ry);
void lv_vg_lite_path_append_arc_right_angle(lv_vg_lite_path_t * path,
float start_x, float start_y,
float center_x, float center_y,
float end_x, float end_y);
void lv_vg_lite_path_append_arc(lv_vg_lite_path_t * path,
float cx, float cy,
float radius,
float start_angle,
float sweep,
bool pie);
uint8_t lv_vg_lite_vlc_op_arg_len(uint8_t vlc_op);
uint8_t lv_vg_lite_path_format_len(vg_lite_format_t format);
void lv_vg_lite_path_for_each_data(const vg_lite_path_t * path, lv_vg_lite_path_iter_cb_t cb, void * user_data);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_PATH_H*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
/**
* @file lv_vg_lite_utils.h
*
*/
#ifndef LV_VG_LITE_UTILS_H
#define LV_VG_LITE_UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lvgl.h"
#if LV_USE_DRAW_VG_LITE
#include <stdbool.h>
#include <vg_lite.h>
/*********************
* DEFINES
*********************/
#define LV_VG_LITE_BUF_ALIGN 64
#define LV_VG_LITE_IS_ERROR(err) (err > 0)
#define VLC_GET_OP_CODE(ptr) (*((uint8_t*)ptr))
#if LV_VG_LITE_USE_ASSERT
#define LV_VG_LITE_ASSERT(expr) LV_ASSERT(expr)
#else
#define LV_VG_LITE_ASSERT(expr)
#endif
#define LV_VG_LITE_CHECK_ERROR(expr) \
do { \
vg_lite_error_t error = expr; \
if (LV_VG_LITE_IS_ERROR(error)) { \
LV_LOG_ERROR("Execute '" #expr "' error(%d): %s", \
(int)error, lv_vg_lite_error_string(error)); \
LV_VG_LITE_ASSERT(false); \
} \
} while (0)
#define LV_VG_LITE_ASSERT_PATH(path) LV_VG_LITE_ASSERT(lv_vg_lite_path_check(path))
#define LV_VG_LITE_ASSERT_SRC_BUFFER(buffer) LV_VG_LITE_ASSERT(lv_vg_lite_buffer_check(buffer, true))
#define LV_VG_LITE_ASSERT_DEST_BUFFER(buffer) LV_VG_LITE_ASSERT(lv_vg_lite_buffer_check(buffer, false))
#define LV_VG_LITE_ALIGN(number, align_bytes) \
(((number) + ((align_bytes)-1)) & ~((align_bytes)-1))
#define LV_VG_LITE_IS_ALIGNED(num, align) (((uintptr_t)(num) & ((align)-1)) == 0)
#define LV_VG_LITE_IS_INDEX_FMT(fmt) \
((fmt) == VG_LITE_INDEX_1 \
|| (fmt) == VG_LITE_INDEX_2 \
|| (fmt) == VG_LITE_INDEX_4 \
|| (fmt) == VG_LITE_INDEX_8)
/**********************
* TYPEDEFS
**********************/
typedef enum {
LV_VG_LITE_IMAGE_FLAG_ALLOCED = 1 << 0,
LV_VG_LITE_IMAGE_FLAG_ALIGNED = 1 << 1,
LV_VG_LITE_IMAGE_FLAG_PRE_MUL = 1 << 2,
} lv_vg_lite_image_flag_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/* Print info */
void lv_vg_lite_dump_info(void);
const char * lv_vg_lite_error_string(vg_lite_error_t error);
const char * lv_vg_lite_feature_string(vg_lite_feature_t feature);
const char * lv_vg_lite_buffer_format_string(vg_lite_buffer_format_t format);
const char * lv_vg_lite_filter_string(vg_lite_filter_t filter);
const char * lv_vg_lite_blend_string(vg_lite_blend_t blend);
const char * lv_vg_lite_global_alpha_string(vg_lite_global_alpha_t global_alpha);
const char * lv_vg_lite_fill_rule_string(vg_lite_fill_t fill_rule);
const char * lv_vg_lite_image_mode_string(vg_lite_buffer_image_mode_t image_mode);
const char * lv_vg_lite_vlc_op_string(uint8_t vlc_op);
void lv_vg_lite_path_dump_info(const vg_lite_path_t * path);
void lv_vg_lite_buffer_dump_info(const vg_lite_buffer_t * buffer);
void lv_vg_lite_matrix_dump_info(const vg_lite_matrix_t * matrix);
bool lv_vg_lite_is_dest_cf_supported(lv_color_format_t cf);
bool lv_vg_lite_is_src_cf_supported(lv_color_format_t cf);
/* Converter */
vg_lite_buffer_format_t lv_vg_lite_vg_fmt(lv_color_format_t cf);
void lv_vg_lite_buffer_format_bytes(
vg_lite_buffer_format_t format,
uint32_t * mul,
uint32_t * div,
uint32_t * bytes_align);
uint32_t lv_vg_lite_width_to_stride(uint32_t w, vg_lite_buffer_format_t color_format);
uint32_t lv_vg_lite_width_align(uint32_t w);
bool lv_vg_lite_buffer_init(
vg_lite_buffer_t * buffer,
const void * ptr,
int32_t width,
int32_t height,
vg_lite_buffer_format_t format,
bool tiled);
void lv_vg_lite_image_matrix(vg_lite_matrix_t * matrix, int32_t x, int32_t y, const lv_draw_image_dsc_t * dsc);
bool lv_vg_lite_buffer_open_image(vg_lite_buffer_t * buffer, lv_image_decoder_dsc_t * decoder_dsc, const void * src);
vg_lite_blend_t lv_vg_lite_blend_mode(lv_blend_mode_t blend_mode);
uint32_t lv_vg_lite_get_palette_size(vg_lite_buffer_format_t format);
vg_lite_color_t lv_vg_lite_color(lv_color_t color, lv_opa_t opa, bool pre_mul);
void lv_vg_lite_rect(vg_lite_rectangle_t * rect, const lv_area_t * area);
/* Param checker */
bool lv_vg_lite_buffer_check(const vg_lite_buffer_t * buffer, bool is_src);
bool lv_vg_lite_path_check(const vg_lite_path_t * path);
/* Wrapper */
bool lv_vg_lite_support_blend_normal(void);
bool lv_vg_lite_16px_align(void);
void lv_vg_lite_draw_linear_grad(
vg_lite_buffer_t * buffer,
vg_lite_path_t * path,
const lv_area_t * area,
const lv_grad_dsc_t * grad,
const vg_lite_matrix_t * matrix,
vg_lite_fill_t fill,
vg_lite_blend_t blend);
void lv_vg_lite_matrix_multiply(vg_lite_matrix_t * matrix, const vg_lite_matrix_t * mult);
void lv_vg_lite_matrix_flip_y(vg_lite_matrix_t * matrix);
bool lv_vg_lite_matrix_inverse(vg_lite_matrix_t * result, const vg_lite_matrix_t * matrix);
lv_point_precise_t lv_vg_lite_matrix_transform_point(const vg_lite_matrix_t * matrix, const lv_point_precise_t * point);
void lv_vg_lite_set_scissor_area(const lv_area_t * area);
void lv_vg_lite_disable_scissor(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*VG_LITE_UTILS_H*/

View File

@@ -350,6 +350,35 @@
#endif #endif
#endif #endif
/* Use VG-Lite GPU. */
#ifndef LV_USE_DRAW_VG_LITE
#ifdef CONFIG_LV_USE_DRAW_VG_LITE
#define LV_USE_DRAW_VG_LITE CONFIG_LV_USE_DRAW_VG_LITE
#else
#define LV_USE_DRAW_VG_LITE 0
#endif
#endif
#if LV_USE_DRAW_VG_LITE
/* Enbale VG-Lite custom external 'gpu_init()' function */
#ifndef LV_VG_LITE_USE_GPU_INIT
#ifdef CONFIG_LV_VG_LITE_USE_GPU_INIT
#define LV_VG_LITE_USE_GPU_INIT CONFIG_LV_VG_LITE_USE_GPU_INIT
#else
#define LV_VG_LITE_USE_GPU_INIT 0
#endif
#endif
/* Enable VG-Lite assert. */
#ifndef LV_VG_LITE_USE_ASSERT
#ifdef CONFIG_LV_VG_LITE_USE_ASSERT
#define LV_VG_LITE_USE_ASSERT CONFIG_LV_VG_LITE_USE_ASSERT
#else
#define LV_VG_LITE_USE_ASSERT 0
#endif
#endif
#endif
/*================= /*=================
* OPERATING SYSTEM * OPERATING SYSTEM
*=================*/ *=================*/

View File

@@ -38,6 +38,9 @@
#if LV_USE_DRAW_SDL #if LV_USE_DRAW_SDL
#include "draw/sdl/lv_draw_sdl.h" #include "draw/sdl/lv_draw_sdl.h"
#endif #endif
#if LV_USE_DRAW_VG_LITE
#include "draw/vg_lite/lv_draw_vg_lite.h"
#endif
/********************* /*********************
* DEFINES * DEFINES
@@ -192,6 +195,10 @@ void lv_init(void)
_lv_image_decoder_init(); _lv_image_decoder_init();
lv_bin_decoder_init(); /*LVGL built-in binary image decoder*/ lv_bin_decoder_init(); /*LVGL built-in binary image decoder*/
#if LV_USE_DRAW_VG_LITE
lv_draw_vg_lite_init();
#endif
_lv_cache_init(); _lv_cache_init();
_lv_cache_builtin_init(); _lv_cache_builtin_init();
lv_cache_lock(); lv_cache_lock();
@@ -357,6 +364,10 @@ void lv_deinit(void)
lv_draw_vglite_deinit(); lv_draw_vglite_deinit();
#endif #endif
#if LV_USE_DRAW_VG_LITE
lv_draw_vg_lite_deinit();
#endif
#if LV_USE_DRAW_SW #if LV_USE_DRAW_SW
lv_draw_sw_deinit(); lv_draw_sw_deinit();
#endif #endif