Skip to content

Commit

Permalink
feat(obj): add transform matrix attribute (lvgl#7187)
Browse files Browse the repository at this point in the history
  • Loading branch information
FASTSHIFT authored Nov 9, 2024
1 parent f89ac36 commit 43a3c65
Show file tree
Hide file tree
Showing 15 changed files with 283 additions and 14 deletions.
1 change: 1 addition & 0 deletions examples/widgets/lv_example_widgets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions examples/widgets/obj/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 42 additions & 0 deletions examples/widgets/obj/lv_example_obj_3.c
Original file line number Diff line number Diff line change
@@ -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*/
7 changes: 7 additions & 0 deletions src/core/lv_obj.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
102 changes: 102 additions & 0 deletions src/core/lv_obj_pos.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
**********************/
Expand Down Expand Up @@ -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);
Expand Down
22 changes: 22 additions & 0 deletions src/core/lv_obj_pos.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/core/lv_obj_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*/
Expand Down
3 changes: 3 additions & 0 deletions src/core/lv_obj_style.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
50 changes: 36 additions & 14 deletions src/core/lv_refr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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)) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 43a3c65

Please sign in to comment.