mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-23 01:33:59 +08:00
feat(obj): add transform matrix attribute (#7187)
This commit is contained in:
parent
f89ac3677e
commit
43a3c65b82
@ -111,6 +111,7 @@ void lv_example_msgbox_2(void);
|
||||
|
||||
void lv_example_obj_1(void);
|
||||
void lv_example_obj_2(void);
|
||||
void lv_example_obj_3(void);
|
||||
|
||||
void lv_example_roller_1(void);
|
||||
void lv_example_roller_2(void);
|
||||
|
@ -11,3 +11,8 @@ Make an object draggable
|
||||
.. lv_example:: widgets/obj/lv_example_obj_2
|
||||
:language: c
|
||||
|
||||
Transform object using a 3x3 matrix
|
||||
-----------------------------------
|
||||
|
||||
.. lv_example:: widgets/obj/lv_example_obj_3
|
||||
:language: c
|
||||
|
42
examples/widgets/obj/lv_example_obj_3.c
Normal file
42
examples/widgets/obj/lv_example_obj_3.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_BUILD_EXAMPLES
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
|
||||
static void timer_cb(lv_timer_t * timer)
|
||||
{
|
||||
lv_obj_t * obj = lv_timer_get_user_data(timer);
|
||||
|
||||
static float value = 0.1f;
|
||||
lv_matrix_t matrix;
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_matrix_scale(&matrix, value, 1);
|
||||
lv_matrix_rotate(&matrix, value * 360);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
|
||||
value += 0.01f;
|
||||
|
||||
if(value > 2.0f) {
|
||||
lv_obj_reset_transform(obj);
|
||||
value = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
void lv_example_obj_3(void)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_create(lv_screen_active());
|
||||
lv_obj_center(obj);
|
||||
|
||||
lv_timer_create(timer_cb, 20, obj);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void lv_example_obj_3(void)
|
||||
{
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text_static(label, "LV_DRAW_TRANSFORM_USE_MATRIX is not enabled");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
#endif /*LV_DRAW_TRANSFORM_USE_MATRIX*/
|
||||
#endif /*LV_BUILD_EXAMPLES*/
|
@ -541,6 +541,13 @@ static void lv_obj_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
|
||||
|
||||
lv_event_remove_all(&obj->spec_attr->event_list);
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
if(obj->spec_attr->matrix) {
|
||||
lv_free(obj->spec_attr->matrix);
|
||||
obj->spec_attr->matrix = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
lv_free(obj->spec_attr);
|
||||
obj->spec_attr = NULL;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "../layouts/lv_layout_private.h"
|
||||
#include "lv_obj_event_private.h"
|
||||
#include "lv_obj_draw_private.h"
|
||||
#include "lv_obj_style_private.h"
|
||||
#include "lv_obj_private.h"
|
||||
#include "../display/lv_display.h"
|
||||
#include "../display/lv_display_private.h"
|
||||
@ -983,6 +984,82 @@ void lv_obj_center(lv_obj_t * obj)
|
||||
lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
void lv_obj_set_transform(lv_obj_t * obj, const lv_matrix_t * matrix)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
|
||||
if(!matrix) {
|
||||
lv_obj_reset_transform(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_allocate_spec_attr(obj);
|
||||
if(!obj->spec_attr->matrix) {
|
||||
obj->spec_attr->matrix = lv_malloc(sizeof(lv_matrix_t));;
|
||||
LV_ASSERT_MALLOC(obj->spec_attr->matrix);
|
||||
}
|
||||
|
||||
/* Invalidate the old area */
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
/* Copy the matrix */
|
||||
*obj->spec_attr->matrix = *matrix;
|
||||
|
||||
/* Matrix is set. Update the layer type */
|
||||
lv_obj_update_layer_type(obj);
|
||||
|
||||
/* Invalidate the new area */
|
||||
lv_obj_invalidate(obj);
|
||||
#else
|
||||
LV_UNUSED(obj);
|
||||
LV_UNUSED(matrix);
|
||||
LV_LOG_WARN("Transform matrix is not used because LV_DRAW_TRANSFORM_USE_MATRIX is disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
void lv_obj_reset_transform(lv_obj_t * obj)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
if(!obj->spec_attr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!obj->spec_attr->matrix) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Invalidate the old area */
|
||||
lv_obj_invalidate(obj);
|
||||
|
||||
/* Free the matrix */
|
||||
lv_free(obj->spec_attr->matrix);
|
||||
obj->spec_attr->matrix = NULL;
|
||||
|
||||
/* Matrix is cleared. Update the layer type */
|
||||
lv_obj_update_layer_type(obj);
|
||||
|
||||
/* Invalidate the new area */
|
||||
lv_obj_invalidate(obj);
|
||||
#else
|
||||
LV_UNUSED(obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
const lv_matrix_t * lv_obj_get_transform(const lv_obj_t * obj)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
LV_ASSERT_OBJ(obj, MY_CLASS);
|
||||
if(obj->spec_attr) {
|
||||
return obj->spec_attr->matrix;
|
||||
}
|
||||
#else
|
||||
LV_UNUSED(obj);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@ -1170,6 +1247,31 @@ static void layout_update_core(lv_obj_t * obj)
|
||||
|
||||
static void transform_point_array(const lv_obj_t * obj, lv_point_t * p, size_t p_count, bool inv)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
const lv_matrix_t * obj_matrix = lv_obj_get_transform(obj);
|
||||
if(obj_matrix) {
|
||||
lv_matrix_t m;
|
||||
lv_matrix_identity(&m);
|
||||
lv_matrix_translate(&m, obj->coords.x1, obj->coords.y1);
|
||||
lv_matrix_multiply(&m, obj_matrix);
|
||||
lv_matrix_translate(&m, -obj->coords.x1, -obj->coords.y1);
|
||||
|
||||
if(inv) {
|
||||
lv_matrix_t inv_m;
|
||||
lv_matrix_inverse(&inv_m, &m);
|
||||
m = inv_m;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < p_count; i++) {
|
||||
lv_point_precise_t p_precise = lv_point_to_precise(&p[i]);
|
||||
lv_point_precise_t res = lv_matrix_transform_precise_point(&m, &p_precise);
|
||||
p[i] = lv_point_from_precise(&res);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* LV_DRAW_TRANSFORM_USE_MATRIX */
|
||||
|
||||
int32_t angle = lv_obj_get_style_transform_rotation(obj, 0);
|
||||
int32_t scale_x = lv_obj_get_style_transform_scale_x_safe(obj, 0);
|
||||
int32_t scale_y = lv_obj_get_style_transform_scale_y_safe(obj, 0);
|
||||
|
@ -197,6 +197,21 @@ void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, in
|
||||
*/
|
||||
void lv_obj_center(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Set the transfrom matrix of an object
|
||||
* @param obj pointer to an object
|
||||
* @param matrix pointer to a matrix to set
|
||||
* @note `LV_DRAW_TRANSFORM_USE_MATRIX` needs to be enabled.
|
||||
*/
|
||||
void lv_obj_set_transform(lv_obj_t * obj, const lv_matrix_t * matrix);
|
||||
|
||||
/**
|
||||
* Reset the transfrom matrix of an object to identity matrix
|
||||
* @param obj pointer to an object
|
||||
* @note `LV_DRAW_TRANSFORM_USE_MATRIX` needs to be enabled.
|
||||
*/
|
||||
void lv_obj_reset_transform(lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Copy the coordinates of an object to an area
|
||||
* @param obj pointer to an object
|
||||
@ -342,6 +357,13 @@ void lv_obj_move_to(lv_obj_t * obj, int32_t x, int32_t y);
|
||||
|
||||
void lv_obj_move_children_by(lv_obj_t * obj, int32_t x_diff, int32_t y_diff, bool ignore_floating);
|
||||
|
||||
/**
|
||||
* Get the transform matrix of an object
|
||||
* @param obj pointer to an object
|
||||
* @return pointer to the transform matrix or NULL if not set
|
||||
*/
|
||||
const lv_matrix_t * lv_obj_get_transform(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Transform a point using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
|
@ -31,6 +31,9 @@ extern "C" {
|
||||
struct _lv_obj_spec_attr_t {
|
||||
lv_obj_t ** children; /**< Store the pointer of the children in an array.*/
|
||||
lv_group_t * group_p;
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_matrix_t * matrix; /**< The transform matrix*/
|
||||
#endif
|
||||
lv_event_list_t event_list;
|
||||
|
||||
lv_point_t scroll; /**< The current X/Y scroll offset*/
|
||||
|
@ -966,6 +966,9 @@ static void trans_anim_completed_cb(lv_anim_t * a)
|
||||
|
||||
static lv_layer_type_t calculate_layer_type(lv_obj_t * obj)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
if(lv_obj_get_transform(obj) != NULL) return LV_LAYER_TYPE_TRANSFORM;
|
||||
#endif
|
||||
if(lv_obj_get_style_transform_rotation(obj, 0) != 0) return LV_LAYER_TYPE_TRANSFORM;
|
||||
if(lv_obj_get_style_transform_scale_x(obj, 0) != 256) return LV_LAYER_TYPE_TRANSFORM;
|
||||
if(lv_obj_get_style_transform_scale_y(obj, 0) != 256) return LV_LAYER_TYPE_TRANSFORM;
|
||||
|
@ -969,11 +969,17 @@ static bool alpha_test_area_on_obj(lv_obj_t * obj, const lv_area_t * area)
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
|
||||
static void refr_obj_matrix(lv_layer_t * layer, lv_obj_t * obj)
|
||||
static bool obj_get_matrix(lv_obj_t * obj, lv_matrix_t * matrix)
|
||||
{
|
||||
lv_matrix_t ori_matrix = layer->matrix;
|
||||
lv_matrix_t obj_matrix;
|
||||
lv_matrix_identity(&obj_matrix);
|
||||
lv_matrix_identity(matrix);
|
||||
|
||||
const lv_matrix_t * obj_matrix = lv_obj_get_transform(obj);
|
||||
if(obj_matrix) {
|
||||
lv_matrix_translate(matrix, obj->coords.x1, obj->coords.y1);
|
||||
lv_matrix_multiply(matrix, obj_matrix);
|
||||
lv_matrix_translate(matrix, -obj->coords.x1, -obj->coords.y1);
|
||||
return true;
|
||||
}
|
||||
|
||||
lv_point_t pivot = {
|
||||
.x = lv_obj_get_style_transform_pivot_x(obj, 0),
|
||||
@ -991,39 +997,55 @@ static void refr_obj_matrix(lv_layer_t * layer, lv_obj_t * obj)
|
||||
|
||||
if(scale_x <= 0 || scale_y <= 0) {
|
||||
/* NOT draw if scale is negative or zero */
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* generate the obj matrix */
|
||||
lv_matrix_translate(&obj_matrix, pivot.x, pivot.y);
|
||||
lv_matrix_translate(matrix, pivot.x, pivot.y);
|
||||
if(rotation != 0) {
|
||||
lv_matrix_rotate(&obj_matrix, rotation * 0.1f);
|
||||
lv_matrix_rotate(matrix, rotation * 0.1f);
|
||||
}
|
||||
|
||||
if(scale_x != LV_SCALE_NONE || scale_y != LV_SCALE_NONE) {
|
||||
lv_matrix_scale(
|
||||
&obj_matrix,
|
||||
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_skew(matrix, skew_x, skew_y);
|
||||
}
|
||||
|
||||
lv_matrix_translate(&obj_matrix, -pivot.x, -pivot.y);
|
||||
lv_matrix_translate(matrix, -pivot.x, -pivot.y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void refr_obj_matrix(lv_layer_t * layer, lv_obj_t * obj)
|
||||
{
|
||||
lv_matrix_t obj_matrix;
|
||||
if(!obj_get_matrix(obj, &obj_matrix)) {
|
||||
/* NOT draw if obj matrix is not available */
|
||||
return;
|
||||
}
|
||||
|
||||
lv_matrix_t matrix_inv;
|
||||
if(!lv_matrix_inverse(&matrix_inv, &obj_matrix)) {
|
||||
/* NOT draw if matrix is not invertible */
|
||||
return;
|
||||
}
|
||||
|
||||
/* save original matrix */
|
||||
lv_matrix_t ori_matrix = layer->matrix;
|
||||
|
||||
/* 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);
|
||||
clip_area = lv_matrix_transform_area(&matrix_inv, &clip_area);
|
||||
|
||||
/* increase the clip area by 1 pixel to avoid rounding errors */
|
||||
if(!lv_matrix_is_identity_or_translation(&obj_matrix)) {
|
||||
|
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_identity.png
Normal file
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_identity.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_rotate.png
Normal file
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_rotate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_scale.png
Normal file
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_scale.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_skew.png
Normal file
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_skew.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_translate.png
Normal file
BIN
tests/ref_imgs_vg_lite/widgets/obj_transform_translate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
62
tests/src/test_cases/widgets/test_obj_transform.c
Normal file
62
tests/src/test_cases/widgets/test_obj_transform.c
Normal file
@ -0,0 +1,62 @@
|
||||
#if LV_BUILD_TEST
|
||||
#include "../lvgl.h"
|
||||
#include "unity/unity.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
/* Function run after every test */
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
void test_obj_transform(void)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_obj_t * obj = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_size(obj, 100, 100);
|
||||
lv_obj_center(obj);
|
||||
|
||||
lv_matrix_t matrix;
|
||||
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_identity.png");
|
||||
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_matrix_translate(&matrix, 50, 100);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_translate.png");
|
||||
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_matrix_rotate(&matrix, 30);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_rotate.png");
|
||||
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_matrix_scale(&matrix, 0.8f, 1.6f);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_scale.png");
|
||||
|
||||
lv_matrix_identity(&matrix);
|
||||
lv_matrix_skew(&matrix, 10.0f, 20.0f);
|
||||
lv_obj_set_transform(obj, &matrix);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_skew.png");
|
||||
|
||||
const lv_matrix_t * obj_transform = lv_obj_get_transform(obj);
|
||||
TEST_ASSERT_NOT_NULL(obj_transform);
|
||||
TEST_ASSERT_EQUAL(lv_memcmp(&matrix, obj_transform, sizeof(lv_matrix_t)), 0);
|
||||
|
||||
lv_obj_reset_transform(obj);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("widgets/obj_transform_identity.png");
|
||||
TEST_ASSERT_NULL(lv_obj_get_transform(obj));
|
||||
|
||||
#else
|
||||
TEST_PASS();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user