fix(draw): fix the invalidation of scaled areas (#5548)
@ -91,7 +91,6 @@ typedef struct _lv_global_t {
|
||||
|
||||
uint32_t memory_zero;
|
||||
uint32_t math_rand_seed;
|
||||
lv_area_transform_cache_t area_trans_cache;
|
||||
|
||||
lv_event_t * event_header;
|
||||
uint32_t event_last_register_id;
|
||||
|
@ -28,7 +28,7 @@
|
||||
static int32_t calc_content_width(lv_obj_t * obj);
|
||||
static int32_t calc_content_height(lv_obj_t * obj);
|
||||
static void layout_update_core(lv_obj_t * obj);
|
||||
static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv);
|
||||
static void transform_point_array(const lv_obj_t * obj, lv_point_t * p, size_t p_count, bool inv);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -762,36 +762,40 @@ void lv_obj_move_children_by(lv_obj_t * obj, int32_t x_diff, int32_t y_diff, boo
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv)
|
||||
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, lv_obj_point_transform_flag_t flags)
|
||||
{
|
||||
lv_obj_transform_point_array(obj, p, 1, flags);
|
||||
}
|
||||
|
||||
void lv_obj_transform_point_array(const lv_obj_t * obj, lv_point_t points[], size_t count,
|
||||
lv_obj_point_transform_flag_t flags)
|
||||
{
|
||||
if(obj) {
|
||||
lv_layer_type_t layer_type = _lv_obj_get_layer_type(obj);
|
||||
bool do_tranf = layer_type == LV_LAYER_TYPE_TRANSFORM;
|
||||
if(inv) {
|
||||
if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
|
||||
if(do_tranf) transform_point(obj, p, inv);
|
||||
bool recursive = flags & LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE;
|
||||
bool inverse = flags & LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE;
|
||||
if(inverse) {
|
||||
if(recursive) lv_obj_transform_point_array(lv_obj_get_parent(obj), points, count, flags);
|
||||
if(do_tranf) transform_point_array(obj, points, count, inverse);
|
||||
}
|
||||
else {
|
||||
if(do_tranf) transform_point(obj, p, inv);
|
||||
if(recursive) lv_obj_transform_point(lv_obj_get_parent(obj), p, recursive, inv);
|
||||
if(do_tranf) transform_point_array(obj, points, count, inverse);
|
||||
if(recursive) lv_obj_transform_point_array(lv_obj_get_parent(obj), points, count, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, bool recursive,
|
||||
bool inv)
|
||||
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, lv_obj_point_transform_flag_t flags)
|
||||
{
|
||||
lv_point_t p[4] = {
|
||||
{area->x1, area->y1},
|
||||
{area->x1, area->y2},
|
||||
{area->x2, area->y1},
|
||||
{area->x2, area->y2},
|
||||
{area->x1, area->y2 + 1},
|
||||
{area->x2 + 1, area->y1},
|
||||
{area->x2 + 1, area->y2 + 1},
|
||||
};
|
||||
|
||||
lv_obj_transform_point(obj, &p[0], recursive, inv);
|
||||
lv_obj_transform_point(obj, &p[1], recursive, inv);
|
||||
lv_obj_transform_point(obj, &p[2], recursive, inv);
|
||||
lv_obj_transform_point(obj, &p[3], recursive, inv);
|
||||
lv_obj_transform_point_array(obj, p, 4, flags);
|
||||
|
||||
area->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x);
|
||||
area->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x);
|
||||
@ -808,7 +812,13 @@ void lv_obj_invalidate_area(const lv_obj_t * obj, const lv_area_t * area)
|
||||
|
||||
lv_area_t area_tmp;
|
||||
lv_area_copy(&area_tmp, area);
|
||||
|
||||
if(!lv_obj_area_is_visible(obj, &area_tmp)) return;
|
||||
if(obj->spec_attr && obj->spec_attr->layer_type == LV_LAYER_TYPE_TRANSFORM) {
|
||||
/*Make the area slightly larger to avoid rounding errors.
|
||||
*5 is an empirical value*/
|
||||
lv_area_increase(&area_tmp, 5, 5);
|
||||
}
|
||||
|
||||
_lv_inv_area(lv_obj_get_display(obj), &area_tmp);
|
||||
}
|
||||
@ -853,7 +863,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
|
||||
/*The area is not on the object*/
|
||||
if(!_lv_area_intersect(area, area, &obj_coords)) return false;
|
||||
|
||||
lv_obj_get_transformed_area(obj, area, true, false);
|
||||
lv_obj_get_transformed_area(obj, area, LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE);
|
||||
|
||||
/*Truncate recursively to the parents*/
|
||||
lv_obj_t * parent = lv_obj_get_parent(obj);
|
||||
@ -868,7 +878,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area)
|
||||
lv_area_increase(&parent_coords, parent_ext_size, parent_ext_size);
|
||||
}
|
||||
|
||||
lv_obj_get_transformed_area(parent, &parent_coords, true, false);
|
||||
lv_obj_get_transformed_area(parent, &parent_coords, LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE);
|
||||
if(!_lv_area_intersect(area, area, &parent_coords)) return false;
|
||||
|
||||
parent = lv_obj_get_parent(parent);
|
||||
@ -1118,11 +1128,13 @@ static void layout_update_core(lv_obj_t * obj)
|
||||
}
|
||||
}
|
||||
|
||||
static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv)
|
||||
static void transform_point_array(const lv_obj_t * obj, lv_point_t * p, size_t p_count, bool inv)
|
||||
{
|
||||
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);
|
||||
if(scale_x == 0) scale_x = 1;
|
||||
if(scale_y == 0) scale_y = 1;
|
||||
|
||||
if(angle == 0 && scale_x == LV_SCALE_NONE && scale_y == LV_SCALE_NONE) return;
|
||||
|
||||
@ -1143,9 +1155,9 @@ static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv)
|
||||
|
||||
if(inv) {
|
||||
angle = -angle;
|
||||
scale_x = (256 * 256) / scale_x;
|
||||
scale_y = (256 * 256) / scale_y;
|
||||
scale_x = (256 * 256 + scale_x - 1) / scale_x;
|
||||
scale_y = (256 * 256 + scale_y - 1) / scale_y;
|
||||
}
|
||||
|
||||
lv_point_transform(p, angle, scale_x, scale_y, &pivot, !inv);
|
||||
lv_point_array_transform(p, p_count, angle, scale_x, scale_y, &pivot, !inv);
|
||||
}
|
||||
|
@ -23,6 +23,20 @@ extern "C" {
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
/** No flags */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_NONE = 0x00,
|
||||
|
||||
/** Consider the transformation properties of the parents too */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_RECURSIVE = 0x01,
|
||||
|
||||
/** Execute the inverse of the transformation (-angle and 1/zoom) */
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE = 0x02,
|
||||
|
||||
/** Both inverse and recursive*/
|
||||
LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE_RECURSIVE = 0x03,
|
||||
} lv_obj_point_transform_flag_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@ -335,19 +349,27 @@ void lv_obj_move_children_by(lv_obj_t * obj, int32_t x_diff, int32_t y_diff, boo
|
||||
* 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
|
||||
* @param p a point to transform, the result will be written back here too
|
||||
* @param recursive consider the transformation properties of the parents too
|
||||
* @param inv do the inverse of the transformation (-angle and 1/zoom)
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv);
|
||||
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Transform an array of points using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
* @param points the array of points to transform, the result will be written back here too
|
||||
* @param count number of points in the array
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_transform_point_array(const lv_obj_t * obj, lv_point_t points[], size_t count,
|
||||
lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Transform an area using the angle and zoom style properties of an object
|
||||
* @param obj pointer to an object whose style properties should be used
|
||||
* @param area an area to transform, the result will be written back here too
|
||||
* @param recursive consider the transformation properties of the parents too
|
||||
* @param inv do the inverse of the transformation (-angle and 1/zoom)
|
||||
* @param flags OR-ed valued of :cpp:enum:`lv_obj_point_transform_flag_t`
|
||||
*/
|
||||
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, bool recursive, bool inv);
|
||||
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, lv_obj_point_transform_flag_t flags);
|
||||
|
||||
/**
|
||||
* Mark an area of an object as invalid.
|
||||
|
@ -837,7 +837,7 @@ static lv_result_t layer_get_area(lv_layer_t * layer, lv_obj_t * obj, lv_layer_t
|
||||
*This area needs to be updated on the screen.*/
|
||||
lv_area_t clip_coords_for_obj;
|
||||
lv_area_t tranf_coords = *obj_draw_size_out;
|
||||
lv_obj_get_transformed_area(obj, &tranf_coords, false, false);
|
||||
lv_obj_get_transformed_area(obj, &tranf_coords, LV_OBJ_POINT_TRANSFORM_FLAG_NONE);
|
||||
if(!_lv_area_intersect(&clip_coords_for_obj, &layer->_clip_area, &tranf_coords)) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
@ -846,7 +846,7 @@ static lv_result_t layer_get_area(lv_layer_t * layer, lv_obj_t * obj, lv_layer_t
|
||||
*It will tell which area of the non-transformed widget needs to be redrawn
|
||||
*in order to cover transformed area after transformation.*/
|
||||
lv_area_t inverse_clip_coords_for_obj = clip_coords_for_obj;
|
||||
lv_obj_get_transformed_area(obj, &inverse_clip_coords_for_obj, false, true);
|
||||
lv_obj_get_transformed_area(obj, &inverse_clip_coords_for_obj, LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE);
|
||||
if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, obj_draw_size_out)) {
|
||||
return LV_RESULT_INVALID;
|
||||
}
|
||||
@ -931,10 +931,22 @@ void refr_obj(lv_layer_t * layer, lv_obj_t * obj)
|
||||
area_need_alpha ? LV_COLOR_FORMAT_ARGB8888 : LV_COLOR_FORMAT_NATIVE, &layer_area_act);
|
||||
lv_obj_redraw(new_layer, obj);
|
||||
|
||||
lv_point_t pivot = {
|
||||
.x = lv_obj_get_style_transform_pivot_x(obj, 0),
|
||||
.y = lv_obj_get_style_transform_pivot_y(obj, 0)
|
||||
};
|
||||
|
||||
if(LV_COORD_IS_PCT(pivot.x)) {
|
||||
pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100;
|
||||
}
|
||||
if(LV_COORD_IS_PCT(pivot.y)) {
|
||||
pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100;
|
||||
}
|
||||
|
||||
lv_draw_image_dsc_t layer_draw_dsc;
|
||||
lv_draw_image_dsc_init(&layer_draw_dsc);
|
||||
layer_draw_dsc.pivot.x = obj->coords.x1 + lv_obj_get_style_transform_pivot_x(obj, 0) - new_layer->buf_area.x1;
|
||||
layer_draw_dsc.pivot.y = obj->coords.y1 + lv_obj_get_style_transform_pivot_y(obj, 0) - new_layer->buf_area.y1;
|
||||
layer_draw_dsc.pivot.x = obj->coords.x1 + pivot.x - new_layer->buf_area.x1;
|
||||
layer_draw_dsc.pivot.y = obj->coords.y1 + pivot.y - new_layer->buf_area.y1;
|
||||
|
||||
layer_draw_dsc.opa = opa;
|
||||
layer_draw_dsc.rotation = lv_obj_get_style_transform_rotation(obj, 0);
|
||||
|
@ -88,8 +88,8 @@ void lv_draw_sw_transform(lv_draw_unit_t * draw_unit, const lv_area_t * dest_are
|
||||
|
||||
point_transform_dsc_t tr_dsc;
|
||||
tr_dsc.angle = -draw_dsc->rotation;
|
||||
tr_dsc.scale_x = (256 * 256) / draw_dsc->scale_x;
|
||||
tr_dsc.scale_y = (256 * 256) / draw_dsc->scale_y;
|
||||
tr_dsc.scale_x = draw_dsc->scale_x;
|
||||
tr_dsc.scale_y = draw_dsc->scale_y;
|
||||
tr_dsc.pivot = draw_dsc->pivot;
|
||||
|
||||
int32_t angle_low = tr_dsc.angle / 10;
|
||||
@ -622,16 +622,16 @@ static void transform_point_upscaled(point_transform_dsc_t * t, int32_t xin, int
|
||||
yin -= t->pivot.y;
|
||||
|
||||
if(t->angle == 0) {
|
||||
*xout = ((int32_t)(xin * t->scale_x)) + (t->pivot_x_256);
|
||||
*yout = ((int32_t)(yin * t->scale_y)) + (t->pivot_y_256);
|
||||
*xout = ((int32_t)(xin * 256 * 256 / t->scale_x)) + (t->pivot_x_256);
|
||||
*yout = ((int32_t)(yin * 256 * 256 / t->scale_y)) + (t->pivot_y_256);
|
||||
}
|
||||
else if(t->scale_x == LV_SCALE_NONE && t->scale_y == LV_SCALE_NONE) {
|
||||
*xout = ((t->cosma * xin - t->sinma * yin) >> 2) + (t->pivot_x_256);
|
||||
*yout = ((t->sinma * xin + t->cosma * yin) >> 2) + (t->pivot_y_256);
|
||||
}
|
||||
else {
|
||||
*xout = (((t->cosma * xin - t->sinma * yin) * t->scale_x) >> 10) + (t->pivot_x_256);
|
||||
*yout = (((t->sinma * xin + t->cosma * yin) * t->scale_y) >> 10) + (t->pivot_y_256);
|
||||
*xout = (((t->cosma * xin - t->sinma * yin) * 256 / t->scale_x) >> 2) + (t->pivot_x_256);
|
||||
*yout = (((t->sinma * xin + t->cosma * yin) * 256 / t->scale_y) >> 2) + (t->pivot_y_256);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,7 +519,7 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
|
||||
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL;
|
||||
|
||||
lv_point_t p_trans = *point;
|
||||
lv_obj_transform_point(obj, &p_trans, false, true);
|
||||
lv_obj_transform_point(obj, &p_trans, LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE);
|
||||
|
||||
bool hit_test_ok = lv_obj_hit_test(obj, &p_trans);
|
||||
|
||||
|
@ -93,7 +93,6 @@ static inline void lv_global_init(lv_global_t * global)
|
||||
global->style_refresh = true;
|
||||
global->layout_count = _LV_LAYOUT_LAST;
|
||||
global->style_last_custom_prop_id = (uint32_t)_LV_STYLE_LAST_BUILT_IN_PROP;
|
||||
global->area_trans_cache.angle_prev = INT32_MIN;
|
||||
global->event_last_register_id = _LV_EVENT_LAST;
|
||||
lv_rand_set_seed(0x1234ABCD);
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define trans_cache LV_GLOBAL_DEFAULT()->area_trans_cache
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
@ -440,61 +439,73 @@ void lv_area_align(const lv_area_t * base, lv_area_t * to_align, lv_align_t alig
|
||||
}
|
||||
|
||||
#define _LV_TRANSFORM_TRIGO_SHIFT 10
|
||||
void lv_point_transform(lv_point_t * p, int32_t angle, int32_t scale_x, int32_t scale_y, const lv_point_t * pivot,
|
||||
|
||||
void lv_point_transform(lv_point_t * point, int32_t angle, int32_t scale_x, int32_t scale_y, const lv_point_t * pivot,
|
||||
bool zoom_first)
|
||||
{
|
||||
lv_point_array_transform(point, 1, angle, scale_x, scale_y, pivot, zoom_first);
|
||||
}
|
||||
|
||||
void lv_point_array_transform(lv_point_t * points, size_t count, int32_t angle, int32_t scale_x, int32_t scale_y,
|
||||
const lv_point_t * pivot,
|
||||
bool zoom_first)
|
||||
{
|
||||
if(angle == 0 && scale_x == 256 && scale_y == 256) {
|
||||
return;
|
||||
}
|
||||
uint32_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
points[i].x -= pivot->x;
|
||||
points[i].y -= pivot->y;
|
||||
|
||||
p->x -= pivot->x;
|
||||
p->y -= pivot->y;
|
||||
}
|
||||
|
||||
if(angle == 0) {
|
||||
p->x = (((int32_t)(p->x) * scale_x) >> 8) + pivot->x;
|
||||
p->y = (((int32_t)(p->y) * scale_y) >> 8) + pivot->y;
|
||||
for(i = 0; i < count; i++) {
|
||||
points[i].x = (((int32_t)(points[i].x) * scale_x) >> 8) + pivot->x;
|
||||
points[i].y = (((int32_t)(points[i].y) * scale_y) >> 8) + pivot->y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
lv_area_transform_cache_t * cache = &trans_cache;
|
||||
if(cache->angle_prev != angle) {
|
||||
int32_t angle_limited = angle;
|
||||
if(angle_limited > 3600) angle_limited -= 3600;
|
||||
if(angle_limited < 0) angle_limited += 3600;
|
||||
|
||||
int32_t angle_low = angle_limited / 10;
|
||||
int32_t angle_high = angle_low + 1;
|
||||
int32_t angle_rem = angle_limited - (angle_low * 10);
|
||||
int32_t angle_limited = angle;
|
||||
if(angle_limited > 3600) angle_limited -= 3600;
|
||||
if(angle_limited < 0) angle_limited += 3600;
|
||||
|
||||
int32_t s1 = lv_trigo_sin(angle_low);
|
||||
int32_t s2 = lv_trigo_sin(angle_high);
|
||||
int32_t angle_low = angle_limited / 10;
|
||||
int32_t angle_high = angle_low + 1;
|
||||
int32_t angle_rem = angle_limited - (angle_low * 10);
|
||||
|
||||
int32_t c1 = lv_trigo_sin(angle_low + 90);
|
||||
int32_t c2 = lv_trigo_sin(angle_high + 90);
|
||||
int32_t s1 = lv_trigo_sin(angle_low);
|
||||
int32_t s2 = lv_trigo_sin(angle_high);
|
||||
|
||||
cache->sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
|
||||
cache->cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
|
||||
cache->sinma = cache->sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
cache->cosma = cache->cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
cache->angle_prev = angle;
|
||||
}
|
||||
int32_t x = p->x;
|
||||
int32_t y = p->y;
|
||||
if(scale_x == 256 && scale_y == 256) {
|
||||
p->x = ((cache->cosma * x - cache->sinma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
p->y = ((cache->sinma * x + cache->cosma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
}
|
||||
else {
|
||||
if(zoom_first) {
|
||||
x *= scale_x;
|
||||
y *= scale_y;
|
||||
p->x = (((cache->cosma * x - cache->sinma * y)) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->x;
|
||||
p->y = (((cache->sinma * x + cache->cosma * y)) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->y;
|
||||
int32_t c1 = lv_trigo_sin(angle_low + 90);
|
||||
int32_t c2 = lv_trigo_sin(angle_high + 90);
|
||||
|
||||
int32_t sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
|
||||
sinma = sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
int32_t cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
|
||||
cosma = cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
|
||||
|
||||
for(i = 0; i < count; i++) {
|
||||
int32_t x = points[i].x;
|
||||
int32_t y = points[i].y;
|
||||
if(scale_x == 256 && scale_y == 256) {
|
||||
points[i].x = ((cosma * x - sinma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
|
||||
points[i].y = ((sinma * x + cosma * y) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
|
||||
}
|
||||
else {
|
||||
p->x = (((cache->cosma * x - cache->sinma * y) * scale_x) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->x;
|
||||
p->y = (((cache->sinma * x + cache->cosma * y) * scale_y) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->y;
|
||||
if(zoom_first) {
|
||||
x *= scale_x;
|
||||
y *= scale_y;
|
||||
points[i].x = (((cosma * x - sinma * y)) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->x;
|
||||
points[i].y = (((sinma * x + cosma * y)) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->y;
|
||||
}
|
||||
else {
|
||||
points[i].x = (((cosma * x - sinma * y) * scale_x) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->x;
|
||||
points[i].y = (((sinma * x + cosma * y) * scale_y) >> (_LV_TRANSFORM_TRIGO_SHIFT + 8)) + pivot->y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ extern "C" {
|
||||
#include "lv_types.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
@ -98,12 +99,6 @@ typedef _lv_dir_t lv_dir_t;
|
||||
typedef uint8_t lv_dir_t;
|
||||
#endif /*DOXYGEN*/
|
||||
|
||||
typedef struct {
|
||||
int32_t angle_prev;
|
||||
int32_t sinma;
|
||||
int32_t cosma;
|
||||
} lv_area_transform_cache_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
@ -262,9 +257,32 @@ bool _lv_area_is_equal(const lv_area_t * a, const lv_area_t * b);
|
||||
*/
|
||||
void lv_area_align(const lv_area_t * base, lv_area_t * to_align, lv_align_t align, int32_t ofs_x, int32_t ofs_y);
|
||||
|
||||
void lv_point_transform(lv_point_t * p, int32_t angle, int32_t scale_x, int32_t scale_y, const lv_point_t * pivot,
|
||||
/**
|
||||
* Transform a point
|
||||
* @param point pointer to a point
|
||||
* @param angle angle with 0.1 resolutions (123 means 12.3°)
|
||||
* @param scale_x horizontal zoom, 256 means 100%
|
||||
* @param scale_y vertical zoom, 256 means 100%
|
||||
* @param pivot pointer to the pivot point of the transformation
|
||||
* @param zoom_first true: zoom first and rotate after that; else: opssoite order
|
||||
*/
|
||||
void lv_point_transform(lv_point_t * point, int32_t angle, int32_t scale_x, int32_t scale_y, const lv_point_t * pivot,
|
||||
bool zoom_first);
|
||||
|
||||
/**
|
||||
* Transform an array of points
|
||||
* @param points pointer to an array of points
|
||||
* @param count number of points in the array
|
||||
* @param angle angle with 0.1 resolutions (123 means 12.3°)
|
||||
* @param scale_x horizontal zoom, 256 means 100%
|
||||
* @param scale_y vertical zoom, 256 means 100%
|
||||
* @param pivot pointer to the pivot point of the transformation
|
||||
* @param zoom_first true: zoom first and rotate after that; else: opssoite order
|
||||
*/
|
||||
void lv_point_array_transform(lv_point_t * points, size_t count, int32_t angle, int32_t scale_x, int32_t scale_y,
|
||||
const lv_point_t * pivot,
|
||||
bool zoom_first);
|
||||
|
||||
static inline lv_point_t lv_point_from_precise(const lv_point_precise_t * p)
|
||||
{
|
||||
lv_point_t point = {
|
||||
|
@ -135,7 +135,7 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e)
|
||||
else if(code == LV_EVENT_PRESSED) {
|
||||
/*Save the pressed coordinates*/
|
||||
lv_indev_get_point(lv_indev_active(), &slider->pressed_point);
|
||||
lv_obj_transform_point(obj, &slider->pressed_point, true, true);
|
||||
lv_obj_transform_point(obj, &slider->pressed_point, LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE_RECURSIVE);
|
||||
}
|
||||
else if(code == LV_EVENT_PRESSING) {
|
||||
update_knob_pos(obj, true);
|
||||
@ -336,7 +336,7 @@ static void drag_start(lv_obj_t * obj)
|
||||
}
|
||||
else if(mode == LV_SLIDER_MODE_RANGE) {
|
||||
lv_indev_get_point(lv_indev_active(), &p);
|
||||
lv_obj_transform_point(obj, &p, true, true);
|
||||
lv_obj_transform_point(obj, &p, LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE_RECURSIVE);
|
||||
const bool is_rtl = LV_BASE_DIR_RTL == lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
|
||||
const bool is_horizontal = is_slider_horizontal(obj);
|
||||
const bool is_reversed = slider->bar.val_reversed ^ (is_rtl && is_horizontal);
|
||||
@ -400,7 +400,7 @@ static void update_knob_pos(lv_obj_t * obj, bool check_drag)
|
||||
|
||||
lv_point_t p;
|
||||
lv_indev_get_point(indev, &p);
|
||||
lv_obj_transform_point(obj, &p, true, true);
|
||||
lv_obj_transform_point(obj, &p, LV_OBJ_POINT_TRANSFORM_FLAG_INVERSE_RECURSIVE);
|
||||
|
||||
bool is_hor = is_slider_horizontal(obj);
|
||||
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
BIN
tests/ref_imgs/draw/layer_transform_1.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
44
tests/src/test_cases/draw/test_layer_transform.c
Normal file
@ -0,0 +1,44 @@
|
||||
#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_no_residual_border_on_scale_down(void)
|
||||
{
|
||||
lv_obj_t * obj = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_size(obj, 100, 100);
|
||||
lv_obj_center(obj);
|
||||
lv_obj_set_style_border_color(obj, lv_color_hex3(0xf00), 0);
|
||||
lv_obj_set_style_bg_color(obj, lv_color_hex3(0x0f0), 0);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("draw/layer_transform_1.png");
|
||||
|
||||
int32_t pivot_x[] = {lv_pct(50), lv_pct(8), lv_pct(0), lv_pct(106), lv_pct(-16)};
|
||||
int32_t pivot_y[] = {lv_pct(50), lv_pct(12), lv_pct(0), lv_pct(113), lv_pct(-27)};
|
||||
int32_t scale[] = {256 * 4, 412, 569, 288, 711};
|
||||
|
||||
uint32_t i;
|
||||
for(i = 0; i < 5; i++) {
|
||||
lv_obj_set_style_transform_pivot_x(obj, pivot_x[i], 0);
|
||||
lv_obj_set_style_transform_pivot_y(obj, pivot_y[i], 0);
|
||||
lv_obj_set_style_transform_scale(obj, scale[i], 0);
|
||||
lv_refr_now(NULL);
|
||||
|
||||
/*Should be the same as the original without any artifacts*/
|
||||
lv_obj_set_style_transform_scale(obj, 256, 0);
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("draw/layer_transform_1.png");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|