feat(draw): add global matrix drawing modes (#4883)

Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
Signed-off-by: wangxuedong <wangxuedong@xiaomi.com>
Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
Co-authored-by: wangxuedong <wangxuedong@xiaomi.com>
This commit is contained in:
VIFEX
2024-07-25 21:24:59 +08:00
committed by GitHub
parent 91cd8ecf90
commit 0980518441
44 changed files with 604 additions and 194 deletions

15
Kconfig
View File

@@ -177,6 +177,13 @@ menu "LVGL configuration"
help
Align the start address of draw_buf addresses to this bytes.
config LV_DRAW_TRANSFORM_USE_MATRIX
bool "Using matrix for transformations"
default n
depends on LV_USE_MATRIX
help
Requirements: The rendering engine needs to support 3x3 matrix transformations.
config LV_DRAW_LAYER_SIMPLE_BUF_SIZE
int "Optimal size to buffer the widget with opacity"
default 24576
@@ -372,6 +379,8 @@ menu "LVGL configuration"
config LV_USE_DRAW_VG_LITE
bool "Use VG-Lite GPU"
default n
select LV_USE_MATRIX
config LV_VG_LITE_USE_GPU_INIT
bool "Enable VG-Lite custom external 'gpu_init()' function"
@@ -415,6 +424,7 @@ menu "LVGL configuration"
config LV_USE_VECTOR_GRAPHIC
bool "Use Vector Graphic APIs"
default n
select LV_USE_MATRIX
help
Enable drawing support vector graphic APIs.
endmenu
@@ -696,6 +706,11 @@ menu "LVGL configuration"
config LV_USE_FLOAT
bool "Use float as lv_value_precise_t"
default n
config LV_USE_MATRIX
bool "Enable matrix support"
default n
select LV_USE_FLOAT
endmenu
menu "Font Usage"

View File

@@ -106,6 +106,12 @@
/*Align the start address of draw_buf addresses to this bytes*/
#define LV_DRAW_BUF_ALIGN 4
/*Using matrix for transformations.
*Requirements:
`LV_USE_MATRIX = 1`.
The rendering engine needs to support 3x3 matrix transformations.*/
#define LV_DRAW_TRANSFORM_USE_MATRIX 0
/* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode
* it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks.
* "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers
@@ -438,6 +444,10 @@
/* Use `float` as `lv_value_precise_t` */
#define LV_USE_FLOAT 0
/*Enable matrix support
*Requires `LV_USE_FLOAT = 1`*/
#define LV_USE_MATRIX 0
/*==================
* FONT USAGE
*===================*/
@@ -791,7 +801,8 @@
/*Rlottie library*/
#define LV_USE_RLOTTIE 0
/*Enable Vector Graphic APIs*/
/*Enable Vector Graphic APIs
*Requires `LV_USE_MATRIX = 1`*/
#define LV_USE_VECTOR_GRAPHIC 0
/* Enable ThorVG (vector graphics library) from the src/libs folder */

View File

@@ -604,6 +604,10 @@ static void refr_area(const lv_area_t * area_p)
lv_layer_t * layer = disp_refr->layer_head;
layer->draw_buf = disp_refr->buf_act;
#if LV_DRAW_TRANSFORM_USE_MATRIX
lv_matrix_identity(&layer->matrix);
#endif
/*With full refresh just redraw directly into the buffer*/
/*In direct mode draw directly on the absolute coordinates of the buffer*/
if(disp_refr->render_mode != LV_DISPLAY_RENDER_MODE_PARTIAL) {
@@ -891,18 +895,120 @@ static bool alpha_test_area_on_obj(lv_obj_t * obj, const lv_area_t * area)
else return true;
}
void refr_obj(lv_layer_t * layer, lv_obj_t * obj)
#if LV_DRAW_TRANSFORM_USE_MATRIX
static void refr_obj_matrix(lv_layer_t * layer, lv_obj_t * obj)
{
lv_matrix_t ori_matrix = layer->matrix;
lv_matrix_t obj_matrix;
lv_matrix_identity(&obj_matrix);
lv_point_t pivot = {
.x = lv_obj_get_style_transform_pivot_x(obj, 0),
.y = lv_obj_get_style_transform_pivot_y(obj, 0)
};
pivot.x = obj->coords.x1 + lv_pct_to_px(pivot.x, lv_area_get_width(&obj->coords));
pivot.y = obj->coords.y1 + lv_pct_to_px(pivot.y, lv_area_get_height(&obj->coords));
int32_t rotation = lv_obj_get_style_transform_rotation(obj, 0);
int32_t scale_x = lv_obj_get_style_transform_scale_x(obj, 0);
int32_t scale_y = lv_obj_get_style_transform_scale_y(obj, 0);
int32_t skew_x = lv_obj_get_style_transform_skew_x(obj, 0);
int32_t skew_y = lv_obj_get_style_transform_skew_y(obj, 0);
/* generate the obj matrix */
lv_matrix_translate(&obj_matrix, pivot.x, pivot.y);
if(rotation != 0) {
lv_matrix_rotate(&obj_matrix, rotation * 0.1f);
}
if(scale_x != LV_SCALE_NONE || scale_y != LV_SCALE_NONE) {
lv_matrix_scale(
&obj_matrix,
(float)scale_x / LV_SCALE_NONE,
(float)scale_y / LV_SCALE_NONE
);
}
if(skew_x != 0 || skew_y != 0) {
lv_matrix_skew(&obj_matrix, skew_x, skew_y);
}
lv_matrix_translate(&obj_matrix, -pivot.x, -pivot.y);
/* apply the obj matrix */
lv_matrix_multiply(&layer->matrix, &obj_matrix);
/* calculate clip area without transform */
lv_matrix_t matrix_reverse;
lv_matrix_inverse(&matrix_reverse, &obj_matrix);
lv_area_t clip_area = layer->_clip_area;
lv_area_t clip_area_ori = layer->_clip_area;
clip_area = lv_matrix_transform_area(&matrix_reverse, &clip_area);
/* increase the clip area by 1 pixel to avoid rounding errors */
if(!lv_matrix_is_identity_or_translation(&obj_matrix)) {
lv_area_increase(&clip_area, 1, 1);
}
layer->_clip_area = clip_area;
/* redraw obj */
lv_obj_redraw(layer, obj);
/* restore original matrix */
layer->matrix = ori_matrix;
/* restore clip area */
layer->_clip_area = clip_area_ori;
}
static bool refr_check_obj_clip_overflow(lv_layer_t * layer, lv_obj_t * obj)
{
if(lv_obj_get_style_transform_rotation(obj, 0) == 0) {
return false;
}
/*Truncate the area to the object*/
lv_area_t obj_coords;
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
lv_area_copy(&obj_coords, &obj->coords);
lv_area_increase(&obj_coords, ext_size, ext_size);
lv_obj_get_transformed_area(obj, &obj_coords, LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE);
lv_area_t clip_coords_for_obj;
if(!_lv_area_intersect(&clip_coords_for_obj, &layer->_clip_area, &obj_coords)) {
return false;
}
bool has_clip = lv_memcmp(&clip_coords_for_obj, &obj_coords, sizeof(lv_area_t)) != 0;
return has_clip;
}
#endif /* LV_DRAW_TRANSFORM_USE_MATRIX */
static void refr_obj(lv_layer_t * layer, lv_obj_t * obj)
{
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return;
lv_opa_t opa = lv_obj_get_style_opa_layered(obj, 0);
if(opa < LV_OPA_MIN) return;
#if LV_DRAW_TRANSFORM_USE_MATRIX
/*If the layer opa is full then use the matrix transform*/
if(opa >= LV_OPA_MAX && !refr_check_obj_clip_overflow(layer, obj)) {
refr_obj_matrix(layer, obj);
return;
}
#endif /* LV_DRAW_TRANSFORM_USE_MATRIX */
lv_layer_type_t layer_type = _lv_obj_get_layer_type(obj);
if(layer_type == LV_LAYER_TYPE_NONE) {
lv_obj_redraw(layer, obj);
}
else {
lv_opa_t opa = lv_obj_get_style_opa_layered(obj, 0);
if(opa < LV_OPA_MIN) return;
lv_area_t layer_area_full;
lv_area_t obj_draw_size;
lv_result_t res = layer_get_area(layer, obj, layer_type, &layer_area_full, &obj_draw_size);

View File

@@ -89,6 +89,9 @@ lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords)
new_task->area = *coords;
new_task->_real_area = *coords;
new_task->clip_area = layer->_clip_area;
#if LV_DRAW_TRANSFORM_USE_MATRIX
new_task->matrix = layer->matrix;
#endif
new_task->state = LV_DRAW_TASK_STATE_QUEUED;
/*Find the tail*/
@@ -346,6 +349,10 @@ lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t c
new_layer->buf_area = *area;
new_layer->color_format = color_format;
#if LV_DRAW_TRANSFORM_USE_MATRIX
lv_matrix_identity(&new_layer->matrix);
#endif
if(disp->layer_head) {
lv_layer_t * tail = disp->layer_head;
while(tail->next) tail = tail->next;

View File

@@ -19,6 +19,7 @@ extern "C" {
#include "../misc/lv_style.h"
#include "../misc/lv_text.h"
#include "../misc/lv_profiler.h"
#include "../misc/lv_matrix.h"
#include "lv_image_decoder.h"
#include "../osal/lv_os.h"
#include "lv_draw_buf.h"
@@ -29,6 +30,12 @@ extern "C" {
#define LV_DRAW_UNIT_NONE 0
#define LV_DRAW_UNIT_IDLE -1 /*The draw unit is idle, new dispatching might be requested to try again*/
#if LV_DRAW_TRANSFORM_USE_MATRIX
#if !LV_USE_MATRIX
#error "LV_DRAW_TRANSFORM_USE_MATRIX requires LV_USE_MATRIX = 1"
#endif
#endif
/**********************
* TYPEDEFS
**********************/
@@ -80,6 +87,11 @@ struct _lv_draw_task_t {
*/
lv_area_t clip_area;
#if LV_DRAW_TRANSFORM_USE_MATRIX
/** Transform matrix to be applied when rendering the layer */
lv_matrix_t matrix;
#endif
volatile int state; /*int instead of lv_draw_task_state_t to be sure its atomic*/
void * draw_dsc;
@@ -166,6 +178,11 @@ struct _lv_layer_t {
*/
lv_area_t _clip_area;
#if LV_DRAW_TRANSFORM_USE_MATRIX
/** Transform matrix to be applied when rendering the layer */
lv_matrix_t matrix;
#endif
/** Linked list of draw tasks */
lv_draw_task_t * draw_task_head;

View File

@@ -56,33 +56,6 @@ typedef struct {
* STATIC PROTOTYPES
**********************/
static bool _is_identity_or_translation(const lv_matrix_t * matrix)
{
return (matrix->m[0][0] == 1.0f &&
matrix->m[0][1] == 0.0f &&
matrix->m[1][0] == 0.0f &&
matrix->m[1][1] == 1.0f &&
matrix->m[2][0] == 0.0f &&
matrix->m[2][1] == 0.0f &&
matrix->m[2][2] == 1.0f);
}
static void _multiply_matrix(lv_matrix_t * matrix, const lv_matrix_t * mul)
{
/*TODO: use NEON to optimize this function on ARM architecture.*/
lv_matrix_t tmp;
for(int y = 0; y < 3; y++) {
for(int x = 0; x < 3; x++) {
tmp.m[y][x] = (matrix->m[y][0] * mul->m[0][x])
+ (matrix->m[y][1] * mul->m[1][x])
+ (matrix->m[y][2] * mul->m[2][x]);
}
}
lv_memcpy(matrix, &tmp, sizeof(lv_matrix_t));
}
static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_t * src)
{
lv_memcpy(&(dst->fill_dsc), &(src->fill_dsc), sizeof(lv_vector_fill_dsc_t));
@@ -111,89 +84,6 @@ static void _copy_draw_dsc(lv_vector_draw_dsc_t * dst, const lv_vector_draw_dsc_
* GLOBAL FUNCTIONS
**********************/
/* matrix functions */
void lv_matrix_identity(lv_matrix_t * matrix)
{
matrix->m[0][0] = 1.0f;
matrix->m[0][1] = 0.0f;
matrix->m[0][2] = 0.0f;
matrix->m[1][0] = 0.0f;
matrix->m[1][1] = 1.0f;
matrix->m[1][2] = 0.0f;
matrix->m[2][0] = 0.0f;
matrix->m[2][1] = 0.0f;
matrix->m[2][2] = 1.0f;
}
void lv_matrix_translate(lv_matrix_t * matrix, float dx, float dy)
{
if(_is_identity_or_translation(matrix)) {
/*optimization for matrix translation.*/
matrix->m[0][2] += dx;
matrix->m[1][2] += dy;
return;
}
lv_matrix_t tlm = {{
{1.0f, 0.0f, dx},
{0.0f, 1.0f, dy},
{0.0f, 0.0f, 1.0f},
}
};
_multiply_matrix(matrix, &tlm);
}
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y)
{
lv_matrix_t scm = {{
{scale_x, 0.0f, 0.0f},
{0.0f, scale_y, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
_multiply_matrix(matrix, &scm);
}
void lv_matrix_rotate(lv_matrix_t * matrix, float degree)
{
float radian = degree / 180.0f * (float)M_PI;
float cos_r = cosf(radian);
float sin_r = sinf(radian);
lv_matrix_t rtm = {{
{cos_r, -sin_r, 0.0f},
{sin_r, cos_r, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
_multiply_matrix(matrix, &rtm);
}
void lv_matrix_skew(lv_matrix_t * matrix, float skew_x, float skew_y)
{
float rskew_x = skew_x / 180.0f * (float)M_PI;
float rskew_y = skew_y / 180.0f * (float)M_PI;
float tan_x = tanf(rskew_x);
float tan_y = tanf(rskew_y);
lv_matrix_t skm = {{
{1.0f, tan_x, 0.0f},
{tan_y, 1.0f, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
_multiply_matrix(matrix, &skm);
}
void lv_matrix_multiply(lv_matrix_t * matrix, const lv_matrix_t * m)
{
_multiply_matrix(matrix, m);
}
void lv_matrix_transform_point(const lv_matrix_t * matrix, lv_fpoint_t * point)
{
float x = point->x;

View File

@@ -15,9 +15,14 @@ extern "C" {
*********************/
#include "lv_draw.h"
#include "../misc/lv_array.h"
#include "../misc/lv_matrix.h"
#if LV_USE_VECTOR_GRAPHIC
#if !LV_USE_MATRIX
#error "lv_draw_vector needs LV_USE_MATRIX = 1"
#endif
/**********************
* TYPEDEFS
**********************/
@@ -95,10 +100,6 @@ typedef struct {
float y;
} lv_fpoint_t;
typedef struct {
float m[3][3];
} lv_matrix_t;
typedef struct {
lv_vector_path_quality_t quality;
lv_array_t ops;
@@ -166,50 +167,6 @@ typedef struct {
* GLOBAL PROTOTYPES
**********************/
/**
* Set matrix to identity matrix
* @param matrix pointer to a matrix
*/
void lv_matrix_identity(lv_matrix_t * matrix);
/**
* Translate the matrix to new position
* @param matrix pointer to a matrix
* @param tx the amount of translate in x direction
* @param tx the amount of translate in y direction
*/
void lv_matrix_translate(lv_matrix_t * matrix, float tx, float ty);
/**
* Change the scale factor of the matrix
* @param matrix pointer to a matrix
* @param scale_x the scale factor for the X direction
* @param scale_y the scale factor for the Y direction
*/
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y);
/**
* Rotate the matrix with origin
* @param matrix pointer to a matrix
* @param degree angle to rotate
*/
void lv_matrix_rotate(lv_matrix_t * matrix, float degree);
/**
* Change the skew factor of the matrix
* @param matrix pointer to a matrix
* @param skew_x the skew factor for x direction
* @param skew_y the skew factor for y direction
*/
void lv_matrix_skew(lv_matrix_t * matrix, float skew_x, float skew_y);
/**
* Multiply two matrix and store the result to the first one
* @param matrix pointer to a matrix
* @param matrix2 pointer to another matrix
*/
void lv_matrix_multiply(lv_matrix_t * matrix, const lv_matrix_t * matrix2);
/**
* Transform the coordinates of a point using given matrix
* @param matrix pointer to a matrix

View File

@@ -116,6 +116,12 @@ static void draw_execute(lv_draw_vg_lite_unit_t * u)
vg_lite_identity(&u->global_matrix);
vg_lite_translate(-layer->buf_area.x1, -layer->buf_area.y1, &u->global_matrix);
#if LV_DRAW_TRANSFORM_USE_MATRIX
vg_lite_matrix_t layer_matrix;
lv_vg_lite_matrix(&layer_matrix, &t->matrix);
lv_vg_lite_matrix_multiply(&u->global_matrix, &layer_matrix);
#endif
switch(t->type) {
case LV_DRAW_TASK_TYPE_LABEL:
lv_draw_vg_lite_label(draw_unit, t->draw_dsc, &t->area);

View File

@@ -198,6 +198,7 @@ static void draw_letter_bitmap(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_d
vg_lite_matrix_t path_matrix;
vg_lite_identity(&path_matrix);
lv_vg_lite_matrix_multiply(&path_matrix, &u->global_matrix);
LV_VG_LITE_ASSERT_MATRIX(&path_matrix);
LV_PROFILER_BEGIN_TAG("vg_lite_draw_pattern");
LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
@@ -243,16 +244,24 @@ static void draw_letter_outline(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_
lv_vg_lite_path_t * outline = (lv_vg_lite_path_t *)dsc->glyph_data;
lv_point_t pos = {dsc->letter_coords->x1, dsc->letter_coords->y1};
/* scale size */
float scale = FT_F26DOT6_TO_PATH_SCALE(lv_freetype_outline_get_scale(dsc->g->resolved_font));
/* 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);
/* matrix for drawing, different from matrix for calculating the bonding box */
vg_lite_matrix_t draw_matrix;
vg_lite_identity(&draw_matrix);
lv_vg_lite_matrix_multiply(&draw_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, &draw_matrix);
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, &draw_matrix);
vg_lite_scale(scale, scale, &matrix);
/* calc inverse matrix */
@@ -272,20 +281,16 @@ static void draw_letter_outline(lv_draw_vg_lite_unit_t * u, const lv_draw_glyph_
/* 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);
/* Move to the position relative to the first address of the buffer */
lv_layer_t * layer = u->base_unit.target_layer;
vg_lite_translate(-layer->buf_area.x1 / scale, layer->buf_area.y1 / scale, &matrix);
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_ASSERT_MATRIX(&matrix);
LV_VG_LITE_ASSERT_MATRIX(&draw_matrix);
LV_PROFILER_BEGIN_TAG("vg_lite_draw");
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)));
&draw_matrix, VG_LITE_BLEND_SRC_OVER, lv_vg_lite_color(dsc->color, dsc->opa, true)));
LV_PROFILER_END_TAG("vg_lite_draw");
/* Flush in time to avoid accumulation of drawing commands */

View File

@@ -35,7 +35,6 @@ typedef void (*path_drop_func_t)(struct _lv_draw_vg_lite_unit_t *, path_drop_dat
**********************/
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_path_type_t lv_path_opa_to_path_type(const lv_vector_draw_dsc_t * dsc);
static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend);
@@ -106,7 +105,7 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec
/* transform matrix */
vg_lite_matrix_t matrix;
lv_matrix_to_vg(&matrix, &dsc->matrix);
lv_vg_lite_matrix(&matrix, &dsc->matrix);
LV_VG_LITE_ASSERT_MATRIX(&matrix);
/* convert path */
@@ -223,7 +222,7 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec
lv_matrix_multiply(&m, &dsc->fill_dsc.matrix);
vg_lite_matrix_t pattern_matrix;
lv_matrix_to_vg(&pattern_matrix, &m);
lv_vg_lite_matrix(&pattern_matrix, &m);
vg_lite_color_t recolor = lv_vg_lite_color(dsc->fill_dsc.img_dsc.recolor, dsc->fill_dsc.img_dsc.recolor_opa, true);
@@ -250,7 +249,7 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec
break;
case LV_VECTOR_DRAW_STYLE_GRADIENT: {
vg_lite_matrix_t grad_matrix;
lv_matrix_to_vg(&grad_matrix, &dsc->fill_dsc.matrix);
lv_vg_lite_matrix(&grad_matrix, &dsc->fill_dsc.matrix);
lv_vg_lite_draw_grad(
u,
@@ -282,11 +281,6 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec
LV_PROFILER_END;
}
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) {

View File

@@ -153,9 +153,9 @@ bool lv_vg_lite_draw_grad(
vg_lite_linear_gradient_t * linear_grad = &grad_item->vg.linear;
vg_lite_matrix_t * grad_mat_p = vg_lite_get_grad_matrix(linear_grad);
LV_ASSERT_NULL(grad_mat_p);
grad_point_to_matrix(grad_mat_p, grad->x1, grad->y1, grad->x2, grad->y2);
vg_lite_identity(grad_mat_p);
lv_vg_lite_matrix_multiply(grad_mat_p, grad_matrix);
grad_point_to_matrix(grad_mat_p, grad->x1, grad->y1, grad->x2, grad->y2);
LV_VG_LITE_ASSERT_SRC_BUFFER(&linear_grad->image);
@@ -314,10 +314,7 @@ bool lv_vg_lite_draw_grad_helper(
return false;
}
vg_lite_matrix_t grad_matrix;
vg_lite_identity(&grad_matrix);
return lv_vg_lite_draw_grad(u, buffer, path, &grad, &grad_matrix, matrix, fill, blend);
return lv_vg_lite_draw_grad(u, buffer, path, &grad, matrix, matrix, fill, blend);
}
/**********************
@@ -548,7 +545,6 @@ static grad_type_t lv_grad_style_to_type(lv_vector_gradient_style_t style)
static void grad_point_to_matrix(vg_lite_matrix_t * grad_matrix, float x1, float y1, float x2, float y2)
{
vg_lite_identity(grad_matrix);
vg_lite_translate(x1, y1, grad_matrix);
float angle = atan2f(y2 - y1, x2 - x1) * 180.0f / (float)M_PI;

View File

@@ -776,6 +776,15 @@ void lv_vg_lite_rect(vg_lite_rectangle_t * rect, const lv_area_t * area)
rect->height = lv_area_get_height(area);
}
#if LV_USE_MATRIX
void lv_vg_lite_matrix(vg_lite_matrix_t * dest, const lv_matrix_t * src)
{
lv_memcpy(dest, src, sizeof(lv_matrix_t));
}
#endif
uint32_t lv_vg_lite_get_palette_size(vg_lite_buffer_format_t format)
{
uint32_t size = 0;

View File

@@ -145,6 +145,12 @@ 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);
#if LV_USE_MATRIX
void lv_vg_lite_matrix(vg_lite_matrix_t * dest, const lv_matrix_t * src);
#endif
/* Param checker */
bool lv_vg_lite_buffer_check(const vg_lite_buffer_t * buffer, bool is_src);

View File

@@ -836,11 +836,13 @@ static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwB
//Initialize X range
auto height = yEnd - yStart;
aaSpans->lines = static_cast<AALine*>(calloc(height, sizeof(AALine)));
aaSpans->lines = static_cast<AALine*>(malloc(height * sizeof(AALine)));
for (int32_t i = 0; i < height; i++) {
aaSpans->lines[i].x[0] = INT32_MAX;
aaSpans->lines[i].x[1] = INT32_MIN;
aaSpans->lines[i].x[1] = 0;
aaSpans->lines[i].length[0] = 0;
aaSpans->lines[i].length[1] = 0;
}
return aaSpans;
}

View File

@@ -293,6 +293,18 @@
#endif
#endif
/*Using matrix for transformations.
*Requirements:
`LV_USE_MATRIX = 1`.
The rendering engine needs to support 3x3 matrix transformations.*/
#ifndef LV_DRAW_TRANSFORM_USE_MATRIX
#ifdef CONFIG_LV_DRAW_TRANSFORM_USE_MATRIX
#define LV_DRAW_TRANSFORM_USE_MATRIX CONFIG_LV_DRAW_TRANSFORM_USE_MATRIX
#else
#define LV_DRAW_TRANSFORM_USE_MATRIX 0
#endif
#endif
/* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode
* it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks.
* "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers
@@ -1291,6 +1303,16 @@
#endif
#endif
/*Enable matrix support
*Requires `LV_USE_FLOAT = 1`*/
#ifndef LV_USE_MATRIX
#ifdef CONFIG_LV_USE_MATRIX
#define LV_USE_MATRIX CONFIG_LV_USE_MATRIX
#else
#define LV_USE_MATRIX 0
#endif
#endif
/*==================
* FONT USAGE
*===================*/
@@ -2636,7 +2658,8 @@
#endif
#endif
/*Enable Vector Graphic APIs*/
/*Enable Vector Graphic APIs
*Requires `LV_USE_MATRIX = 1`*/
#ifndef LV_USE_VECTOR_GRAPHIC
#ifdef CONFIG_LV_USE_VECTOR_GRAPHIC
#define LV_USE_VECTOR_GRAPHIC CONFIG_LV_USE_VECTOR_GRAPHIC

227
src/misc/lv_matrix.c Normal file
View File

@@ -0,0 +1,227 @@
/**
* @file lv_matrix.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_matrix.h"
#if LV_USE_MATRIX
#include "../stdlib/lv_string.h"
#include "lv_math.h"
#include <math.h>
/*********************
* DEFINES
*********************/
#ifndef M_PI
#define M_PI 3.1415926f
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_matrix_identity(lv_matrix_t * matrix)
{
matrix->m[0][0] = 1.0f;
matrix->m[0][1] = 0.0f;
matrix->m[0][2] = 0.0f;
matrix->m[1][0] = 0.0f;
matrix->m[1][1] = 1.0f;
matrix->m[1][2] = 0.0f;
matrix->m[2][0] = 0.0f;
matrix->m[2][1] = 0.0f;
matrix->m[2][2] = 1.0f;
}
void lv_matrix_translate(lv_matrix_t * matrix, float dx, float dy)
{
if(lv_matrix_is_identity_or_translation(matrix)) {
/*optimization for matrix translation.*/
matrix->m[0][2] += dx;
matrix->m[1][2] += dy;
return;
}
lv_matrix_t tlm = {{
{1.0f, 0.0f, dx},
{0.0f, 1.0f, dy},
{0.0f, 0.0f, 1.0f},
}
};
lv_matrix_multiply(matrix, &tlm);
}
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y)
{
lv_matrix_t scm = {{
{scale_x, 0.0f, 0.0f},
{0.0f, scale_y, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
lv_matrix_multiply(matrix, &scm);
}
void lv_matrix_rotate(lv_matrix_t * matrix, float degree)
{
float radian = degree / 180.0f * (float)M_PI;
float cos_r = cosf(radian);
float sin_r = sinf(radian);
lv_matrix_t rtm = {{
{cos_r, -sin_r, 0.0f},
{sin_r, cos_r, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
lv_matrix_multiply(matrix, &rtm);
}
void lv_matrix_skew(lv_matrix_t * matrix, float skew_x, float skew_y)
{
float rskew_x = skew_x / 180.0f * (float)M_PI;
float rskew_y = skew_y / 180.0f * (float)M_PI;
float tan_x = tanf(rskew_x);
float tan_y = tanf(rskew_y);
lv_matrix_t skm = {{
{1.0f, tan_x, 0.0f},
{tan_y, 1.0f, 0.0f},
{0.0f, 0.0f, 1.0f},
}
};
lv_matrix_multiply(matrix, &skm);
}
void lv_matrix_multiply(lv_matrix_t * matrix, const lv_matrix_t * mul)
{
/*TODO: use NEON to optimize this function on ARM architecture.*/
lv_matrix_t tmp;
for(int y = 0; y < 3; y++) {
for(int x = 0; x < 3; x++) {
tmp.m[y][x] = (matrix->m[y][0] * mul->m[0][x])
+ (matrix->m[y][1] * mul->m[1][x])
+ (matrix->m[y][2] * mul->m[2][x]);
}
}
lv_memcpy(matrix, &tmp, sizeof(lv_matrix_t));
}
bool lv_matrix_inverse(lv_matrix_t * matrix, const lv_matrix_t * m)
{
float det00, det01, det02;
float d;
bool is_affine;
/* Test for identity matrix. */
if(m == NULL) {
lv_matrix_identity(matrix);
return true;
}
det00 = (m->m[1][1] * m->m[2][2]) - (m->m[2][1] * m->m[1][2]);
det01 = (m->m[2][0] * m->m[1][2]) - (m->m[1][0] * m->m[2][2]);
det02 = (m->m[1][0] * m->m[2][1]) - (m->m[2][0] * m->m[1][1]);
/* Compute determinant. */
d = (m->m[0][0] * det00) + (m->m[0][1] * det01) + (m->m[0][2] * det02);
/* Return 0 if there is no inverse matrix. */
if(d == 0.0f)
return false;
/* Compute reciprocal. */
d = 1.0f / d;
/* Determine if the matrix is affine. */
is_affine = (m->m[2][0] == 0.0f) && (m->m[2][1] == 0.0f) && (m->m[2][2] == 1.0f);
matrix->m[0][0] = d * det00;
matrix->m[0][1] = d * ((m->m[2][1] * m->m[0][2]) - (m->m[0][1] * m->m[2][2]));
matrix->m[0][2] = d * ((m->m[0][1] * m->m[1][2]) - (m->m[1][1] * m->m[0][2]));
matrix->m[1][0] = d * det01;
matrix->m[1][1] = d * ((m->m[0][0] * m->m[2][2]) - (m->m[2][0] * m->m[0][2]));
matrix->m[1][2] = d * ((m->m[1][0] * m->m[0][2]) - (m->m[0][0] * m->m[1][2]));
matrix->m[2][0] = is_affine ? 0.0f : d * det02;
matrix->m[2][1] = is_affine ? 0.0f : d * ((m->m[2][0] * m->m[0][1]) - (m->m[0][0] * m->m[2][1]));
matrix->m[2][2] = is_affine ? 1.0f : d * ((m->m[0][0] * m->m[1][1]) - (m->m[1][0] * m->m[0][1]));
/* Success. */
return true;
}
lv_point_precise_t lv_matrix_transform_precise_point(const lv_matrix_t * matrix, const lv_point_precise_t * point)
{
lv_point_precise_t p;
p.x = (lv_value_precise_t)(point->x * matrix->m[0][0] + point->y * matrix->m[0][1] + matrix->m[0][2]);
p.y = (lv_value_precise_t)(point->x * matrix->m[1][0] + point->y * matrix->m[1][1] + matrix->m[1][2]);
return p;
}
lv_area_t lv_matrix_transform_area(const lv_matrix_t * matrix, const lv_area_t * area)
{
lv_area_t res;
lv_point_precise_t p[4] = {
{area->x1, area->y1},
{area->x1, area->y2},
{area->x2, area->y1},
{area->x2, area->y2},
};
p[0] = lv_matrix_transform_precise_point(matrix, &p[0]);
p[1] = lv_matrix_transform_precise_point(matrix, &p[1]);
p[2] = lv_matrix_transform_precise_point(matrix, &p[2]);
p[3] = lv_matrix_transform_precise_point(matrix, &p[3]);
res.x1 = (int32_t)(LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x));
res.x2 = (int32_t)(LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x));
res.y1 = (int32_t)(LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y));
res.y2 = (int32_t)(LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y));
return res;
}
bool lv_matrix_is_identity_or_translation(const lv_matrix_t * matrix)
{
return (matrix->m[0][0] == 1.0f &&
matrix->m[0][1] == 0.0f &&
matrix->m[1][0] == 0.0f &&
matrix->m[1][1] == 1.0f &&
matrix->m[2][0] == 0.0f &&
matrix->m[2][1] == 0.0f &&
matrix->m[2][2] == 1.0f);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_MATRIX*/

130
src/misc/lv_matrix.h Normal file
View File

@@ -0,0 +1,130 @@
/**
* @file lv_matrix.h
*
*/
#ifndef LV_MATRIX_H
#define LV_MATRIX_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
#if LV_USE_MATRIX
#include "lv_types.h"
#include "lv_area.h"
/*********************
* DEFINES
*********************/
#if !LV_USE_FLOAT
#error "LV_USE_FLOAT is required for lv_matrix"
#endif
/**********************
* TYPEDEFS
**********************/
typedef struct {
float m[3][3];
} lv_matrix_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Set matrix to identity matrix
* @param matrix pointer to a matrix
*/
void lv_matrix_identity(lv_matrix_t * matrix);
/**
* Translate the matrix to new position
* @param matrix pointer to a matrix
* @param tx the amount of translate in x direction
* @param tx the amount of translate in y direction
*/
void lv_matrix_translate(lv_matrix_t * matrix, float tx, float ty);
/**
* Change the scale factor of the matrix
* @param matrix pointer to a matrix
* @param scale_x the scale factor for the X direction
* @param scale_y the scale factor for the Y direction
*/
void lv_matrix_scale(lv_matrix_t * matrix, float scale_x, float scale_y);
/**
* Rotate the matrix with origin
* @param matrix pointer to a matrix
* @param degree angle to rotate
*/
void lv_matrix_rotate(lv_matrix_t * matrix, float degree);
/**
* Change the skew factor of the matrix
* @param matrix pointer to a matrix
* @param skew_x the skew factor for x direction
* @param skew_y the skew factor for y direction
*/
void lv_matrix_skew(lv_matrix_t * matrix, float skew_x, float skew_y);
/**
* Multiply two matrix and store the result to the first one
* @param matrix pointer to a matrix
* @param matrix2 pointer to another matrix
*/
void lv_matrix_multiply(lv_matrix_t * matrix, const lv_matrix_t * mul);
/**
* Invert the matrix
* @param matrix pointer to a matrix
* @param m pointer to another matrix (optional)
* @return true: the matrix is invertible, false: the matrix is singular and cannot be inverted
*/
bool lv_matrix_inverse(lv_matrix_t * matrix, const lv_matrix_t * m);
/**
* Transform a point by a matrix
* @param matrix pointer to a matrix
* @param point pointer to a point
* @return the transformed point
*/
lv_point_precise_t lv_matrix_transform_precise_point(const lv_matrix_t * matrix, const lv_point_precise_t * point);
/**
* Transform an area by a matrix
* @param matrix pointer to a matrix
* @param area pointer to an area
* @return the transformed area
*/
lv_area_t lv_matrix_transform_area(const lv_matrix_t * matrix, const lv_area_t * area);
/**
* Check if the matrix is identity or translation matrix
* @param matrix pointer to a matrix
* @return true: the matrix is identity or translation matrix, false: the matrix is not identity or translation matrix
*/
bool lv_matrix_is_identity_or_translation(const lv_matrix_t * matrix);
/**********************
* MACROS
**********************/
#endif /*LV_USE_MATRIX*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_MATRIX_H*/

View File

@@ -111,6 +111,9 @@ lv_result_t lv_snapshot_take_to_draw_buf(lv_obj_t * obj, lv_color_format_t cf, l
layer.buf_area.y2 = snapshot_area.y1 + h - 1;
layer.color_format = cf;
layer._clip_area = snapshot_area;
#if LV_DRAW_TRANSFORM_USE_MATRIX
lv_matrix_identity(&layer.matrix);
#endif
lv_display_t * disp_old = _lv_refr_get_disp_refreshing();
lv_display_t * disp_new = lv_obj_get_display(obj);

View File

@@ -377,6 +377,9 @@ void lv_canvas_init_layer(lv_obj_t * obj, lv_layer_t * layer)
layer->color_format = header->cf;
layer->buf_area = canvas_area;
layer->_clip_area = canvas_area;
#if LV_DRAW_TRANSFORM_USE_MATRIX
lv_matrix_identity(&layer->matrix);
#endif
}
void lv_canvas_finish_layer(lv_obj_t * canvas, lv_layer_t * layer)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -110,10 +110,6 @@ typedef void * lv_user_data_t;
#define LV_DPI_DEF 130
#endif
#if defined(LVGL_CI_USING_SYS_HEAP)
#undef LV_USE_FLOAT
#endif
#ifdef __cplusplus
} /*extern "C"*/
#endif

View File

@@ -10,6 +10,7 @@
#define LV_USE_ASSERT_OBJ 1
#define LV_USE_ASSERT_STYLE 1
#define LV_USE_FLOAT 1
#define LV_USE_MATRIX 1
#define LV_FONT_MONTSERRAT_8 1
#define LV_FONT_MONTSERRAT_10 1

View File

@@ -31,3 +31,9 @@
/* Enable performance monitor log mode for build test */
#define LV_USE_PERF_MONITOR_LOG_MODE 1
/*Using matrix for transformations.
*Requirements:
`LV_USE_MATRIX = 1`.
The rendering engine needs to support 3x3 matrix transformations.*/
#define LV_DRAW_TRANSFORM_USE_MATRIX 1